Map DC shaper LUT to DM CRTC color management. Shaper LUT can be used to
delinearize and/or normalize the color space for computational
efficiency and achiving specific visual styles. Blending usually occurs
in linear space and if a CRTC degamma 1D LUT is set to linearize the
color space, a custom shaper 1D LUT can be used just before applying 3D
LUT.

Signed-off-by: Melissa Wen <m...@igalia.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  7 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 54 ++++++++++++++-----
 2 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index eebe12c353ad..ea76c2957848 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -803,6 +803,13 @@ struct dm_crtc_state {
         * has a larger set of post-blending color calibration. Here, DC MPC
         * color caps are wired up to DM CRTC state:
         */
+       /**
+        * @shaper_lut:
+        *
+        * Post-blending 1D Lookup table used to de-linearize pixel data for 3D
+        * LUT. The blob (if not NULL) is an array of &struct drm_color_lut.
+        */
+       struct drm_property_blob *shaper_lut;
        /**
         * @lut3d:
         *
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index cef8d0d7f37b..934636d7b8d3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -443,15 +443,26 @@ static void amdgpu_dm_atomic_lut3d(const struct 
drm_color_lut *drm_lut,
        }
 }
 
-static int amdgpu_dm_atomic_shaper_lut(struct dc_transfer_func *func_shaper)
+static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
+                                      uint32_t shaper_size,
+                                      struct dc_transfer_func *func_shaper)
 {
-       /* We don't get DRM shaper LUT yet. We assume the input color space is 
already
-        * delinearized, so we don't need a shaper LUT and we can just BYPASS
-        */
-       func_shaper->type = TF_TYPE_BYPASS;
-       func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
+       int ret = 0;
 
-       return 0;
+       if (shaper_size) {
+               /* If DRM shaper LUT is set, we assume a linear color space
+                * (linearized by DRM degamma 1D LUT or not)
+                */
+               func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS;
+               func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
+
+               ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, 
false);
+       } else {
+               func_shaper->type = TF_TYPE_BYPASS;
+               func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
+       }
+
+       return ret;
 }
 
 /* amdgpu_dm_atomic_shaper_lut3d - set DRM CRTC shaper LUT and 3D LUT to DC
@@ -499,7 +510,8 @@ static int amdgpu_dm_atomic_shaper_lut3d(struct dc *dc,
 
        amdgpu_dm_atomic_lut3d(drm_lut3d, drm_lut3d_size, lut3d_func);
 
-       return amdgpu_dm_atomic_shaper_lut(func_shaper);
+       return amdgpu_dm_atomic_shaper_lut(drm_shaper_lut,
+                                          drm_shaper_size, func_shaper);
 }
 
 /**
@@ -531,12 +543,22 @@ static uint32_t amdgpu_dm_get_lut3d_size(struct 
amdgpu_device *adev,
 int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev,
                                const struct drm_crtc_state *crtc_state)
 {
-       const struct drm_color_lut *lut3d = NULL;
        struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc_state);
+       const struct drm_color_lut *shaper = NULL, *lut3d = NULL;
        uint32_t exp_size, size;
 
-       exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_3DLUT_ENTRIES);
+       /* shaper LUT is only available if 3D LUT color caps*/
+       exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_LUT_ENTRIES);
+       shaper = __extract_blob_lut(acrtc_state->shaper_lut, &size);
 
+       if (shaper && size != exp_size) {
+               drm_dbg(&adev->ddev,
+                       "Invalid Shaper LUT size. Should be %u but got %u.\n",
+                       exp_size, size);
+               return -EINVAL;
+       }
+
+       exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_3DLUT_ENTRIES);
        lut3d = __extract_blob_lut(acrtc_state->lut3d, &size);
 
        if (lut3d && size != exp_size) {
@@ -618,15 +640,16 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state 
*crtc,
        uint32_t degamma_size, regamma_size;
        bool has_regamma, has_degamma;
        bool is_legacy;
+       const struct drm_color_lut *shaper_lut, *lut3d;
+       uint32_t shaper_size, lut3d_size;
        int r;
-       const struct drm_color_lut *lut3d;
-       uint32_t lut3d_size;
 
        r =  amdgpu_dm_verify_lut3d_size(adev, &crtc->base);
        if (r)
                return r;
 
        lut3d = __extract_blob_lut(crtc->lut3d, &lut3d_size);
+       shaper_lut = __extract_blob_lut(crtc->shaper_lut, &shaper_size);
 
        r = amdgpu_dm_verify_lut_sizes(&crtc->base);
        if (r)
@@ -680,11 +703,14 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state 
*crtc,
                 * there is no user-blob.
                 */
                lut3d_size = lut3d != NULL ? lut3d_size : 0;
+               shaper_size = shaper_lut != NULL ? shaper_size : 0;
                r = amdgpu_dm_atomic_shaper_lut3d(adev->dm.dc, ctx, stream,
-                                                 NULL, 0,
+                                                 shaper_lut, shaper_size,
                                                  lut3d, lut3d_size);
-               if (r)
+               if (r) {
+                       drm_dbg(&adev->ddev, "Failed on shaper/3D LUTs 
setup\n");
                        return r;
+               }
 
                /* Note: OGAM is disabled if 3D LUT is successfully programmed.
                 * See params and set_output_gamma in
-- 
2.39.2

Reply via email to