summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2019-10-24 13:46:35 -0700
committerAaron Plattner <aplattner@nvidia.com>2020-10-29 15:13:17 -0700
commit245b9db03a1e1189b992409283e3d88b5d56e62d (patch)
treea98e1f33621479380189c09263083b7f614ea0a8
parentb6985d6b3fb3e9ae36f638b0fd65cfad3d4bbd46 (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.c1
-rw-r--r--hw/xfree86/drivers/modesetting/driver.h1
-rw-r--r--hw/xfree86/drivers/modesetting/drmmode_display.c72
-rw-r--r--hw/xfree86/drivers/modesetting/drmmode_display.h3
-rw-r--r--hw/xfree86/drivers/modesetting/modesetting.man6
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@)