diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2019-10-24 13:46:35 -0700 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2020-10-29 15:13:17 -0700 |
commit | 245b9db03a1e1189b992409283e3d88b5d56e62d (patch) | |
tree | a98e1f33621479380189c09263083b7f614ea0a8 | |
parent | b6985d6b3fb3e9ae36f638b0fd65cfad3d4bbd46 (diff) |
modesetting: Use GAMMA_LUT when available
If the kernel exposes GAMMA_LUT and GAMMA_LUT_SIZE properties and the size is
not what the server has pre-configured for the crtc, free the old gamma ramp
memory allocated by the server and replace it with new allocations of the
appropriate size.
In addition, when GAMMA_LUT is available, use drmModeCreatePropertyBlob() and
drmModeObjectSetProperty() to set the gamma ramp rather than using the legacy
drmModeCrtcSetGamma() function.
Add a new option "UseGammaLUT" to allow disabling this new behavior and falling
back to drmModeCrtcSetGamma() unconditionally.
Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
-rw-r--r-- | hw/xfree86/drivers/modesetting/driver.c | 1 | ||||
-rw-r--r-- | hw/xfree86/drivers/modesetting/driver.h | 1 | ||||
-rw-r--r-- | hw/xfree86/drivers/modesetting/drmmode_display.c | 72 | ||||
-rw-r--r-- | hw/xfree86/drivers/modesetting/drmmode_display.h | 3 | ||||
-rw-r--r-- | hw/xfree86/drivers/modesetting/modesetting.man | 6 |
5 files changed, 81 insertions, 2 deletions
diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 6549ef8e1..f1e7d15bd 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -140,6 +140,7 @@ static const OptionInfoRec Options[] = { {OPTION_DOUBLE_SHADOW, "DoubleShadow", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_ATOMIC, "Atomic", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_VARIABLE_REFRESH, "VariableRefresh", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_USE_GAMMA_LUT, "UseGammaLUT", OPTV_BOOLEAN, {0}, FALSE}, {-1, NULL, OPTV_NONE, {0}, FALSE} }; diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index 2791b97c1..38b7ef1ff 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -57,6 +57,7 @@ typedef enum { OPTION_DOUBLE_SHADOW, OPTION_ATOMIC, OPTION_VARIABLE_REFRESH, + OPTION_USE_GAMMA_LUT, } modesettingOpts; typedef struct diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 1791bc87a..96c40980c 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -1670,14 +1670,47 @@ drmmode_show_cursor(xf86CrtcPtr crtc) } static void +drmmode_set_gamma_lut(drmmode_crtc_private_ptr drmmode_crtc, + uint16_t * red, uint16_t * green, uint16_t * blue, + int size) +{ + drmmode_ptr drmmode = drmmode_crtc->drmmode; + drmmode_prop_info_ptr gamma_lut_info = + &drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT]; + const uint32_t crtc_id = drmmode_crtc->mode_crtc->crtc_id; + uint32_t blob_id; + struct drm_color_lut lut[size]; + + assert(gamma_lut_info->prop_id != 0); + + for (int i = 0; i < size; i++) { + lut[i].red = red[i]; + lut[i].green = green[i]; + lut[i].blue = blue[i]; + } + + if (drmModeCreatePropertyBlob(drmmode->fd, lut, sizeof(lut), &blob_id)) + return; + + drmModeObjectSetProperty(drmmode->fd, crtc_id, DRM_MODE_OBJECT_CRTC, + gamma_lut_info->prop_id, blob_id); + + drmModeDestroyPropertyBlob(drmmode->fd, blob_id); +} + +static void drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green, uint16_t * blue, int size) { drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; - drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, - size, red, green, blue); + if (drmmode_crtc->use_gamma_lut) { + drmmode_set_gamma_lut(drmmode_crtc, red, green, blue, size); + } else { + drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + size, red, green, blue); + } } static Bool @@ -2266,6 +2299,8 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res static const drmmode_prop_info_rec crtc_props[] = { [DRMMODE_CRTC_ACTIVE] = { .name = "ACTIVE" }, [DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" }, + [DRMMODE_CRTC_GAMMA_LUT] = { .name = "GAMMA_LUT" }, + [DRMMODE_CRTC_GAMMA_LUT_SIZE] = { .name = "GAMMA_LUT_SIZE" }, }; crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); @@ -2302,6 +2337,39 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG, "Allocated crtc nr. %d to this screen.\n", num); + /* If the GAMMA_LUT property is available, replace the server's default + * gamma ramps with ones of the appropriate size. */ + if (drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].prop_id) { + Bool try_gamma_lut = + xf86ReturnOptValBool(drmmode->Options, OPTION_USE_GAMMA_LUT, TRUE); + uint64_t size = drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].value; + + if (try_gamma_lut && size != crtc->gamma_size) { + uint16_t *gamma = malloc(3 * size * sizeof(uint16_t)); + + if (gamma) { + free(crtc->gamma_red); + + crtc->gamma_size = size; + crtc->gamma_red = gamma; + crtc->gamma_green = gamma + size; + crtc->gamma_blue = gamma + size * 2; + + drmmode_crtc->use_gamma_lut = TRUE; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG, + "Gamma ramp set to %ld entries on CRTC %d\n", + size, num); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to allocate memory for %ld gamma ramp " + "entries on CRTC %d. Falling back to legacy " + "%d-entry mode.\n", + size, num, crtc->gamma_size); + } + } + } + return 1; } diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index 02107d7e3..33ba6bd38 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -67,6 +67,8 @@ enum drmmode_connector_property { enum drmmode_crtc_property { DRMMODE_CRTC_ACTIVE, DRMMODE_CRTC_MODE_ID, + DRMMODE_CRTC_GAMMA_LUT, + DRMMODE_CRTC_GAMMA_LUT_SIZE, DRMMODE_CRTC__COUNT }; @@ -199,6 +201,7 @@ typedef struct { Bool flipping_active; Bool vrr_enabled; + Bool use_gamma_lut; } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; typedef struct { diff --git a/hw/xfree86/drivers/modesetting/modesetting.man b/hw/xfree86/drivers/modesetting/modesetting.man index d530d7c4c..bc294da7c 100644 --- a/hw/xfree86/drivers/modesetting/modesetting.man +++ b/hw/xfree86/drivers/modesetting/modesetting.man @@ -81,6 +81,12 @@ For example: Option \*qZaphodHeads\*q \*qLVDS,VGA-0\*q will assign xrandr outputs LVDS and VGA-0 to this instance of the driver. .TP +.BI "Option \*qUseGammaLUT\*q \*q" boolean \*q +Enable or disable use of the GAMMA_LUT property, when available. +When enabled, this option allows the driver to use gamma ramps with more +entries, if supported by the kernel. +Default: on. +.TP .SH "SEE ALSO" @xservername@(@appmansuffix@), @xconfigfile@(@filemansuffix@), Xserver(@appmansuffix@), X(@miscmansuffix@) |