backend/drm: add support for CTM

This commit is contained in:
Simon Ser 2025-11-13 14:31:14 +01:00
parent 92ba6ffdf8
commit 2db00a9872
8 changed files with 96 additions and 12 deletions

View file

@ -154,6 +154,31 @@ static bool create_gamma_lut_blob(struct wlr_drm_backend *drm,
return true;
}
static bool create_ctm_blob(struct wlr_drm_backend *drm,
const float *matrix, uint32_t *blob_id) {
if (matrix == NULL) {
*blob_id = 0;
return true;
}
// Convert to S31.32 sign-magnitude fixed floating-point encoding
struct drm_color_ctm ctm = {0};
for (size_t i = 0; i < 9; i++) {
uint64_t v = fabs(matrix[i]) * ((uint64_t)1 << 32);
if (matrix[i] < 0) {
v |= (uint64_t)1 << 63;
}
ctm.matrix[i] = v;
}
if (drmModeCreatePropertyBlob(drm->fd, &ctm, sizeof(ctm), blob_id) != 0) {
wlr_log_errno(WLR_ERROR, "Unable to create CTM property blob");
return false;
}
return true;
}
bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
int width, int height, const pixman_region32_t *damage, uint32_t *blob_id) {
pixman_region32_t clipped;
@ -332,26 +357,39 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
}
uint32_t gamma_lut = crtc->gamma_lut;
uint32_t ctm = crtc->ctm;
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
size_t dim = 0;
size_t lut_dim = 0;
uint16_t *lut = NULL;
const float *matrix = NULL;
if (state->crtc_color_transform != NULL) {
dim = state->crtc_color_transform->lut_3x1d->dim;
lut_dim = state->crtc_color_transform->lut_3x1d->dim;
lut = state->crtc_color_transform->lut_3x1d->lut_3x1d;
if (state->crtc_color_transform->has_matrix) {
matrix = state->crtc_color_transform->matrix;
}
}
// Fallback to legacy gamma interface when gamma properties are not
// available (can happen on older Intel GPUs that support gamma but not
// degamma).
if (crtc->props.gamma_lut == 0) {
if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
if (!drm_legacy_crtc_set_gamma(drm, crtc, lut_dim, lut)) {
return false;
}
} else {
if (!create_gamma_lut_blob(drm, dim, lut, &gamma_lut)) {
if (!create_gamma_lut_blob(drm, lut_dim, lut, &gamma_lut)) {
return false;
}
}
if (matrix != NULL && crtc->props.ctm == 0) {
wlr_log(WLR_DEBUG, "CRTC %"PRIu32" doesn't support CTM", crtc->id);
return false;
}
if (!create_ctm_blob(drm, matrix, &ctm)) {
return false;
}
}
uint32_t fb_damage_clips = 0;
@ -394,6 +432,7 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
state->mode_id = mode_id;
state->gamma_lut = gamma_lut;
state->ctm = ctm;
state->fb_damage_clips = fb_damage_clips;
state->primary_in_fence_fd = in_fence_fd;
state->vrr_enabled = vrr_enabled;
@ -413,6 +452,7 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
crtc->own_mode_id = true;
commit_blob(drm, &crtc->mode_id, state->mode_id);
commit_blob(drm, &crtc->gamma_lut, state->gamma_lut);
commit_blob(drm, &crtc->ctm, state->ctm);
commit_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
conn->output.adaptive_sync_status = state->vrr_enabled ?
@ -439,6 +479,7 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state)
rollback_blob(drm, &crtc->mode_id, state->mode_id);
rollback_blob(drm, &crtc->gamma_lut, state->gamma_lut);
rollback_blob(drm, &crtc->ctm, state->ctm);
rollback_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
destroy_blob(drm, state->fb_damage_clips);
@ -543,6 +584,9 @@ static void atomic_connector_add(struct atomic *atom,
if (crtc->props.gamma_lut != 0) {
atomic_add(atom, crtc->id, crtc->props.gamma_lut, state->gamma_lut);
}
if (crtc->props.ctm != 0) {
atomic_add(atom, crtc->id, crtc->props.ctm, state->ctm);
}
if (crtc->props.vrr_enabled != 0) {
atomic_add(atom, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
}