[PATCH xf86-video-amdgpu 06/13] Compose non-legacy with legacy gamma LUT before pushing to kernel DRM
sunpeng.li at amd.com
sunpeng.li at amd.com
Thu May 3 18:31:48 UTC 2018
From: "Leo (Sunpeng) Li" <sunpeng.li at amd.com>
Frequently, a user may have non-legacy gamma enabled for monitor
correction, while using legacy gamma for things like
redshift/nightlight.
To do so, we compose the two LUTs. Legacy gamma will be applied first,
then non-legacy. i.e. non-legacy_LUT(legacy_LUT(in_color)).
Note that the staged gamma LUT within the driver-private CRTC will
always contain the non-legacy LUT. This is to ensure that we have a
cached copy for future compositions.
Signed-off-by: Leo (Sunpeng) Li <sunpeng.li at amd.com>
---
src/drmmode_display.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 105 insertions(+), 1 deletion(-)
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 7223b93..9c8c344 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -869,6 +869,95 @@ err_allocs:
}
/**
+ * If legacy LUT is a, and non-legacy LUT is b, then the result of b(a(x)) is
+ * returned in out_lut. out_lut's length is expected to be the same as the
+ * non-legacy LUT b.
+ *
+ * @a_(red|green|blue): The red, green, and blue components of the legacy LUT.
+ * @b_lut: The non-legacy LUT, in DRM's color LUT format.
+ * @out_lut: The composed LUT, in DRM's color LUT format.
+ * @len_a: Length of legacy lut.
+ * @len_b: Length of non-legacy lut.
+ */
+static void drmmode_lut_compose(uint16_t *a_red,
+ uint16_t *a_green,
+ uint16_t *a_blue,
+ struct drm_color_lut *b_lut,
+ struct drm_color_lut *out_lut,
+ uint32_t len_a, uint32_t len_b)
+{
+ uint32_t i_l, i_r, i;
+ uint32_t i_amax, i_bmax;
+ uint32_t coeff_ibmax;
+ uint32_t j;
+ uint64_t a_out_ibmax;
+ int color;
+ size_t struct_size = sizeof(struct drm_color_lut);
+
+ uint32_t max_lut = (1 << 16) - 1;
+
+ i_amax = len_a - 1;
+ i_bmax = len_b - 1;
+
+ /* A linear interpolation is done on the legacy LUT before it is
+ * composed, to bring it up-to-size with the non-legacy LUT. The
+ * interpolation uses integers by keeping things multiplied until the
+ * last moment.
+ */
+ for (color = 0; color < 3; color++) {
+ uint16_t *a, *b, *out;
+
+ /* Set the initial pointers to the right color components. The
+ * inner for-loop will then maintain the correct offset from
+ * the initial element.
+ */
+ if (color == 0) {
+ a = a_red;
+ b = &b_lut[0].red;
+ out = &out_lut[0].red;
+ } else if (color == 1) {
+ a = a_green;
+ b = &b_lut[0].green;
+ out = &out_lut[0].green;
+ } else {
+ a = a_blue;
+ b = &b_lut[0].blue;
+ out = &out_lut[0].blue;
+ }
+
+ for (i = 0; i < len_b; i++) {
+
+ /* i_l and i_r tracks the left and right elements in
+ * a_lut, to the sample point i. Also handle last
+ * element edge case, when i_l = i_amax.
+ */
+ i_l = i * i_amax / i_bmax;
+ i_r = i_l + !!(i_amax - i_l);
+
+ /* coeff is intended to be in [0, 1), depending on
+ * where sample i is between i_l and i_r. We keep it
+ * multiplied with i_bmax throughout to maintain
+ * precision */
+ coeff_ibmax = (i * i_amax) - (i_l * i_bmax);
+ a_out_ibmax = i_bmax * a[i_l] +
+ coeff_ibmax * (a[i_r] - a[i_l]);
+
+ /* j = floor((a_out/max_lut)*i_bmax).
+ * i.e. the element in LUT b that a_out maps to. We
+ * have to divide by max_lut to normalize a_out, since
+ * values in the LUTs are [0, 1<<16)
+ */
+ j = a_out_ibmax / max_lut;
+ *(uint16_t*)((void*)out + (i*struct_size)) =
+ *(uint16_t*)((void*)b + (j*struct_size));
+ }
+ }
+
+ for (i = 0; i < len_b; i++)
+ out_lut[i].reserved = 0;
+}
+
+/**
* Configure and change a color property on a CRTC, through RandR. Only the
* specified output will be affected, even if the CRTC is attached to multiple
* outputs. If the request is pending, then the change will make it's way into
@@ -1130,7 +1219,22 @@ static int drmmode_crtc_push_cm_prop(xf86CrtcPtr crtc,
/* Calculate the expected size of value in bytes */
expected_bytes = sizeof(struct drm_color_lut) *
drmmode_crtc->gamma_lut_size;
- blob_data = drmmode_crtc->degamma_lut;
+
+ /* Compose legacy and non-legacy LUT */
+ if (drmmode_crtc->gamma_lut) {
+ blob_data = malloc(expected_bytes);
+ if (!blob_data)
+ return BadAlloc;
+ drmmode_lut_compose(crtc->gamma_red,
+ crtc->gamma_green,
+ crtc->gamma_blue,
+ drmmode_crtc->gamma_lut,
+ blob_data, crtc->gamma_size,
+ drmmode_crtc->gamma_lut_size);
+ free_blob_data = TRUE;
+ } else
+ blob_data = NULL;
+
} else if (cm_prop_index == CM_DEGAMMA_LUT) {
expected_bytes = sizeof(struct drm_color_lut) *
drmmode_crtc->degamma_lut_size;
--
2.7.4
More information about the amd-gfx
mailing list