diff mbox series

[22/36] drm/amd/display: add CRTC shaper LUT support

Message ID 20230523221520.3115570-23-mwen@igalia.com (mailing list archive)
State New, archived
Headers show
Series drm/amd/display: add AMD driver-specific properties for color mgmt | expand

Commit Message

Melissa Wen May 23, 2023, 10:15 p.m. UTC
Map DC shaper LUT to DM CRTC color management. Shaper LUT can be used to
delinearize and/or normalize the color space for computational
efficiency and achiving specific visual styles. Blending usually occurs
in linear space and if a CRTC degamma 1D LUT is set to linearize the
color space, a custom shaper 1D LUT can be used just before applying 3D
LUT.

Signed-off-by: Melissa Wen <mwen@igalia.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  7 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 54 ++++++++++++++-----
 2 files changed, 47 insertions(+), 14 deletions(-)
diff mbox series

Patch

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 eebe12c353ad..ea76c2957848 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -803,6 +803,13 @@  struct dm_crtc_state {
 	 * has a larger set of post-blending color calibration. Here, DC MPC
 	 * color caps are wired up to DM CRTC state:
 	 */
+	/**
+	 * @shaper_lut:
+	 *
+	 * Post-blending 1D Lookup table used to de-linearize pixel data for 3D
+	 * LUT. The blob (if not NULL) is an array of &struct drm_color_lut.
+	 */
+	struct drm_property_blob *shaper_lut;
 	/**
 	 * @lut3d:
 	 *
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 cef8d0d7f37b..934636d7b8d3 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
@@ -443,15 +443,26 @@  static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut,
 	}
 }
 
-static int amdgpu_dm_atomic_shaper_lut(struct dc_transfer_func *func_shaper)
+static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
+				       uint32_t shaper_size,
+				       struct dc_transfer_func *func_shaper)
 {
-	/* We don't get DRM shaper LUT yet. We assume the input color space is already
-	 * delinearized, so we don't need a shaper LUT and we can just BYPASS
-	 */
-	func_shaper->type = TF_TYPE_BYPASS;
-	func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
+	int ret = 0;
 
-	return 0;
+	if (shaper_size) {
+		/* If DRM shaper LUT is set, we assume a linear color space
+		 * (linearized by DRM degamma 1D LUT or not)
+		 */
+		func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS;
+		func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
+
+		ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, false);
+	} else {
+		func_shaper->type = TF_TYPE_BYPASS;
+		func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
+	}
+
+	return ret;
 }
 
 /* amdgpu_dm_atomic_shaper_lut3d - set DRM CRTC shaper LUT and 3D LUT to DC
@@ -499,7 +510,8 @@  static int amdgpu_dm_atomic_shaper_lut3d(struct dc *dc,
 
 	amdgpu_dm_atomic_lut3d(drm_lut3d, drm_lut3d_size, lut3d_func);
 
-	return amdgpu_dm_atomic_shaper_lut(func_shaper);
+	return amdgpu_dm_atomic_shaper_lut(drm_shaper_lut,
+					   drm_shaper_size, func_shaper);
 }
 
 /**
@@ -531,12 +543,22 @@  static uint32_t amdgpu_dm_get_lut3d_size(struct amdgpu_device *adev,
 int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev,
 				const struct drm_crtc_state *crtc_state)
 {
-	const struct drm_color_lut *lut3d = NULL;
 	struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc_state);
+	const struct drm_color_lut *shaper = NULL, *lut3d = NULL;
 	uint32_t exp_size, size;
 
-	exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_3DLUT_ENTRIES);
+	/* shaper LUT is only available if 3D LUT color caps*/
+	exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_LUT_ENTRIES);
+	shaper = __extract_blob_lut(acrtc_state->shaper_lut, &size);
 
+	if (shaper && size != exp_size) {
+		drm_dbg(&adev->ddev,
+			"Invalid Shaper LUT size. Should be %u but got %u.\n",
+			exp_size, size);
+		return -EINVAL;
+	}
+
+	exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_3DLUT_ENTRIES);
 	lut3d = __extract_blob_lut(acrtc_state->lut3d, &size);
 
 	if (lut3d && size != exp_size) {
@@ -618,15 +640,16 @@  int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc,
 	uint32_t degamma_size, regamma_size;
 	bool has_regamma, has_degamma;
 	bool is_legacy;
+	const struct drm_color_lut *shaper_lut, *lut3d;
+	uint32_t shaper_size, lut3d_size;
 	int r;
-	const struct drm_color_lut *lut3d;
-	uint32_t lut3d_size;
 
 	r =  amdgpu_dm_verify_lut3d_size(adev, &crtc->base);
 	if (r)
 		return r;
 
 	lut3d = __extract_blob_lut(crtc->lut3d, &lut3d_size);
+	shaper_lut = __extract_blob_lut(crtc->shaper_lut, &shaper_size);
 
 	r = amdgpu_dm_verify_lut_sizes(&crtc->base);
 	if (r)
@@ -680,11 +703,14 @@  int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc,
 		 * there is no user-blob.
 		 */
 		lut3d_size = lut3d != NULL ? lut3d_size : 0;
+		shaper_size = shaper_lut != NULL ? shaper_size : 0;
 		r = amdgpu_dm_atomic_shaper_lut3d(adev->dm.dc, ctx, stream,
-						  NULL, 0,
+						  shaper_lut, shaper_size,
 						  lut3d, lut3d_size);
-		if (r)
+		if (r) {
+			drm_dbg(&adev->ddev, "Failed on shaper/3D LUTs setup\n");
 			return r;
+		}
 
 		/* Note: OGAM is disabled if 3D LUT is successfully programmed.
 		 * See params and set_output_gamma in