On 2023-10-05 13:15, Melissa Wen wrote: > From: Joshua Ashton <joshua@xxxxxxxxx> > > Blend 1D LUT or a pre-defined transfer function (TF) can be set to > linearize content before blending, so that it's positioned just before > blending planes in the AMD color mgmt pipeline, and after 3D LUT > (non-linear space). Shaper and Blend LUTs are 1D LUTs that sandwich 3D > LUT. Drivers should advertize blend properties according to HW caps. > > There is no blend ROM for pre-defined TF. When setting blend 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. > > v3: > - spell out TF+LUT behavior in the commit and comments (Harry) > > Signed-off-by: Joshua Ashton <joshua@xxxxxxxxx> > Signed-off-by: Melissa Wen <mwen@xxxxxxxxxx> Reviewed-by: Harry Wentland <harry.wentland@xxxxxxx> Harry > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 22 ++++++++++++ > .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 12 +++++++ > .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 21 +++++++++++ > .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 36 +++++++++++++++++++ > 4 files changed, 91 insertions(+) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h > index af70db4f6b4b..dee35d208493 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h > @@ -402,6 +402,28 @@ struct amdgpu_mode_info { > * entries for 3D LUT array is the 3D LUT size cubed; > */ > struct drm_property *plane_lut3d_size_property; > + /** > + * @plane_blend_lut_property: Plane property for output gamma before > + * blending. Userspace set a blend LUT to convert colors after 3D LUT > + * conversion. It works as a post-3DLUT 1D LUT. With shaper LUT, they > + * are sandwiching 3D LUT with two 1D LUT. If plane_blend_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_blend_lut_property; > + /** > + * @plane_blend_lut_size_property: Plane property to define the max > + * size of blend LUT as supported by the driver (read-only). > + */ > + struct drm_property *plane_blend_lut_size_property; > + /** > + * @plane_blend_tf_property: Plane property to set a predefined > + * transfer function for pre-blending blend/out_gamma (after applying > + * 3D LUT) with or without LUT. There is no blend 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_blend_tf_property; > }; > > #define AMDGPU_MAX_BL_LEVEL 0xFF > 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 0e2a04a3caf3..1b96c742d747 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h > @@ -800,6 +800,18 @@ struct dm_plane_state { > * &struct drm_color_lut. > */ > struct drm_property_blob *lut3d; > + /** > + * @blend_lut: blend lut lookup table blob. The blob (if not NULL) is an > + * array of &struct drm_color_lut. > + */ > + struct drm_property_blob *blend_lut; > + /** > + * @blend_tf: > + * > + * Pre-defined transfer function for converting plane pixel data before > + * applying blend LUT. > + */ > + enum amdgpu_transfer_function blend_tf; > }; > > struct dm_crtc_state { > 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 d3c7f9a13a61..82c554662faa 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 > @@ -273,6 +273,27 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev) > return -ENOMEM; > adev->mode_info.plane_lut3d_size_property = prop; > > + prop = drm_property_create(adev_to_drm(adev), > + DRM_MODE_PROP_BLOB, > + "AMD_PLANE_BLEND_LUT", 0); > + if (!prop) > + return -ENOMEM; > + adev->mode_info.plane_blend_lut_property = prop; > + > + prop = drm_property_create_range(adev_to_drm(adev), > + DRM_MODE_PROP_IMMUTABLE, > + "AMD_PLANE_BLEND_LUT_SIZE", 0, UINT_MAX); > + if (!prop) > + return -ENOMEM; > + adev->mode_info.plane_blend_lut_size_property = prop; > + > + prop = amdgpu_create_tf_property(adev_to_drm(adev), > + "AMD_PLANE_BLEND_TF", > + amdgpu_eotf); > + if (!prop) > + return -ENOMEM; > + adev->mode_info.plane_blend_tf_property = prop; > + > return 0; > } > #endif > 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 a381b3558bd1..f1070ca7076a 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 > @@ -1339,6 +1339,7 @@ static void dm_drm_plane_reset(struct drm_plane *plane) > amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; > amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT; > amdgpu_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; > + amdgpu_state->blend_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; > } > > static struct drm_plane_state * > @@ -1364,10 +1365,13 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) > drm_property_blob_get(dm_plane_state->shaper_lut); > if (dm_plane_state->lut3d) > drm_property_blob_get(dm_plane_state->lut3d); > + if (dm_plane_state->blend_lut) > + drm_property_blob_get(dm_plane_state->blend_lut); > > 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; > + dm_plane_state->blend_tf = old_dm_plane_state->blend_tf; > > return &dm_plane_state->base; > } > @@ -1442,6 +1446,8 @@ static void dm_drm_plane_destroy_state(struct drm_plane *plane, > 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->blend_lut) > + drm_property_blob_put(dm_plane_state->blend_lut); > > if (dm_plane_state->dc_state) > dc_plane_state_release(dm_plane_state->dc_state); > @@ -1488,6 +1494,17 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, > mode_info.plane_lut3d_size_property, > MAX_COLOR_3DLUT_SIZE); > } > + > + if (dpp_color_caps.ogam_ram) { > + drm_object_attach_property(&plane->base, > + mode_info.plane_blend_lut_property, 0); > + drm_object_attach_property(&plane->base, > + mode_info.plane_blend_lut_size_property, > + MAX_COLOR_LUT_ENTRIES); > + drm_object_attach_property(&plane->base, > + mode_info.plane_blend_tf_property, > + AMDGPU_TRANSFER_FUNCTION_DEFAULT); > + } > } > > static int > @@ -1540,6 +1557,19 @@ dm_atomic_plane_set_property(struct drm_plane *plane, > &replaced); > dm_plane_state->base.color_mgmt_changed |= replaced; > return ret; > + } else if (property == adev->mode_info.plane_blend_lut_property) { > + ret = drm_property_replace_blob_from_id(plane->dev, > + &dm_plane_state->blend_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_blend_tf_property) { > + if (dm_plane_state->blend_tf != val) { > + dm_plane_state->blend_tf = val; > + dm_plane_state->base.color_mgmt_changed = 1; > + } > } else { > drm_dbg_atomic(plane->dev, > "[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n", > @@ -1575,6 +1605,12 @@ dm_atomic_plane_get_property(struct drm_plane *plane, > } else if (property == adev->mode_info.plane_lut3d_property) { > *val = (dm_plane_state->lut3d) ? > dm_plane_state->lut3d->base.id : 0; > + } else if (property == adev->mode_info.plane_blend_lut_property) { > + *val = (dm_plane_state->blend_lut) ? > + dm_plane_state->blend_lut->base.id : 0; > + } else if (property == adev->mode_info.plane_blend_tf_property) { > + *val = dm_plane_state->blend_tf; > + > } else { > return -EINVAL; > }