[PATCH v4 10/32] drm/amd/display: add plane shaper LUT and TF driver-specific properties

Harry Wentland harry.wentland at amd.com
Wed Nov 15 18:27:11 UTC 2023



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 <mwen at igalia.com>

Reviewed-by: Harry Wentland <harry.wentland at 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;



More information about the amd-gfx mailing list