]> Git Repo - linux.git/commitdiff
drm/amd/display: add plane shaper LUT and TF driver-specific properties
authorMelissa Wen <[email protected]>
Thu, 16 Nov 2023 19:57:50 +0000 (18:57 -0100)
committerAlex Deucher <[email protected]>
Wed, 13 Dec 2023 21:08:00 +0000 (16:08 -0500)
On AMD HW, 3D LUT always assumes a preceding shaper 1D LUT used for
delinearizing and/or normalizing the color space before applying a 3D
LUT. Add pre-defined transfer function to enable delinearizing content
with or without shaper LUT, where AMD color module calculates the
resulted shaper curve. We apply an inverse EOTF to go from linear
values to encoded values. If we are already in a non-linear space and/or
don't need to normalize values, we can bypass shaper LUT with a linear
transfer function that is also the default TF value.

There is no shaper ROM. When setting shaper TF (!= Identity) and LUT at
the same time, the color module will combine the pre-defined TF and the
custom LUT values into the LUT that's actually programmed.

v2:
- squash commits for shaper LUT and shaper TF
- define inverse EOTF as supported shaper TFs

v3:
- spell out TF+LUT behavior in the commit and comments (Harry)
- replace BT709 EOTF by inv OETF

v5:
- get shaper blob correctly (Joshua)

Reviewed-by: Harry Wentland <[email protected]>
Signed-off-by: Melissa Wen <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c

index 7350094f3db6afb30e76f58fe88042f13354435a..981a2eb252570032d12b91db86efe32dbebe21a1 100644 (file)
@@ -364,6 +364,27 @@ struct amdgpu_mode_info {
         * @plane_hdr_mult_property:
         */
        struct drm_property *plane_hdr_mult_property;
+       /**
+        * @shaper_lut_property: Plane property to set pre-blending shaper LUT
+        * that converts color content before 3D LUT. If
+        * plane_shaper_tf_property != Identity TF, AMD color module will
+        * combine the user LUT values with pre-defined TF into the LUT
+        * parameters to be programmed.
+        */
+       struct drm_property *plane_shaper_lut_property;
+       /**
+        * @shaper_lut_size_property: Plane property for the size of
+        * pre-blending shaper LUT as supported by the driver (read-only).
+        */
+       struct drm_property *plane_shaper_lut_size_property;
+       /**
+        * @plane_shaper_tf_property: Plane property to set a predefined
+        * transfer function for pre-blending shaper (before applying 3D LUT)
+        * with or without LUT. There is no shaper ROM, but we can use AMD
+        * color modules to program LUT parameters from predefined TF (or
+        * from a combination of pre-defined TF and the custom 1D LUT).
+        */
+       struct drm_property *plane_shaper_tf_property;
        /**
         * @plane_lut3d_property: Plane property for color transformation using
         * a 3D LUT (pre-blending), a three-dimensional array where each
index 0f78024ac0e53a6f7b224fa46ba727fe3e2806fc..9bee60cbc2b5958be0324ffbf09982ff0a5a1176 100644 (file)
@@ -784,6 +784,17 @@ struct dm_plane_state {
         * TF is needed for any subsequent linear-to-non-linear transforms.
         */
        __u64 hdr_mult;
+       /**
+        * @shaper_lut: shaper lookup table blob. The blob (if not NULL) is an
+        * array of &struct drm_color_lut.
+        */
+       struct drm_property_blob *shaper_lut;
+       /**
+        * @shaper_tf:
+        *
+        * Predefined transfer function to delinearize color space.
+        */
+       enum amdgpu_transfer_function shaper_tf;
        /**
         * @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of
         * &struct drm_color_lut.
index a3b4f6a4c4a8fe3c7fbc5520dedd54eb8d202e2a..866c6f1d3d99608601b787e43f2293b98ceeceaa 100644 (file)
@@ -173,6 +173,14 @@ static const u32 amdgpu_eotf =
        BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF) |
        BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF);
 
+static const u32 amdgpu_inv_eotf =
+       BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF) |
+       BIT(AMDGPU_TRANSFER_FUNCTION_BT709_OETF) |
+       BIT(AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF) |
+       BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF) |
+       BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF) |
+       BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF);
+
 static struct drm_property *
 amdgpu_create_tf_property(struct drm_device *dev,
                          const char *name,
@@ -231,6 +239,27 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev)
                return -ENOMEM;
        adev->mode_info.plane_hdr_mult_property = prop;
 
+       prop = drm_property_create(adev_to_drm(adev),
+                                  DRM_MODE_PROP_BLOB,
+                                  "AMD_PLANE_SHAPER_LUT", 0);
+       if (!prop)
+               return -ENOMEM;
+       adev->mode_info.plane_shaper_lut_property = prop;
+
+       prop = drm_property_create_range(adev_to_drm(adev),
+                                        DRM_MODE_PROP_IMMUTABLE,
+                                        "AMD_PLANE_SHAPER_LUT_SIZE", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       adev->mode_info.plane_shaper_lut_size_property = prop;
+
+       prop = amdgpu_create_tf_property(adev_to_drm(adev),
+                                        "AMD_PLANE_SHAPER_TF",
+                                        amdgpu_inv_eotf);
+       if (!prop)
+               return -ENOMEM;
+       adev->mode_info.plane_shaper_tf_property = prop;
+
        prop = drm_property_create(adev_to_drm(adev),
                                   DRM_MODE_PROP_BLOB,
                                   "AMD_PLANE_LUT3D", 0);
index e588cff7d6b0a2588567ab1da9b6ecf0233b5c65..7f0de29889f0590f1f34d43dbba5f0070a9588a7 100644 (file)
@@ -1343,6 +1343,7 @@ static void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane)
        __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base);
        amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
        amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT;
+       amdgpu_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
 }
 
 static struct drm_plane_state *amdgpu_dm_plane_drm_plane_duplicate_state(struct drm_plane *plane)
@@ -1364,12 +1365,16 @@ static struct drm_plane_state *amdgpu_dm_plane_drm_plane_duplicate_state(struct
        if (old_dm_plane_state->degamma_lut)
                dm_plane_state->degamma_lut =
                        drm_property_blob_get(old_dm_plane_state->degamma_lut);
+       if (old_dm_plane_state->shaper_lut)
+               dm_plane_state->shaper_lut =
+                       drm_property_blob_get(old_dm_plane_state->shaper_lut);
        if (old_dm_plane_state->lut3d)
                dm_plane_state->lut3d =
                        drm_property_blob_get(old_dm_plane_state->lut3d);
 
        dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf;
        dm_plane_state->hdr_mult = old_dm_plane_state->hdr_mult;
+       dm_plane_state->shaper_tf = old_dm_plane_state->shaper_tf;
 
        return &dm_plane_state->base;
 }
@@ -1442,6 +1447,8 @@ static void amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *plane,
                drm_property_blob_put(dm_plane_state->degamma_lut);
        if (dm_plane_state->lut3d)
                drm_property_blob_put(dm_plane_state->lut3d);
+       if (dm_plane_state->shaper_lut)
+               drm_property_blob_put(dm_plane_state->shaper_lut);
 
        if (dm_plane_state->dc_state)
                dc_plane_state_release(dm_plane_state->dc_state);
@@ -1477,6 +1484,14 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm,
                                   AMDGPU_HDR_MULT_DEFAULT);
 
        if (dpp_color_caps.hw_3d_lut) {
+               drm_object_attach_property(&plane->base,
+                                          mode_info.plane_shaper_lut_property, 0);
+               drm_object_attach_property(&plane->base,
+                                          mode_info.plane_shaper_lut_size_property,
+                                          MAX_COLOR_LUT_ENTRIES);
+               drm_object_attach_property(&plane->base,
+                                          mode_info.plane_shaper_tf_property,
+                                          AMDGPU_TRANSFER_FUNCTION_DEFAULT);
                drm_object_attach_property(&plane->base,
                                           mode_info.plane_lut3d_property, 0);
                drm_object_attach_property(&plane->base,
@@ -1514,6 +1529,19 @@ dm_atomic_plane_set_property(struct drm_plane *plane,
                        dm_plane_state->hdr_mult = val;
                        dm_plane_state->base.color_mgmt_changed = 1;
                }
+       } else if (property == adev->mode_info.plane_shaper_lut_property) {
+               ret = drm_property_replace_blob_from_id(plane->dev,
+                                                       &dm_plane_state->shaper_lut,
+                                                       val, -1,
+                                                       sizeof(struct drm_color_lut),
+                                                       &replaced);
+               dm_plane_state->base.color_mgmt_changed |= replaced;
+               return ret;
+       } else if (property == adev->mode_info.plane_shaper_tf_property) {
+               if (dm_plane_state->shaper_tf != val) {
+                       dm_plane_state->shaper_tf = val;
+                       dm_plane_state->base.color_mgmt_changed = 1;
+               }
        } else if (property == adev->mode_info.plane_lut3d_property) {
                ret = drm_property_replace_blob_from_id(plane->dev,
                                                        &dm_plane_state->lut3d,
@@ -1549,6 +1577,11 @@ dm_atomic_plane_get_property(struct drm_plane *plane,
                *val = dm_plane_state->degamma_tf;
        } else if (property == adev->mode_info.plane_hdr_mult_property) {
                *val = dm_plane_state->hdr_mult;
+       } else  if (property == adev->mode_info.plane_shaper_lut_property) {
+               *val = (dm_plane_state->shaper_lut) ?
+                       dm_plane_state->shaper_lut->base.id : 0;
+       } else if (property == adev->mode_info.plane_shaper_tf_property) {
+               *val = dm_plane_state->shaper_tf;
        } else  if (property == adev->mode_info.plane_lut3d_property) {
                *val = (dm_plane_state->lut3d) ?
                        dm_plane_state->lut3d->base.id : 0;
This page took 0.069034 seconds and 4 git commands to generate.