[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