[v2,10/34] drm/amd/display: add plane 3D LUT driver-specific properties
Commit Message
Add 3D LUT property for plane gamma correction using a 3D lookup table.
Since a 3D LUT has a limited number of entries in each dimension we want
to use them in an optimal fashion. This means using the 3D LUT in a
colorspace that is optimized for human vision, such as sRGB, PQ, or
another non-linear space. Therefore, userpace may need one 1D LUT
(shaper) before it to delinearize content and another 1D LUT after 3D
LUT (blend) to linearize content again for blending. The next patches
add these 1D LUTs to the plane color mgmt pipeline.
Signed-off-by: Melissa Wen <mwen@igalia.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 10 ++++++++
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 9 ++++++++
.../amd/display/amdgpu_dm/amdgpu_dm_color.c | 14 +++++++++++
.../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 23 +++++++++++++++++++
4 files changed, 56 insertions(+)
Comments
On 09/07, Pekka Paalanen wrote:
> On Wed, 6 Sep 2023 15:30:04 -0400
> Harry Wentland <harry.wentland@amd.com> wrote:
>
> > On 2023-08-10 12:02, Melissa Wen wrote:
> > > Add 3D LUT property for plane gamma correction using a 3D lookup table.
> > > Since a 3D LUT has a limited number of entries in each dimension we want
> > > to use them in an optimal fashion. This means using the 3D LUT in a
> > > colorspace that is optimized for human vision, such as sRGB, PQ, or
> > > another non-linear space. Therefore, userpace may need one 1D LUT
> > > (shaper) before it to delinearize content and another 1D LUT after 3D
> > > LUT (blend) to linearize content again for blending. The next patches
> > > add these 1D LUTs to the plane color mgmt pipeline.
> > >
> > > Signed-off-by: Melissa Wen <mwen@igalia.com>
> > > ---
> > > drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 10 ++++++++
> > > .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 9 ++++++++
> > > .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 14 +++++++++++
> > > .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 23 +++++++++++++++++++
> > > 4 files changed, 56 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > > index 66bae0eed80c..730a88236501 100644
> > > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> > > @@ -363,6 +363,16 @@ struct amdgpu_mode_info {
> > > * @plane_hdr_mult_property:
> > > */
> > > struct drm_property *plane_hdr_mult_property;
> > > + /**
> > > + * @plane_lut3d_property: Plane property for gamma correction using a
> > > + * 3D LUT (pre-blending).
> > > + */
> >
> > I think we'll want to describe how the 3DLUT entries are laid out.
> > Something that describes how userspace should fill it, like
> > gamescope does for example:
> > https://github.com/ValveSoftware/gamescope/blob/7108880ed80b68c21750369e2ac9b7315fecf264/src/color_helpers.cpp#L302
> >
> > Something like: a three-dimensional array, with each dimension
> > having a size of the cubed root of lut3d_size, blue being the
> > outermost dimension, red the innermost.
> >
>
> Here is an example of how we defined a 3D LUT layout in Weston:
>
> https://gitlab.freedesktop.org/wayland/weston/-/blob/68e2a606c056c8453c770263f41f34cd68bdc9d0/libweston/color.h#L114-152
>
> I think that is the most clear definition it can be, without needing to
> understand specific terminology.
Thanks for sharing it, Pekka! I'll check Weston's definition for 3D LUT
and also other elements for improving docs.
Melissa
>
>
> Thanks,
> pq
>
> >
> > > + struct drm_property *plane_lut3d_property;
> > > + /**
> > > + * @plane_degamma_lut_size_property: Plane property to define the max
> > > + * size of 3D LUT as supported by the driver (read-only).
> > > + */
> >
> > We should probably document that the size of the 3DLUT should
> > be the size of one dimension cubed, or that the cubed root of
> > the LUT size gives the size per dimension.
> >
> > Harry
@@ -363,6 +363,16 @@ struct amdgpu_mode_info {
* @plane_hdr_mult_property:
*/
struct drm_property *plane_hdr_mult_property;
+ /**
+ * @plane_lut3d_property: Plane property for gamma correction using a
+ * 3D LUT (pre-blending).
+ */
+ struct drm_property *plane_lut3d_property;
+ /**
+ * @plane_degamma_lut_size_property: Plane property to define the max
+ * size of 3D LUT as supported by the driver (read-only).
+ */
+ struct drm_property *plane_lut3d_size_property;
};
#define AMDGPU_MAX_BL_LEVEL 0xFF
@@ -769,6 +769,11 @@ struct dm_plane_state {
* S31.32 sign-magnitude.
*/
__u64 hdr_mult;
+ /**
+ * @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of
+ * &struct drm_color_lut.
+ */
+ struct drm_property_blob *lut3d;
};
struct dm_crtc_state {
@@ -854,6 +859,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
void amdgpu_dm_trigger_timing_sync(struct drm_device *dev);
+/* 3D LUT max size is 17x17x17 */
+#define MAX_COLOR_3DLUT_ENTRIES 4913
+#define MAX_COLOR_3DLUT_BITDEPTH 12
+/* 1D LUT size */
#define MAX_COLOR_LUT_ENTRIES 4096
/* Legacy gamm LUT users such as X doesn't like large LUT sizes */
#define MAX_COLOR_LEGACY_LUT_ENTRIES 256
@@ -209,6 +209,20 @@ 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_LUT3D", 0);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_lut3d_property = prop;
+
+ prop = drm_property_create_range(adev_to_drm(adev),
+ DRM_MODE_PROP_IMMUTABLE,
+ "AMD_PLANE_LUT3D_SIZE", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_lut3d_size_property = prop;
+
return 0;
}
#endif
@@ -1353,6 +1353,8 @@ 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->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;
@@ -1426,6 +1428,8 @@ static void dm_drm_plane_destroy_state(struct drm_plane *plane,
if (dm_plane_state->degamma_lut)
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->dc_state)
dc_plane_state_release(dm_plane_state->dc_state);
@@ -1456,6 +1460,14 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm,
drm_object_attach_property(&plane->base,
dm->adev->mode_info.plane_hdr_mult_property,
AMDGPU_HDR_MULT_DEFAULT);
+
+ if (dpp_color_caps.hw_3d_lut) {
+ drm_object_attach_property(&plane->base,
+ mode_info.plane_lut3d_property, 0);
+ drm_object_attach_property(&plane->base,
+ mode_info.plane_lut3d_size_property,
+ MAX_COLOR_3DLUT_ENTRIES);
+ }
}
static int
@@ -1487,6 +1499,14 @@ 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_lut3d_property) {
+ ret = drm_property_replace_blob_from_id(plane->dev,
+ &dm_plane_state->lut3d,
+ val, -1,
+ sizeof(struct drm_color_lut),
+ &replaced);
+ dm_plane_state->base.color_mgmt_changed |= replaced;
+ return ret;
} else {
drm_dbg_atomic(plane->dev,
"[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n",
@@ -1514,6 +1534,9 @@ 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_lut3d_property) {
+ *val = (dm_plane_state->lut3d) ?
+ dm_plane_state->lut3d->base.id : 0;
} else {
return -EINVAL;
}