Skip to content

Commit 486c95a

Browse files
melissawenalexdeucher
authored andcommitted
drm/amd/display: add plane 3D LUT support
Wire up DC 3D LUT to DM plane color management (pre-blending). On AMD display HW, 3D LUT comes after a shaper curve and we always have to program a shaper curve to delinearize or normalize the color space before applying a 3D LUT (since we have a reduced number of LUT entries). In this version, the default values of 3D LUT for size and bit_depth are 17x17x17 and 12-bit, but we already provide here a more generic mechanisms to program other supported values (9x9x9 size and 10-bit). v2: - started with plane 3D LUT instead of CRTC 3D LUT support v4: - lut3d_size is the max dimension size instead of # of entries Reviewed-by: Harry Wentland <[email protected]> Signed-off-by: Melissa Wen <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
1 parent 65d2765 commit 486c95a

File tree

2 files changed

+99
-4
lines changed

2 files changed

+99
-4
lines changed

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8270,6 +8270,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
82708270
bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix;
82718271
bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult;
82728272
bundle->surface_updates[planes_count].func_shaper = dc_plane->in_shaper_func;
8273+
bundle->surface_updates[planes_count].lut3d_func = dc_plane->lut3d_func;
82738274
}
82748275

82758276
amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,86 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
623623
}
624624
}
625625

626+
static void __to_dc_lut3d_color(struct dc_rgb *rgb,
627+
const struct drm_color_lut lut,
628+
int bit_precision)
629+
{
630+
rgb->red = drm_color_lut_extract(lut.red, bit_precision);
631+
rgb->green = drm_color_lut_extract(lut.green, bit_precision);
632+
rgb->blue = drm_color_lut_extract(lut.blue, bit_precision);
633+
}
634+
635+
static void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
636+
uint32_t lut3d_size,
637+
struct tetrahedral_params *params,
638+
bool use_tetrahedral_9,
639+
int bit_depth)
640+
{
641+
struct dc_rgb *lut0;
642+
struct dc_rgb *lut1;
643+
struct dc_rgb *lut2;
644+
struct dc_rgb *lut3;
645+
int lut_i, i;
646+
647+
648+
if (use_tetrahedral_9) {
649+
lut0 = params->tetrahedral_9.lut0;
650+
lut1 = params->tetrahedral_9.lut1;
651+
lut2 = params->tetrahedral_9.lut2;
652+
lut3 = params->tetrahedral_9.lut3;
653+
} else {
654+
lut0 = params->tetrahedral_17.lut0;
655+
lut1 = params->tetrahedral_17.lut1;
656+
lut2 = params->tetrahedral_17.lut2;
657+
lut3 = params->tetrahedral_17.lut3;
658+
}
659+
660+
for (lut_i = 0, i = 0; i < lut3d_size - 4; lut_i++, i += 4) {
661+
/*
662+
* We should consider the 3D LUT RGB values are distributed
663+
* along four arrays lut0-3 where the first sizes 1229 and the
664+
* other 1228. The bit depth supported for 3dlut channel is
665+
* 12-bit, but DC also supports 10-bit.
666+
*
667+
* TODO: improve color pipeline API to enable the userspace set
668+
* bit depth and 3D LUT size/stride, as specified by VA-API.
669+
*/
670+
__to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth);
671+
__to_dc_lut3d_color(&lut1[lut_i], lut[i + 1], bit_depth);
672+
__to_dc_lut3d_color(&lut2[lut_i], lut[i + 2], bit_depth);
673+
__to_dc_lut3d_color(&lut3[lut_i], lut[i + 3], bit_depth);
674+
}
675+
/* lut0 has 1229 points (lut_size/4 + 1) */
676+
__to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth);
677+
}
678+
679+
/* amdgpu_dm_atomic_lut3d - set DRM 3D LUT to DC stream
680+
* @drm_lut3d: user 3D LUT
681+
* @drm_lut3d_size: size of 3D LUT
682+
* @lut3d: DC 3D LUT
683+
*
684+
* Map user 3D LUT data to DC 3D LUT and all necessary bits to program it
685+
* on DCN accordingly.
686+
*/
687+
static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut3d,
688+
uint32_t drm_lut3d_size,
689+
struct dc_3dlut *lut)
690+
{
691+
if (!drm_lut3d_size) {
692+
lut->state.bits.initialized = 0;
693+
} else {
694+
/* Stride and bit depth are not programmable by API yet.
695+
* Therefore, only supports 17x17x17 3D LUT (12-bit).
696+
*/
697+
lut->lut_3d.use_tetrahedral_9 = false;
698+
lut->lut_3d.use_12bits = true;
699+
lut->state.bits.initialized = 1;
700+
__drm_3dlut_to_dc_3dlut(drm_lut3d, drm_lut3d_size, &lut->lut_3d,
701+
lut->lut_3d.use_tetrahedral_9,
702+
MAX_COLOR_3DLUT_BITDEPTH);
703+
}
704+
}
705+
626706
static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
627707
bool has_rom,
628708
enum dc_transfer_func_predefined tf,
@@ -665,8 +745,8 @@ int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev,
665745
struct drm_plane_state *plane_state)
666746
{
667747
struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
668-
const struct drm_color_lut *shaper = NULL;
669-
uint32_t exp_size, size;
748+
const struct drm_color_lut *shaper = NULL, *lut3d = NULL;
749+
uint32_t exp_size, size, dim_size = MAX_COLOR_3DLUT_SIZE;
670750
bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut;
671751

672752
/* shaper LUT is only available if 3D LUT color caps */
@@ -680,6 +760,17 @@ int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev,
680760
return -EINVAL;
681761
}
682762

763+
/* The number of 3D LUT entries is the dimension size cubed */
764+
exp_size = has_3dlut ? dim_size * dim_size * dim_size : 0;
765+
lut3d = __extract_blob_lut(dm_plane_state->lut3d, &size);
766+
767+
if (lut3d && size != exp_size) {
768+
drm_dbg(&adev->ddev,
769+
"Invalid 3D LUT size. Should be %u but got %u.\n",
770+
exp_size, size);
771+
return -EINVAL;
772+
}
773+
683774
return 0;
684775
}
685776

@@ -976,16 +1067,19 @@ amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state,
9761067
{
9771068
struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
9781069
enum amdgpu_transfer_function shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
979-
const struct drm_color_lut *shaper_lut;
980-
uint32_t shaper_size;
1070+
const struct drm_color_lut *shaper_lut, *lut3d;
1071+
uint32_t shaper_size, lut3d_size;
9811072
int ret;
9821073

9831074
dc_plane_state->hdr_mult = dc_fixpt_from_s3132(dm_plane_state->hdr_mult);
9841075

9851076
shaper_lut = __extract_blob_lut(dm_plane_state->shaper_lut, &shaper_size);
9861077
shaper_size = shaper_lut != NULL ? shaper_size : 0;
9871078
shaper_tf = dm_plane_state->shaper_tf;
1079+
lut3d = __extract_blob_lut(dm_plane_state->lut3d, &lut3d_size);
1080+
lut3d_size = lut3d != NULL ? lut3d_size : 0;
9881081

1082+
amdgpu_dm_atomic_lut3d(lut3d, lut3d_size, dc_plane_state->lut3d_func);
9891083
ret = amdgpu_dm_atomic_shaper_lut(shaper_lut, false,
9901084
amdgpu_tf_to_dc_tf(shaper_tf),
9911085
shaper_size,

0 commit comments

Comments
 (0)