drm/amd/display: Use 4096 lut entries
authorLeo (Sunpeng) Li <sunpeng.li@amd.com>
Mon, 12 Feb 2018 18:20:56 +0000 (13:20 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 5 Mar 2018 20:33:09 +0000 (15:33 -0500)
Points in the DRM LUT are spaced linearly. Points in hardware are spaced
exponentially, with greater density towards 0. To maintain low-end
accuracy in hardware when sampling the DRM LUT, more points are needed.

However, X doesn't seem to play with legacy LUTs of such size.
Therefore, check for legacy lut when updating DC states, and update
accordingly.

v2: Use a macro for the maximum drm LUT value.

v3: Update commit to reflect that this does not map 1-1 to HW

Signed-off-by: Leo (Sunpeng) Li <sunpeng.li@amd.com>
Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c

index 3af6f0b..fa7b2fa 100644 (file)
@@ -3197,7 +3197,7 @@ static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
        dm->adev->mode_info.crtcs[crtc_index] = acrtc;
        drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES,
                                   true, MAX_COLOR_LUT_ENTRIES);
-       drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LUT_ENTRIES);
+       drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES);
 
        return 0;
 
index aa7df57..b68400c 100644 (file)
@@ -268,7 +268,9 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc);
 #define amdgpu_dm_crtc_handle_crc_irq(x)
 #endif
 
-#define MAX_COLOR_LUT_ENTRIES 256
+#define MAX_COLOR_LUT_ENTRIES 4096
+/* Legacy gamm LUT users such as X doesn't like large LUT sizes */
+#define MAX_COLOR_LEGACY_LUT_ENTRIES 256
 
 void amdgpu_dm_init_color_mod(void);
 int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state,
index 62bb72f..e845c51 100644 (file)
@@ -27,6 +27,8 @@
 #include "amdgpu_dm.h"
 #include "modules/color/color_gamma.h"
 
+#define MAX_DRM_LUT_VALUE 0xFFFF
+
 /*
  * Initialize the color module.
  *
@@ -47,19 +49,18 @@ void amdgpu_dm_init_color_mod(void)
  * f(a) = (0xFF00/MAX_COLOR_LUT_ENTRIES-1)a; for integer a in
  *                                           [0, MAX_COLOR_LUT_ENTRIES)
  */
-static bool __is_lut_linear(struct drm_color_lut *lut)
+static bool __is_lut_linear(struct drm_color_lut *lut, uint32_t size)
 {
        int i;
-       uint32_t max_os = 0xFF00;
        uint32_t expected;
        int delta;
 
-       for (i = 0; i < MAX_COLOR_LUT_ENTRIES; i++) {
+       for (i = 0; i < size; i++) {
                /* All color values should equal */
                if ((lut[i].red != lut[i].green) || (lut[i].green != lut[i].blue))
                        return false;
 
-               expected = i * max_os / (MAX_COLOR_LUT_ENTRIES-1);
+               expected = i * MAX_DRM_LUT_VALUE / (size-1);
 
                /* Allow a +/-1 error. */
                delta = lut[i].red - expected;
@@ -70,6 +71,42 @@ static bool __is_lut_linear(struct drm_color_lut *lut)
 }
 
 /**
+ * Convert the drm_color_lut to dc_gamma. The conversion depends on the size
+ * of the lut - whether or not it's legacy.
+ */
+static void __drm_lut_to_dc_gamma(struct drm_color_lut *lut,
+                                 struct dc_gamma *gamma,
+                                 bool is_legacy)
+{
+       uint32_t r, g, b;
+       int i;
+
+       if (is_legacy) {
+               for (i = 0; i < MAX_COLOR_LEGACY_LUT_ENTRIES; i++) {
+                       r = drm_color_lut_extract(lut[i].red, 16);
+                       g = drm_color_lut_extract(lut[i].green, 16);
+                       b = drm_color_lut_extract(lut[i].blue, 16);
+
+                       gamma->entries.red[i] = dal_fixed31_32_from_int(r);
+                       gamma->entries.green[i] = dal_fixed31_32_from_int(g);
+                       gamma->entries.blue[i] = dal_fixed31_32_from_int(b);
+               }
+               return;
+       }
+
+       /* else */
+       for (i = 0; i < MAX_COLOR_LUT_ENTRIES; i++) {
+               r = drm_color_lut_extract(lut[i].red, 16);
+               g = drm_color_lut_extract(lut[i].green, 16);
+               b = drm_color_lut_extract(lut[i].blue, 16);
+
+               gamma->entries.red[i] = dal_fixed31_32_from_fraction(r, MAX_DRM_LUT_VALUE);
+               gamma->entries.green[i] = dal_fixed31_32_from_fraction(g, MAX_DRM_LUT_VALUE);
+               gamma->entries.blue[i] = dal_fixed31_32_from_fraction(b, MAX_DRM_LUT_VALUE);
+       }
+}
+
+/**
  * amdgpu_dm_set_regamma_lut: Set regamma lut for the given CRTC.
  * @crtc: amdgpu_dm crtc state
  *
@@ -85,11 +122,10 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc)
        struct drm_property_blob *blob = crtc->base.gamma_lut;
        struct dc_stream_state *stream = crtc->stream;
        struct drm_color_lut *lut;
+       uint32_t lut_size;
        struct dc_gamma *gamma;
        enum dc_transfer_func_type old_type = stream->out_transfer_func->type;
 
-       uint32_t r, g, b;
-       int i;
        bool ret;
 
        if (!blob) {
@@ -100,8 +136,9 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc)
        }
 
        lut = (struct drm_color_lut *)blob->data;
+       lut_size = blob->length / sizeof(struct drm_color_lut);
 
-       if (__is_lut_linear(lut)) {
+       if (__is_lut_linear(lut, lut_size)) {
                /* Set to bypass if lut is set to linear */
                stream->out_transfer_func->type = TF_TYPE_BYPASS;
                stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
@@ -112,20 +149,20 @@ int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc)
        if (!gamma)
                return -ENOMEM;
 
-       gamma->num_entries = MAX_COLOR_LUT_ENTRIES;
-       gamma->type = GAMMA_RGB_256;
-
-       /* Truncate, and store in dc_gamma for output tf calculation */
-       for (i = 0; i < gamma->num_entries; i++) {
-               r = drm_color_lut_extract(lut[i].red, 16);
-               g = drm_color_lut_extract(lut[i].green, 16);
-               b = drm_color_lut_extract(lut[i].blue, 16);
-
-               gamma->entries.red[i] = dal_fixed31_32_from_int(r);
-               gamma->entries.green[i] = dal_fixed31_32_from_int(g);
-               gamma->entries.blue[i] = dal_fixed31_32_from_int(b);
+       gamma->num_entries = lut_size;
+       if (gamma->num_entries == MAX_COLOR_LEGACY_LUT_ENTRIES)
+               gamma->type = GAMMA_RGB_256;
+       else if (gamma->num_entries == MAX_COLOR_LUT_ENTRIES)
+               gamma->type = GAMMA_CS_TFM_1D;
+       else {
+               /* Invalid lut size */
+               dc_gamma_release(&gamma);
+               return -EINVAL;
        }
 
+       /* Convert drm_lut into dc_gamma */
+       __drm_lut_to_dc_gamma(lut, gamma, gamma->type == GAMMA_RGB_256);
+
        /* Call color module to translate into something DC understands. Namely
         * a transfer function.
         */
@@ -212,7 +249,7 @@ int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state,
        }
 
        lut = (struct drm_color_lut *)blob->data;
-       if (__is_lut_linear(lut)) {
+       if (__is_lut_linear(lut, MAX_COLOR_LUT_ENTRIES)) {
                dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
                dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
                return 0;