diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2019-10-25 00:06:40 -0700 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2020-10-29 15:25:00 -0700 |
commit | 4e670f1281ad75c5673b6ac75645036d810da8d9 (patch) | |
tree | 83d098b0b2a2413dcaf4f1de91f1249f09dde0f4 | |
parent | 245b9db03a1e1189b992409283e3d88b5d56e62d (diff) |
modesetting: Add CTM RandR property
When the "CTM" (color transform matrix) modesetting property is available,
create a corresponding RandR property.
To match the format of the property available in the amdgpu driver, expose it as
an array of 18 32-bit XA_INTEGERs representing a 3x3 matrix in row-major order,
where each entry is a S31.32 sign-magnitude fixed-point number with the
fractional part listed first.
Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
Acked-by: Michel Dänzer <mdaenzer@redhat.com>
Reviewed-by: James Jones <jajones@nvidia.com>
-rw-r--r-- | hw/xfree86/drivers/modesetting/drmmode_display.c | 124 | ||||
-rw-r--r-- | hw/xfree86/drivers/modesetting/drmmode_display.h | 4 |
2 files changed, 128 insertions, 0 deletions
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 96c40980c..e81168e26 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -60,6 +60,32 @@ static PixmapPtr drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int int depth, int bitsPerPixel, int devKind, void *pPixData); +static const struct drm_color_ctm ctm_identity = { { + 1UL << 32, 0, 0, + 0, 1UL << 32, 0, + 0, 0, 1UL << 32 +} }; + +static Bool ctm_is_identity(const struct drm_color_ctm *ctm) +{ + const size_t matrix_len = sizeof(ctm->matrix) / sizeof(ctm->matrix[0]); + const uint64_t one = 1ULL << 32; + const uint64_t neg_zero = 1ULL << 63; + int i; + + for (i = 0; i < matrix_len; i++) { + const Bool diagonal = i / 3 == i % 3; + const uint64_t val = ctm->matrix[i]; + + if ((diagonal && val != one) || + (!diagonal && val != 0 && val != neg_zero)) { + return FALSE; + } + } + + return TRUE; +} + static inline uint32_t * formats_ptr(struct drm_format_modifier_blob *blob) { @@ -750,6 +776,39 @@ drmmode_crtc_disable(xf86CrtcPtr crtc) return ret; } +static void +drmmode_set_ctm(xf86CrtcPtr crtc, const struct drm_color_ctm *ctm) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + drmmode_prop_info_ptr ctm_info = + &drmmode_crtc->props[DRMMODE_CRTC_CTM]; + int ret; + uint32_t blob_id = 0; + + if (ctm_info->prop_id == 0) + return; + + if (ctm && drmmode_crtc->use_gamma_lut && !ctm_is_identity(ctm)) { + ret = drmModeCreatePropertyBlob(drmmode->fd, ctm, sizeof(*ctm), &blob_id); + if (ret != 0) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "Failed to create CTM property blob: %d\n", ret); + blob_id = 0; + } + } + + ret = drmModeObjectSetProperty(drmmode->fd, + drmmode_crtc->mode_crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, ctm_info->prop_id, + blob_id); + if (ret != 0) + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "Failed to set CTM property: %d\n", ret); + + drmModeDestroyPropertyBlob(drmmode->fd, blob_id); +} + static int drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only) { @@ -763,6 +822,7 @@ drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only) uint32_t fb_id; int x, y; int i, ret = 0; + const struct drm_color_ctm *ctm = NULL; if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y)) return 1; @@ -853,12 +913,16 @@ drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only) continue; output_ids[output_count] = drmmode_output->output_id; output_count++; + + ctm = &drmmode_output->ctm; } drmmode_ConvertToKMode(crtc->scrn, &kmode, &crtc->mode); ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, fb_id, x, y, output_ids, output_count, &kmode); + drmmode_set_ctm(crtc, ctm); + free(output_ids); return ret; } @@ -2301,6 +2365,7 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res [DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" }, [DRMMODE_CRTC_GAMMA_LUT] = { .name = "GAMMA_LUT" }, [DRMMODE_CRTC_GAMMA_LUT_SIZE] = { .name = "GAMMA_LUT_SIZE" }, + [DRMMODE_CRTC_CTM] = { .name = "CTM" }, }; crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); @@ -2370,6 +2435,11 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res } } + if (drmmode_crtc->use_gamma_lut && + drmmode_crtc->props[DRMMODE_CRTC_CTM].prop_id) { + drmmode->use_ctm = TRUE; + } + return 1; } @@ -2432,6 +2502,20 @@ drmmode_output_update_properties(xf86OutputPtr output) } } } + + /* Update the CTM property */ + if (drmmode_output->ctm_atom) { + err = RRChangeOutputProperty(output->randr_output, + drmmode_output->ctm_atom, + XA_INTEGER, 32, PropModeReplace, 18, + &drmmode_output->ctm, + FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + } static xf86OutputStatus @@ -2784,6 +2868,31 @@ drmmode_output_create_resources(xf86OutputPtr output) } } + if (drmmode->use_ctm) { + Atom name = MakeAtom("CTM", 3, TRUE); + + if (name != BAD_RESOURCE) { + drmmode_output->ctm_atom = name; + + err = RRConfigureOutputProperty(output->randr_output, name, + FALSE, FALSE, TRUE, 0, NULL); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + + err = RRChangeOutputProperty(output->randr_output, name, + XA_INTEGER, 32, PropModeReplace, 18, + &ctm_identity, FALSE, FALSE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + + drmmode_output->ctm = ctm_identity; + } + } + for (i = 0; i < drmmode_output->num_props; i++) { drmmode_prop_ptr p = &drmmode_output->props[i]; @@ -2906,6 +3015,21 @@ drmmode_output_set_property(xf86OutputPtr output, Atom property, } } + if (property == drmmode_output->ctm_atom) { + const size_t matrix_size = sizeof(drmmode_output->ctm); + + if (value->type != XA_INTEGER || value->format != 32 || + value->size * 4 != matrix_size) + return FALSE; + + memcpy(&drmmode_output->ctm, value->data, matrix_size); + + // Update the CRTC if there is one bound to this output. + if (output->crtc) { + drmmode_set_ctm(output->crtc, &drmmode_output->ctm); + } + } + return TRUE; } diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index 33ba6bd38..c3d3f712d 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -69,6 +69,7 @@ enum drmmode_crtc_property { DRMMODE_CRTC_MODE_ID, DRMMODE_CRTC_GAMMA_LUT, DRMMODE_CRTC_GAMMA_LUT_SIZE, + DRMMODE_CRTC_CTM, DRMMODE_CRTC__COUNT }; @@ -132,6 +133,7 @@ typedef struct { Bool present_enable; uint32_t vrr_prop_id; + Bool use_ctm; } drmmode_rec, *drmmode_ptr; typedef struct { @@ -226,6 +228,8 @@ typedef struct { int enc_mask; int enc_clone_mask; xf86CrtcPtr current_crtc; + Atom ctm_atom; + struct drm_color_ctm ctm; } drmmode_output_private_rec, *drmmode_output_private_ptr; typedef struct { |