On 2023-10-05 13:15, Melissa Wen wrote:
> 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
> 
> Signed-off-by: Melissa Wen <m...@igalia.com>

Reviewed-by: Harry Wentland <harry.wentl...@amd.com>

Harry

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h      | 21 ++++++++++++
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 11 +++++++
>  .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 29 +++++++++++++++++
>  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 32 +++++++++++++++++++
>  4 files changed, 93 insertions(+)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> index f7adaa52c23f..af70db4f6b4b 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> @@ -363,6 +363,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
> 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 7a2350c62cf1..0e2a04a3caf3 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -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.
> 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 011f2f9ec890..d3c7f9a13a61 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
> @@ -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,
> @@ -230,6 +238,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);
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c 
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
> index 068798ffdd56..a381b3558bd1 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
> @@ -1338,6 +1338,7 @@ static void dm_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 *
> @@ -1359,11 +1360,14 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane)
>  
>       if (dm_plane_state->degamma_lut)
>               drm_property_blob_get(dm_plane_state->degamma_lut);
> +     if (dm_plane_state->shaper_lut)
> +             drm_property_blob_get(dm_plane_state->shaper_lut);
>       if (dm_plane_state->lut3d)
>               drm_property_blob_get(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;
>  }
> @@ -1436,6 +1440,8 @@ static void dm_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);
> @@ -1468,6 +1474,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,
> @@ -1505,6 +1519,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,
> @@ -1540,6 +1567,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;

Reply via email to