* [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT
@ 2025-12-08 23:44 Melissa Wen
2025-12-08 23:44 ` [RFC PATCH 1/2] drm/amd/display: fix wrong color value mapping on DCN32 " Melissa Wen
` (3 more replies)
0 siblings, 4 replies; 16+ messages in thread
From: Melissa Wen @ 2025-12-08 23:44 UTC (permalink / raw)
To: airlied, alexander.deucher, christian.koenig, harry.wentland,
simona, siqueira, sunpeng.li
Cc: kernel-dev, Melissa Wen, amd-gfx, dri-devel
There are some unexpected banding and shimmer effects when using
steamOS/gamescope color pipeline for HDR on DCN32 or newer families.
Those problems are not present in Steam Deck (DCN301). It happens on
DCN32 because plane shaper LUT uses DCN30 CM3 helper to translate curves
instead of DCN10 CM helper. This series identifies the necessary changes
on CM3 helper to reduce differences on color transformation made by
those two helpers.
Patch 1 aims to solve the shimmer/colorful points that looks like a
wrong map of black values on red/green/blue colors. Patch 2 extends the
delta clamping fix made in commit 27fc10d1095f ("drm/amd/display: Fix
the delta clamping for shaper LUT") to solve some banding effects.
Banding is not fully solved by any helper and needs further
investigation.
One easy way to check the current and expected behavior is moving the
cursor (doing composition) to get the expected result from GFX. When the
cursor disappears, those color transformations are back to be done by
the display hw.
Lemme know your thoughts!
Melissa
Melissa Wen (2):
drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
drm/amd/display: extend delta clamping logic to CM3 LUT helper
.../amd/display/dc/dcn30/dcn30_cm_common.c | 32 +++++++++++++++----
.../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
.../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
.../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++----
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 ++++++----
5 files changed, 50 insertions(+), 26 deletions(-)
--
2.51.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [RFC PATCH 1/2] drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
2025-12-08 23:44 [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT Melissa Wen
@ 2025-12-08 23:44 ` Melissa Wen
2026-01-16 20:29 ` Harry Wentland
2025-12-08 23:44 ` [RFC PATCH 2/2] drm/amd/display: extend delta clamping logic to CM3 LUT helper Melissa Wen
` (2 subsequent siblings)
3 siblings, 1 reply; 16+ messages in thread
From: Melissa Wen @ 2025-12-08 23:44 UTC (permalink / raw)
To: airlied, alexander.deucher, christian.koenig, harry.wentland,
simona, siqueira, sunpeng.li
Cc: kernel-dev, Melissa Wen, amd-gfx, dri-devel
We've seen some shimmer points on DCN32 when using the steamOS color
pipeline for HDR on gaming. Looks like black values being wrongly mapped
to red/blue/green values. Fiz that by using the exact number of
hw_points computed in the LUT segmentation. Probably the whole logic
that adds +1 to the latest points should be revisited.
Signed-off-by: Melissa Wen <mwen@igalia.com>
---
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
index 0690c346f2c5..ba20575be214 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
@@ -225,7 +225,7 @@ bool cm3_helper_translate_curve_to_hw_format(
// DCN3+ have 257 pts in lieu of no separate slope registers
// Prior HW had 256 base+slope pairs
- lut_params->hw_points_num = hw_points + 1;
+ lut_params->hw_points_num = hw_points;
k = 0;
for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
--
2.51.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC PATCH 2/2] drm/amd/display: extend delta clamping logic to CM3 LUT helper
2025-12-08 23:44 [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT Melissa Wen
2025-12-08 23:44 ` [RFC PATCH 1/2] drm/amd/display: fix wrong color value mapping on DCN32 " Melissa Wen
@ 2025-12-08 23:44 ` Melissa Wen
2026-01-16 20:27 ` Harry Wentland
2025-12-09 1:34 ` [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT Matthew Schwartz
2026-01-16 17:08 ` Melissa Wen
3 siblings, 1 reply; 16+ messages in thread
From: Melissa Wen @ 2025-12-08 23:44 UTC (permalink / raw)
To: airlied, alexander.deucher, christian.koenig, harry.wentland,
simona, siqueira, sunpeng.li
Cc: kernel-dev, Melissa Wen, amd-gfx, dri-devel
Commit 27fc10d1095f ("drm/amd/display: Fix the delta clamping for shaper
LUT") fixed banding when using plane shaper LUT in DCN10 CM helper. The
problem is also present in DCN30 CM helper, fix banding by extending the
same bug delta clamping fix to CM3.
Signed-off-by: Melissa Wen <mwen@igalia.com>
---
.../amd/display/dc/dcn30/dcn30_cm_common.c | 30 +++++++++++++++----
.../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
.../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
.../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++-----
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 +++++-----
5 files changed, 49 insertions(+), 25 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
index ba20575be214..b1c2c8da1937 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
@@ -105,9 +105,12 @@ void cm_helper_program_gamcor_xfer_func(
#define NUMBER_REGIONS 32
#define NUMBER_SW_SEGMENTS 16
-bool cm3_helper_translate_curve_to_hw_format(
- const struct dc_transfer_func *output_tf,
- struct pwl_params *lut_params, bool fixpoint)
+#define DC_LOGGER \
+ ctx->logger
+
+bool cm3_helper_translate_curve_to_hw_format(struct dc_context *ctx,
+ const struct dc_transfer_func *output_tf,
+ struct pwl_params *lut_params, bool fixpoint)
{
struct curve_points3 *corner_points;
struct pwl_result_data *rgb_resulted;
@@ -248,6 +251,10 @@ bool cm3_helper_translate_curve_to_hw_format(
if (fixpoint == true) {
i = 1;
while (i != hw_points + 2) {
+ uint32_t red_clamp;
+ uint32_t green_clamp;
+ uint32_t blue_clamp;
+
if (i >= hw_points) {
if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
rgb_plus_1->red = dc_fixpt_add(rgb->red,
@@ -260,9 +267,20 @@ bool cm3_helper_translate_curve_to_hw_format(
rgb_minus_1->delta_blue);
}
- rgb->delta_red_reg = dc_fixpt_clamp_u0d10(rgb->delta_red);
- rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green);
- rgb->delta_blue_reg = dc_fixpt_clamp_u0d10(rgb->delta_blue);
+ rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red);
+ rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
+ rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue);
+
+ red_clamp = dc_fixpt_clamp_u0d14(rgb->delta_red);
+ green_clamp = dc_fixpt_clamp_u0d14(rgb->delta_green);
+ blue_clamp = dc_fixpt_clamp_u0d14(rgb->delta_blue);
+
+ if (red_clamp >> 10 || green_clamp >> 10 || blue_clamp >> 10)
+ DC_LOG_ERROR("Losing delta precision while programming shaper LUT.");
+
+ rgb->delta_red_reg = red_clamp & 0x3ff;
+ rgb->delta_green_reg = green_clamp & 0x3ff;
+ rgb->delta_blue_reg = blue_clamp & 0x3ff;
rgb->red_reg = dc_fixpt_clamp_u0d14(rgb->red);
rgb->green_reg = dc_fixpt_clamp_u0d14(rgb->green);
rgb->blue_reg = dc_fixpt_clamp_u0d14(rgb->blue);
diff --git a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h
index b86347c9b038..95f9318a54ef 100644
--- a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h
+++ b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h
@@ -59,7 +59,7 @@ void cm_helper_program_gamcor_xfer_func(
const struct pwl_params *params,
const struct dcn3_xfer_func_reg *reg);
-bool cm3_helper_translate_curve_to_hw_format(
+bool cm3_helper_translate_curve_to_hw_format(struct dc_context *ctx,
const struct dc_transfer_func *output_tf,
struct pwl_params *lut_params, bool fixpoint);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index 81bcadf5e57e..f2d4cd527874 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -239,7 +239,7 @@ bool dcn30_set_blend_lut(
if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
blend_lut = &plane_state->blend_tf.pwl;
else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
- result = cm3_helper_translate_curve_to_hw_format(
+ result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
&plane_state->blend_tf, &dpp_base->regamma_params, false);
if (!result)
return result;
@@ -334,8 +334,9 @@ bool dcn30_set_input_transfer_func(struct dc *dc,
if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL)
params = &plane_state->in_transfer_func.pwl;
else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS &&
- cm3_helper_translate_curve_to_hw_format(&plane_state->in_transfer_func,
- &dpp_base->degamma_params, false))
+ cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
+ &plane_state->in_transfer_func,
+ &dpp_base->degamma_params, false))
params = &dpp_base->degamma_params;
result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
@@ -406,7 +407,7 @@ bool dcn30_set_output_transfer_func(struct dc *dc,
params = &stream->out_transfer_func.pwl;
else if (pipe_ctx->stream->out_transfer_func.type ==
TF_TYPE_DISTRIBUTED_POINTS &&
- cm3_helper_translate_curve_to_hw_format(
+ cm3_helper_translate_curve_to_hw_format(stream->ctx,
&stream->out_transfer_func,
&mpc->blender_params, false))
params = &mpc->blender_params;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
index b213a2ac827a..27abc08918bc 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
@@ -486,8 +486,9 @@ bool dcn32_set_mcm_luts(
if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
lut_params = &plane_state->blend_tf.pwl;
else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
- result = cm3_helper_translate_curve_to_hw_format(&plane_state->blend_tf,
- &dpp_base->regamma_params, false);
+ result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
+ &plane_state->blend_tf,
+ &dpp_base->regamma_params, false);
if (!result)
return result;
@@ -502,8 +503,9 @@ bool dcn32_set_mcm_luts(
else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
// TODO: dpp_base replace
ASSERT(false);
- cm3_helper_translate_curve_to_hw_format(&plane_state->in_shaper_func,
- &dpp_base->shaper_params, true);
+ cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
+ &plane_state->in_shaper_func,
+ &dpp_base->shaper_params, true);
lut_params = &dpp_base->shaper_params;
}
@@ -543,8 +545,9 @@ bool dcn32_set_input_transfer_func(struct dc *dc,
if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL)
params = &plane_state->in_transfer_func.pwl;
else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS &&
- cm3_helper_translate_curve_to_hw_format(&plane_state->in_transfer_func,
- &dpp_base->degamma_params, false))
+ cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
+ &plane_state->in_transfer_func,
+ &dpp_base->degamma_params, false))
params = &dpp_base->degamma_params;
dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
@@ -575,7 +578,7 @@ bool dcn32_set_output_transfer_func(struct dc *dc,
params = &stream->out_transfer_func.pwl;
else if (pipe_ctx->stream->out_transfer_func.type ==
TF_TYPE_DISTRIBUTED_POINTS &&
- cm3_helper_translate_curve_to_hw_format(
+ cm3_helper_translate_curve_to_hw_format(stream->ctx,
&stream->out_transfer_func,
&mpc->blender_params, false))
params = &mpc->blender_params;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index 2fbc22afb89c..5eda7648d0d2 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -430,7 +430,7 @@ void dcn401_populate_mcm_luts(struct dc *dc,
if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL)
m_lut_params.pwl = &mcm_luts.lut1d_func->pwl;
else if (mcm_luts.lut1d_func->type == TF_TYPE_DISTRIBUTED_POINTS) {
- rval = cm3_helper_translate_curve_to_hw_format(
+ rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx,
mcm_luts.lut1d_func,
&dpp_base->regamma_params, false);
m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
@@ -450,7 +450,7 @@ void dcn401_populate_mcm_luts(struct dc *dc,
m_lut_params.pwl = &mcm_luts.shaper->pwl;
else if (mcm_luts.shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
ASSERT(false);
- rval = cm3_helper_translate_curve_to_hw_format(
+ rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx,
mcm_luts.shaper,
&dpp_base->regamma_params, true);
m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
@@ -627,8 +627,9 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
lut_params = &plane_state->blend_tf.pwl;
else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
- rval = cm3_helper_translate_curve_to_hw_format(&plane_state->blend_tf,
- &dpp_base->regamma_params, false);
+ rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
+ &plane_state->blend_tf,
+ &dpp_base->regamma_params, false);
lut_params = rval ? &dpp_base->regamma_params : NULL;
}
result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id);
@@ -639,8 +640,9 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
lut_params = &plane_state->in_shaper_func.pwl;
else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
// TODO: dpp_base replace
- rval = cm3_helper_translate_curve_to_hw_format(&plane_state->in_shaper_func,
- &dpp_base->shaper_params, true);
+ rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
+ &plane_state->in_shaper_func,
+ &dpp_base->shaper_params, true);
lut_params = rval ? &dpp_base->shaper_params : NULL;
}
result &= mpc->funcs->program_shaper(mpc, lut_params, mpcc_id);
@@ -674,7 +676,7 @@ bool dcn401_set_output_transfer_func(struct dc *dc,
params = &stream->out_transfer_func.pwl;
else if (pipe_ctx->stream->out_transfer_func.type ==
TF_TYPE_DISTRIBUTED_POINTS &&
- cm3_helper_translate_curve_to_hw_format(
+ cm3_helper_translate_curve_to_hw_format(stream->ctx,
&stream->out_transfer_func,
&mpc->blender_params, false))
params = &mpc->blender_params;
--
2.51.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT
2025-12-08 23:44 [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT Melissa Wen
2025-12-08 23:44 ` [RFC PATCH 1/2] drm/amd/display: fix wrong color value mapping on DCN32 " Melissa Wen
2025-12-08 23:44 ` [RFC PATCH 2/2] drm/amd/display: extend delta clamping logic to CM3 LUT helper Melissa Wen
@ 2025-12-09 1:34 ` Matthew Schwartz
2025-12-09 14:31 ` Melissa Wen
2026-01-16 17:08 ` Melissa Wen
3 siblings, 1 reply; 16+ messages in thread
From: Matthew Schwartz @ 2025-12-09 1:34 UTC (permalink / raw)
To: Melissa Wen
Cc: airlied, alexander.deucher, christian.koenig, harry.wentland,
simona, siqueira, sunpeng.li, kernel-dev, amd-gfx, dri-devel,
Melissa Wen
> On Dec 8, 2025, at 3:48 PM, Melissa Wen <mwen@igalia.com> wrote:
>
> There are some unexpected banding and shimmer effects when using
> steamOS/gamescope color pipeline for HDR on DCN32 or newer families.
> Those problems are not present in Steam Deck (DCN301). It happens on
> DCN32 because plane shaper LUT uses DCN30 CM3 helper to translate curves
> instead of DCN10 CM helper. This series identifies the necessary changes
> on CM3 helper to reduce differences on color transformation made by
> those two helpers.
>
> Patch 1 aims to solve the shimmer/colorful points that looks like a
> wrong map of black values on red/green/blue colors. Patch 2 extends the
> delta clamping fix made in commit 27fc10d1095f ("drm/amd/display: Fix
> the delta clamping for shaper LUT") to solve some banding effects.
>
> Banding is not fully solved by any helper and needs further
> investigation.
>
> One easy way to check the current and expected behavior is moving the
> cursor (doing composition) to get the expected result from GFX. When the
> cursor disappears, those color transformations are back to be done by
> the display hw.
Hi Melissa,
Could you share how you’re testing the gamescope color pipeline with HDR on DCN32, i.e display and connection type? Are any extra gamescope or kernel patches required?
At least on my own DCN32 setup (AMD 7900XTX) + my primary monitor (an LG 45gx950a-b) via DisplayPort or my DCN35 setup + integrated HDR OLED screen (Legion Go 2), gamescope always composites when HDR is enabled. I applied your patches on top of kernel 6.18, and my kernel is built with CONFIG_DRM_AMD_COLOR_STEAMDECK=y (the downstream name of AMD_PRIVATE_COLOR for SteamOS), so that shouldn't be an issue. I tried everything from 1280x720p -> 5120x2160p, and it does not work on any resolution.
Thanks,
Matt
>
> Lemme know your thoughts!
>
> Melissa
>
> Melissa Wen (2):
> drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
> drm/amd/display: extend delta clamping logic to CM3 LUT helper
>
> .../amd/display/dc/dcn30/dcn30_cm_common.c | 32 +++++++++++++++----
> .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
> .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
> .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++----
> .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 ++++++----
> 5 files changed, 50 insertions(+), 26 deletions(-)
>
> --
> 2.51.0
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT
2025-12-09 1:34 ` [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT Matthew Schwartz
@ 2025-12-09 14:31 ` Melissa Wen
2025-12-09 14:44 ` Melissa Wen
0 siblings, 1 reply; 16+ messages in thread
From: Melissa Wen @ 2025-12-09 14:31 UTC (permalink / raw)
To: Matthew Schwartz
Cc: airlied, alexander.deucher, christian.koenig, harry.wentland,
simona, siqueira, sunpeng.li, kernel-dev, amd-gfx, dri-devel
On 08/12/2025 22:34, Matthew Schwartz wrote:
>
>> On Dec 8, 2025, at 3:48 PM, Melissa Wen <mwen@igalia.com> wrote:
>>
>> There are some unexpected banding and shimmer effects when using
>> steamOS/gamescope color pipeline for HDR on DCN32 or newer families.
>> Those problems are not present in Steam Deck (DCN301). It happens on
>> DCN32 because plane shaper LUT uses DCN30 CM3 helper to translate curves
>> instead of DCN10 CM helper. This series identifies the necessary changes
>> on CM3 helper to reduce differences on color transformation made by
>> those two helpers.
>>
>> Patch 1 aims to solve the shimmer/colorful points that looks like a
>> wrong map of black values on red/green/blue colors. Patch 2 extends the
>> delta clamping fix made in commit 27fc10d1095f ("drm/amd/display: Fix
>> the delta clamping for shaper LUT") to solve some banding effects.
>>
>> Banding is not fully solved by any helper and needs further
>> investigation.
>>
>> One easy way to check the current and expected behavior is moving the
>> cursor (doing composition) to get the expected result from GFX. When the
>> cursor disappears, those color transformations are back to be done by
>> the display hw.
> Hi Melissa,
>
> Could you share how you’re testing the gamescope color pipeline with HDR on DCN32, i.e display and connection type? Are any extra gamescope or kernel patches required?
>
> At least on my own DCN32 setup (AMD 7900XTX) + my primary monitor (an LG 45gx950a-b) via DisplayPort or my DCN35 setup + integrated HDR OLED screen (Legion Go 2), gamescope always composites when HDR is enabled. I applied your patches on top of kernel 6.18, and my kernel is built with CONFIG_DRM_AMD_COLOR_STEAMDECK=y (the downstream name of AMD_PRIVATE_COLOR for SteamOS), so that shouldn't be an issue. I tried everything from 1280x720p -> 5120x2160p, and it does not work on any resolution.
Hi Matt,
You need to hack the DPP color caps to enabled SHAPER/3D and BLEND LUTs
as below:
diff --git
i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
index b276fec3e479..96b4f3239fb1 100644
--- i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+++ w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
@@ -2256,8 +2256,8 @@ static bool dcn32_resource_construct(
dc->caps.color.dpp.gamma_corr = 1;
dc->caps.color.dpp.dgam_rom_for_yuv = 0;
- dc->caps.color.dpp.hw_3d_lut = 0;
- dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN1
+ dc->caps.color.dpp.hw_3d_lut = 1;
+ dc->caps.color.dpp.ogam_ram = 1; // no OGAM in DPP since DCN1
// no OGAM ROM on DCN2 and later ASICs
dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
In short, you need to change `caps.color.dpp.hw_3d_lut` and
`caps.color.dpp.ogam_ram` to 1 in the dcnX_resource.c file to say there
is a "plane" color caps.
The thing is that, in DCN32+, these color caps are not part of DPP
anymore, they are MPC capabilities in MCM that can be moved before or
after blending.
But the current kernel implementation checks DPP color caps to expose
plane color proprerties.
Checking MPC and where the MCM is positioned would be more complex, but
not impossible. Something to improve in the future yes.
You need to confirm that your `drm_info` shows all AMD plane color
properties, but gamescope basically checks CTM and BLEND_TF as you can
see here:
https://github.com/ValveSoftware/gamescope/blob/master/src/Backends/DRMBackend.cpp#L3347
Let me know if it works for you.
BR,
Melissa
>
> Thanks,
> Matt
>
>> Lemme know your thoughts!
>>
>> Melissa
>>
>> Melissa Wen (2):
>> drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
>> drm/amd/display: extend delta clamping logic to CM3 LUT helper
>>
>> .../amd/display/dc/dcn30/dcn30_cm_common.c | 32 +++++++++++++++----
>> .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
>> .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
>> .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++----
>> .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 ++++++----
>> 5 files changed, 50 insertions(+), 26 deletions(-)
>>
>> --
>> 2.51.0
>>
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT
2025-12-09 14:31 ` Melissa Wen
@ 2025-12-09 14:44 ` Melissa Wen
2025-12-09 15:12 ` Harry Wentland
0 siblings, 1 reply; 16+ messages in thread
From: Melissa Wen @ 2025-12-09 14:44 UTC (permalink / raw)
To: Matthew Schwartz
Cc: airlied, alexander.deucher, christian.koenig, harry.wentland,
simona, siqueira, sunpeng.li, kernel-dev, amd-gfx, dri-devel
On 09/12/2025 11:31, Melissa Wen wrote:
>
>
> On 08/12/2025 22:34, Matthew Schwartz wrote:
>>
>>> On Dec 8, 2025, at 3:48 PM, Melissa Wen <mwen@igalia.com> wrote:
>>>
>>> There are some unexpected banding and shimmer effects when using
>>> steamOS/gamescope color pipeline for HDR on DCN32 or newer families.
>>> Those problems are not present in Steam Deck (DCN301). It happens on
>>> DCN32 because plane shaper LUT uses DCN30 CM3 helper to translate
>>> curves
>>> instead of DCN10 CM helper. This series identifies the necessary
>>> changes
>>> on CM3 helper to reduce differences on color transformation made by
>>> those two helpers.
>>>
>>> Patch 1 aims to solve the shimmer/colorful points that looks like a
>>> wrong map of black values on red/green/blue colors. Patch 2 extends the
>>> delta clamping fix made in commit 27fc10d1095f ("drm/amd/display: Fix
>>> the delta clamping for shaper LUT") to solve some banding effects.
>>>
>>> Banding is not fully solved by any helper and needs further
>>> investigation.
>>>
>>> One easy way to check the current and expected behavior is moving the
>>> cursor (doing composition) to get the expected result from GFX. When
>>> the
>>> cursor disappears, those color transformations are back to be done by
>>> the display hw.
>> Hi Melissa,
>>
>> Could you share how you’re testing the gamescope color pipeline with
>> HDR on DCN32, i.e display and connection type? Are any extra
>> gamescope or kernel patches required?
>>
>> At least on my own DCN32 setup (AMD 7900XTX) + my primary monitor (an
>> LG 45gx950a-b) via DisplayPort or my DCN35 setup + integrated HDR
>> OLED screen (Legion Go 2), gamescope always composites when HDR is
>> enabled. I applied your patches on top of kernel 6.18, and my kernel
>> is built with CONFIG_DRM_AMD_COLOR_STEAMDECK=y (the downstream name
>> of AMD_PRIVATE_COLOR for SteamOS), so that shouldn't be an issue. I
>> tried everything from 1280x720p -> 5120x2160p, and it does not work
>> on any resolution.
> Hi Matt,
>
> You need to hack the DPP color caps to enabled SHAPER/3D and BLEND
> LUTs as below:
>
> diff --git
> i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
> w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
> index b276fec3e479..96b4f3239fb1 100644
> --- i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
> +++ w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
> @@ -2256,8 +2256,8 @@ static bool dcn32_resource_construct(
> dc->caps.color.dpp.gamma_corr = 1;
> dc->caps.color.dpp.dgam_rom_for_yuv = 0;
>
> - dc->caps.color.dpp.hw_3d_lut = 0;
> - dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN1
> + dc->caps.color.dpp.hw_3d_lut = 1;
> + dc->caps.color.dpp.ogam_ram = 1; // no OGAM in DPP since DCN1
> // no OGAM ROM on DCN2 and later ASICs
> dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
> dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
>
> In short, you need to change `caps.color.dpp.hw_3d_lut` and
> `caps.color.dpp.ogam_ram` to 1 in the dcnX_resource.c file to say
> there is a "plane" color caps.
> The thing is that, in DCN32+, these color caps are not part of DPP
> anymore, they are MPC capabilities in MCM that can be moved before or
> after blending.
> But the current kernel implementation checks DPP color caps to expose
> plane color proprerties.
> Checking MPC and where the MCM is positioned would be more complex,
> but not impossible. Something to improve in the future yes.
Just found this: dpp_color_caps.hw_3d_lut ||
dm->dc->caps.color.mpc.preblend
(https://gitlab.freedesktop.org/agd5f/linux/-/blob/amd-staging-drm-next/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c#L1636)
Should be enough for new kernel versions. So you might need only the
blend LUT hack.
>
> You need to confirm that your `drm_info` shows all AMD plane color
> properties, but gamescope basically checks CTM and BLEND_TF as you can
> see here:
> https://github.com/ValveSoftware/gamescope/blob/master/src/Backends/DRMBackend.cpp#L3347
>
>
> Let me know if it works for you.
>
> BR,
>
> Melissa
>
>>
>> Thanks,
>> Matt
>>
>>> Lemme know your thoughts!
>>>
>>> Melissa
>>>
>>> Melissa Wen (2):
>>> drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
>>> drm/amd/display: extend delta clamping logic to CM3 LUT helper
>>>
>>> .../amd/display/dc/dcn30/dcn30_cm_common.c | 32 +++++++++++++++----
>>> .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
>>> .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
>>> .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++----
>>> .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 ++++++----
>>> 5 files changed, 50 insertions(+), 26 deletions(-)
>>>
>>> --
>>> 2.51.0
>>>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT
2025-12-09 14:44 ` Melissa Wen
@ 2025-12-09 15:12 ` Harry Wentland
2025-12-09 15:18 ` Melissa Wen
0 siblings, 1 reply; 16+ messages in thread
From: Harry Wentland @ 2025-12-09 15:12 UTC (permalink / raw)
To: Melissa Wen, Matthew Schwartz
Cc: airlied, alexander.deucher, christian.koenig, simona, siqueira,
sunpeng.li, kernel-dev, amd-gfx, dri-devel
On 2025-12-09 09:44, Melissa Wen wrote:
>
>
> On 09/12/2025 11:31, Melissa Wen wrote:
>>
>>
>> On 08/12/2025 22:34, Matthew Schwartz wrote:
>>>
>>>> On Dec 8, 2025, at 3:48 PM, Melissa Wen <mwen@igalia.com> wrote:
>>>>
>>>> There are some unexpected banding and shimmer effects when using
>>>> steamOS/gamescope color pipeline for HDR on DCN32 or newer families.
>>>> Those problems are not present in Steam Deck (DCN301). It happens on
>>>> DCN32 because plane shaper LUT uses DCN30 CM3 helper to translate curves
>>>> instead of DCN10 CM helper. This series identifies the necessary changes
>>>> on CM3 helper to reduce differences on color transformation made by
>>>> those two helpers.
>>>>
>>>> Patch 1 aims to solve the shimmer/colorful points that looks like a
>>>> wrong map of black values on red/green/blue colors. Patch 2 extends the
>>>> delta clamping fix made in commit 27fc10d1095f ("drm/amd/display: Fix
>>>> the delta clamping for shaper LUT") to solve some banding effects.
>>>>
>>>> Banding is not fully solved by any helper and needs further
>>>> investigation.
>>>>
>>>> One easy way to check the current and expected behavior is moving the
>>>> cursor (doing composition) to get the expected result from GFX. When the
>>>> cursor disappears, those color transformations are back to be done by
>>>> the display hw.
>>> Hi Melissa,
>>>
>>> Could you share how you’re testing the gamescope color pipeline with HDR on DCN32, i.e display and connection type? Are any extra gamescope or kernel patches required?
>>>
>>> At least on my own DCN32 setup (AMD 7900XTX) + my primary monitor (an LG 45gx950a-b) via DisplayPort or my DCN35 setup + integrated HDR OLED screen (Legion Go 2), gamescope always composites when HDR is enabled. I applied your patches on top of kernel 6.18, and my kernel is built with CONFIG_DRM_AMD_COLOR_STEAMDECK=y (the downstream name of AMD_PRIVATE_COLOR for SteamOS), so that shouldn't be an issue. I tried everything from 1280x720p -> 5120x2160p, and it does not work on any resolution.
>> Hi Matt,
>>
>> You need to hack the DPP color caps to enabled SHAPER/3D and BLEND LUTs as below:
>>
>> diff --git i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>> index b276fec3e479..96b4f3239fb1 100644
>> --- i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>> +++ w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>> @@ -2256,8 +2256,8 @@ static bool dcn32_resource_construct(
>> dc->caps.color.dpp.gamma_corr = 1;
>> dc->caps.color.dpp.dgam_rom_for_yuv = 0;
>>
>> - dc->caps.color.dpp.hw_3d_lut = 0;
>> - dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN1
>> + dc->caps.color.dpp.hw_3d_lut = 1;
>> + dc->caps.color.dpp.ogam_ram = 1; // no OGAM in DPP since DCN1
>> // no OGAM ROM on DCN2 and later ASICs
>> dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
>> dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
>>
>> In short, you need to change `caps.color.dpp.hw_3d_lut` and `caps.color.dpp.ogam_ram` to 1 in the dcnX_resource.c file to say there is a "plane" color caps.
>> The thing is that, in DCN32+, these color caps are not part of DPP anymore, they are MPC capabilities in MCM that can be moved before or after blending.
>> But the current kernel implementation checks DPP color caps to expose plane color proprerties.
>> Checking MPC and where the MCM is positioned would be more complex, but not impossible. Something to improve in the future yes.
>
> Just found this: dpp_color_caps.hw_3d_lut || dm->dc->caps.color.mpc.preblend (https://gitlab.freedesktop.org/agd5f/linux/-/blob/amd-staging-drm-next/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c#L1636)
>
> Should be enough for new kernel versions. So you might need only the blend LUT hack.
>
>>
>> You need to confirm that your `drm_info` shows all AMD plane color properties, but gamescope basically checks CTM and BLEND_TF as you can see here:
>> https://github.com/ValveSoftware/gamescope/blob/master/src/Backends/DRMBackend.cpp#L3347
>>
Are you testing this with AMD_PRIVATE_COLOR, or with the newly merged color pipeline API? If it's the former, then the kernel needs to be built with an explicit -DAMD_PRIVATE_COLOR for this to work.
Harry
>> Let me know if it works for you.
>>
>> BR,
>>
>> Melissa
>>
>>>
>>> Thanks,
>>> Matt
>>>
>>>> Lemme know your thoughts!
>>>>
>>>> Melissa
>>>>
>>>> Melissa Wen (2):
>>>> drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
>>>> drm/amd/display: extend delta clamping logic to CM3 LUT helper
>>>>
>>>> .../amd/display/dc/dcn30/dcn30_cm_common.c | 32 +++++++++++++++----
>>>> .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
>>>> .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
>>>> .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++----
>>>> .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 ++++++----
>>>> 5 files changed, 50 insertions(+), 26 deletions(-)
>>>>
>>>> --
>>>> 2.51.0
>>>>
>>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT
2025-12-09 15:12 ` Harry Wentland
@ 2025-12-09 15:18 ` Melissa Wen
2025-12-09 18:19 ` Matthew Schwartz
0 siblings, 1 reply; 16+ messages in thread
From: Melissa Wen @ 2025-12-09 15:18 UTC (permalink / raw)
To: Harry Wentland, Matthew Schwartz
Cc: airlied, alexander.deucher, christian.koenig, simona, siqueira,
sunpeng.li, kernel-dev, amd-gfx, dri-devel
On 09/12/2025 12:12, Harry Wentland wrote:
>
> On 2025-12-09 09:44, Melissa Wen wrote:
>>
>> On 09/12/2025 11:31, Melissa Wen wrote:
>>>
>>> On 08/12/2025 22:34, Matthew Schwartz wrote:
>>>>> On Dec 8, 2025, at 3:48 PM, Melissa Wen <mwen@igalia.com> wrote:
>>>>>
>>>>> There are some unexpected banding and shimmer effects when using
>>>>> steamOS/gamescope color pipeline for HDR on DCN32 or newer families.
>>>>> Those problems are not present in Steam Deck (DCN301). It happens on
>>>>> DCN32 because plane shaper LUT uses DCN30 CM3 helper to translate curves
>>>>> instead of DCN10 CM helper. This series identifies the necessary changes
>>>>> on CM3 helper to reduce differences on color transformation made by
>>>>> those two helpers.
>>>>>
>>>>> Patch 1 aims to solve the shimmer/colorful points that looks like a
>>>>> wrong map of black values on red/green/blue colors. Patch 2 extends the
>>>>> delta clamping fix made in commit 27fc10d1095f ("drm/amd/display: Fix
>>>>> the delta clamping for shaper LUT") to solve some banding effects.
>>>>>
>>>>> Banding is not fully solved by any helper and needs further
>>>>> investigation.
>>>>>
>>>>> One easy way to check the current and expected behavior is moving the
>>>>> cursor (doing composition) to get the expected result from GFX. When the
>>>>> cursor disappears, those color transformations are back to be done by
>>>>> the display hw.
>>>> Hi Melissa,
>>>>
>>>> Could you share how you’re testing the gamescope color pipeline with HDR on DCN32, i.e display and connection type? Are any extra gamescope or kernel patches required?
>>>>
>>>> At least on my own DCN32 setup (AMD 7900XTX) + my primary monitor (an LG 45gx950a-b) via DisplayPort or my DCN35 setup + integrated HDR OLED screen (Legion Go 2), gamescope always composites when HDR is enabled. I applied your patches on top of kernel 6.18, and my kernel is built with CONFIG_DRM_AMD_COLOR_STEAMDECK=y (the downstream name of AMD_PRIVATE_COLOR for SteamOS), so that shouldn't be an issue. I tried everything from 1280x720p -> 5120x2160p, and it does not work on any resolution.
>>> Hi Matt,
>>>
>>> You need to hack the DPP color caps to enabled SHAPER/3D and BLEND LUTs as below:
>>>
>>> diff --git i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>> index b276fec3e479..96b4f3239fb1 100644
>>> --- i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>> +++ w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>> @@ -2256,8 +2256,8 @@ static bool dcn32_resource_construct(
>>> dc->caps.color.dpp.gamma_corr = 1;
>>> dc->caps.color.dpp.dgam_rom_for_yuv = 0;
>>>
>>> - dc->caps.color.dpp.hw_3d_lut = 0;
>>> - dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN1
>>> + dc->caps.color.dpp.hw_3d_lut = 1;
>>> + dc->caps.color.dpp.ogam_ram = 1; // no OGAM in DPP since DCN1
>>> // no OGAM ROM on DCN2 and later ASICs
>>> dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
>>> dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
>>>
>>> In short, you need to change `caps.color.dpp.hw_3d_lut` and `caps.color.dpp.ogam_ram` to 1 in the dcnX_resource.c file to say there is a "plane" color caps.
>>> The thing is that, in DCN32+, these color caps are not part of DPP anymore, they are MPC capabilities in MCM that can be moved before or after blending.
>>> But the current kernel implementation checks DPP color caps to expose plane color proprerties.
>>> Checking MPC and where the MCM is positioned would be more complex, but not impossible. Something to improve in the future yes.
>> Just found this: dpp_color_caps.hw_3d_lut || dm->dc->caps.color.mpc.preblend (https://gitlab.freedesktop.org/agd5f/linux/-/blob/amd-staging-drm-next/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c#L1636)
>>
>> Should be enough for new kernel versions. So you might need only the blend LUT hack.
>>
>>> You need to confirm that your `drm_info` shows all AMD plane color properties, but gamescope basically checks CTM and BLEND_TF as you can see here:
>>> https://github.com/ValveSoftware/gamescope/blob/master/src/Backends/DRMBackend.cpp#L3347
>>>
> Are you testing this with AMD_PRIVATE_COLOR, or with the newly merged color pipeline API? If it's the former, then the kernel needs to be built with an explicit -DAMD_PRIVATE_COLOR for this to work.
I'm testing with cflags, but AFAIU Matthew is using a downstream kernel
version where there is an extra commit that enables AMD_PRIVATE_COLOR
via config option ("CONFIG_DRM_AMD_COLOR_STEAMDECK=y").
Depends on this kernel version, the hack for 3D LUT and BLEND LUT are
both necessary.
>
> Harry
>
>>> Let me know if it works for you.
>>>
>>> BR,
>>>
>>> Melissa
>>>
>>>> Thanks,
>>>> Matt
>>>>
>>>>> Lemme know your thoughts!
>>>>>
>>>>> Melissa
>>>>>
>>>>> Melissa Wen (2):
>>>>> drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
>>>>> drm/amd/display: extend delta clamping logic to CM3 LUT helper
>>>>>
>>>>> .../amd/display/dc/dcn30/dcn30_cm_common.c | 32 +++++++++++++++----
>>>>> .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
>>>>> .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
>>>>> .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++----
>>>>> .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 ++++++----
>>>>> 5 files changed, 50 insertions(+), 26 deletions(-)
>>>>>
>>>>> --
>>>>> 2.51.0
>>>>>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT
2025-12-09 15:18 ` Melissa Wen
@ 2025-12-09 18:19 ` Matthew Schwartz
2025-12-10 20:46 ` Melissa Wen
0 siblings, 1 reply; 16+ messages in thread
From: Matthew Schwartz @ 2025-12-09 18:19 UTC (permalink / raw)
To: Melissa Wen, Harry Wentland
Cc: airlied, alexander.deucher, christian.koenig, simona, siqueira,
sunpeng.li, kernel-dev, amd-gfx, dri-devel
On 12/9/25 7:18 AM, Melissa Wen wrote:
>
>
> On 09/12/2025 12:12, Harry Wentland wrote:
>>
>> On 2025-12-09 09:44, Melissa Wen wrote:
>>>
>>> On 09/12/2025 11:31, Melissa Wen wrote:
>>>>
>>>> On 08/12/2025 22:34, Matthew Schwartz wrote:
>>>>>> On Dec 8, 2025, at 3:48 PM, Melissa Wen <mwen@igalia.com> wrote:
>>>>>>
>>>>>> There are some unexpected banding and shimmer effects when using
>>>>>> steamOS/gamescope color pipeline for HDR on DCN32 or newer families.
>>>>>> Those problems are not present in Steam Deck (DCN301). It happens on
>>>>>> DCN32 because plane shaper LUT uses DCN30 CM3 helper to translate curves
>>>>>> instead of DCN10 CM helper. This series identifies the necessary changes
>>>>>> on CM3 helper to reduce differences on color transformation made by
>>>>>> those two helpers.
>>>>>>
>>>>>> Patch 1 aims to solve the shimmer/colorful points that looks like a
>>>>>> wrong map of black values on red/green/blue colors. Patch 2 extends the
>>>>>> delta clamping fix made in commit 27fc10d1095f ("drm/amd/display: Fix
>>>>>> the delta clamping for shaper LUT") to solve some banding effects.
>>>>>>
>>>>>> Banding is not fully solved by any helper and needs further
>>>>>> investigation.
>>>>>>
>>>>>> One easy way to check the current and expected behavior is moving the
>>>>>> cursor (doing composition) to get the expected result from GFX. When the
>>>>>> cursor disappears, those color transformations are back to be done by
>>>>>> the display hw.
>>>>> Hi Melissa,
>>>>>
>>>>> Could you share how you’re testing the gamescope color pipeline with HDR on DCN32, i.e display and connection type? Are any extra gamescope or kernel patches required?
>>>>>
>>>>> At least on my own DCN32 setup (AMD 7900XTX) + my primary monitor (an LG 45gx950a-b) via DisplayPort or my DCN35 setup + integrated HDR OLED screen (Legion Go 2), gamescope always composites when HDR is enabled. I applied your patches on top of kernel 6.18, and my kernel is built with CONFIG_DRM_AMD_COLOR_STEAMDECK=y (the downstream name of AMD_PRIVATE_COLOR for SteamOS), so that shouldn't be an issue. I tried everything from 1280x720p -> 5120x2160p, and it does not work on any resolution.
>>>> Hi Matt,
>>>>
>>>> You need to hack the DPP color caps to enabled SHAPER/3D and BLEND LUTs as below:
>>>>
>>>> diff --git i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>>> index b276fec3e479..96b4f3239fb1 100644
>>>> --- i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>>> +++ w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>>> @@ -2256,8 +2256,8 @@ static bool dcn32_resource_construct(
>>>> dc->caps.color.dpp.gamma_corr = 1;
>>>> dc->caps.color.dpp.dgam_rom_for_yuv = 0;
>>>>
>>>> - dc->caps.color.dpp.hw_3d_lut = 0;
>>>> - dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN1
>>>> + dc->caps.color.dpp.hw_3d_lut = 1;
>>>> + dc->caps.color.dpp.ogam_ram = 1; // no OGAM in DPP since DCN1
>>>> // no OGAM ROM on DCN2 and later ASICs
>>>> dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
>>>> dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
>>>>
>>>> In short, you need to change `caps.color.dpp.hw_3d_lut` and `caps.color.dpp.ogam_ram` to 1 in the dcnX_resource.c file to say there is a "plane" color caps.
>>>> The thing is that, in DCN32+, these color caps are not part of DPP anymore, they are MPC capabilities in MCM that can be moved before or after blending.
>>>> But the current kernel implementation checks DPP color caps to expose plane color proprerties.
>>>> Checking MPC and where the MCM is positioned would be more complex, but not impossible. Something to improve in the future yes.
>>> Just found this: dpp_color_caps.hw_3d_lut || dm->dc->caps.color.mpc.preblend (https://gitlab.freedesktop.org/agd5f/linux/-/blob/amd-staging-drm-next/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c#L1636)
>>>
>>> Should be enough for new kernel versions. So you might need only the blend LUT hack.
>>>
>>>> You need to confirm that your `drm_info` shows all AMD plane color properties, but gamescope basically checks CTM and BLEND_TF as you can see here:
>>>> https://github.com/ValveSoftware/gamescope/blob/master/src/Backends/DRMBackend.cpp#L3347
>>>>
>> Are you testing this with AMD_PRIVATE_COLOR, or with the newly merged color pipeline API? If it's the former, then the kernel needs to be built with an explicit -DAMD_PRIVATE_COLOR for this to work.
>
> I'm testing with cflags, but AFAIU Matthew is using a downstream kernel version where there is an extra commit that enables AMD_PRIVATE_COLOR via config option ("CONFIG_DRM_AMD_COLOR_STEAMDECK=y").
> Depends on this kernel version, the hack for 3D LUT and BLEND LUT are both necessary.
Thanks, I had such a change locally to add back AMD_PLANE_BLEND_TF but I was seeing some color banding in Ori and the Will of the Wisps menu around the sun in the upper left corner which gave me pause. I see you mentioned something similar in one of the threads [1] though, so we're all on the same page now.
I'm not sure if you've also tried this, but gamescopectl drm_debug_disable_output_tf 1 seems to work around the color banding in that case. From what I could tell, this bypasses the hardware LUTs while HDR scanout continues working in gamescope. We lose blending on the MangoHud overlay by disabling that though. I was thinking maybe it's due to the MCM block only doing preblend unlike DPP blending, but I could definitely be on the wrong track here...
[1]: https://lore.kernel.org/amd-gfx/7ad74d3d-5a63-462b-8243-f8f26441b04b@igalia.com/
>
>>
>> Harry
>>
>>>> Let me know if it works for you.
>>>>
>>>> BR,
>>>>
>>>> Melissa
>>>>
>>>>> Thanks,
>>>>> Matt
>>>>>
>>>>>> Lemme know your thoughts!
>>>>>>
>>>>>> Melissa
>>>>>>
>>>>>> Melissa Wen (2):
>>>>>> drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
>>>>>> drm/amd/display: extend delta clamping logic to CM3 LUT helper
>>>>>>
>>>>>> .../amd/display/dc/dcn30/dcn30_cm_common.c | 32 +++++++++++++++----
>>>>>> .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
>>>>>> .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
>>>>>> .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++----
>>>>>> .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 ++++++----
>>>>>> 5 files changed, 50 insertions(+), 26 deletions(-)
>>>>>>
>>>>>> --
>>>>>> 2.51.0
>>>>>>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT
2025-12-09 18:19 ` Matthew Schwartz
@ 2025-12-10 20:46 ` Melissa Wen
2025-12-10 20:56 ` Matthew Schwartz
0 siblings, 1 reply; 16+ messages in thread
From: Melissa Wen @ 2025-12-10 20:46 UTC (permalink / raw)
To: Matthew Schwartz, Harry Wentland
Cc: airlied, alexander.deucher, christian.koenig, simona, siqueira,
sunpeng.li, kernel-dev, amd-gfx, dri-devel
On 09/12/2025 15:19, Matthew Schwartz wrote:
> On 12/9/25 7:18 AM, Melissa Wen wrote:
>>
>> On 09/12/2025 12:12, Harry Wentland wrote:
>>> On 2025-12-09 09:44, Melissa Wen wrote:
>>>> On 09/12/2025 11:31, Melissa Wen wrote:
>>>>> On 08/12/2025 22:34, Matthew Schwartz wrote:
>>>>>>> On Dec 8, 2025, at 3:48 PM, Melissa Wen <mwen@igalia.com> wrote:
>>>>>>>
>>>>>>> There are some unexpected banding and shimmer effects when using
>>>>>>> steamOS/gamescope color pipeline for HDR on DCN32 or newer families.
>>>>>>> Those problems are not present in Steam Deck (DCN301). It happens on
>>>>>>> DCN32 because plane shaper LUT uses DCN30 CM3 helper to translate curves
>>>>>>> instead of DCN10 CM helper. This series identifies the necessary changes
>>>>>>> on CM3 helper to reduce differences on color transformation made by
>>>>>>> those two helpers.
>>>>>>>
>>>>>>> Patch 1 aims to solve the shimmer/colorful points that looks like a
>>>>>>> wrong map of black values on red/green/blue colors. Patch 2 extends the
>>>>>>> delta clamping fix made in commit 27fc10d1095f ("drm/amd/display: Fix
>>>>>>> the delta clamping for shaper LUT") to solve some banding effects.
>>>>>>>
>>>>>>> Banding is not fully solved by any helper and needs further
>>>>>>> investigation.
>>>>>>>
>>>>>>> One easy way to check the current and expected behavior is moving the
>>>>>>> cursor (doing composition) to get the expected result from GFX. When the
>>>>>>> cursor disappears, those color transformations are back to be done by
>>>>>>> the display hw.
>>>>>> Hi Melissa,
>>>>>>
>>>>>> Could you share how you’re testing the gamescope color pipeline with HDR on DCN32, i.e display and connection type? Are any extra gamescope or kernel patches required?
>>>>>>
>>>>>> At least on my own DCN32 setup (AMD 7900XTX) + my primary monitor (an LG 45gx950a-b) via DisplayPort or my DCN35 setup + integrated HDR OLED screen (Legion Go 2), gamescope always composites when HDR is enabled. I applied your patches on top of kernel 6.18, and my kernel is built with CONFIG_DRM_AMD_COLOR_STEAMDECK=y (the downstream name of AMD_PRIVATE_COLOR for SteamOS), so that shouldn't be an issue. I tried everything from 1280x720p -> 5120x2160p, and it does not work on any resolution.
>>>>> Hi Matt,
>>>>>
>>>>> You need to hack the DPP color caps to enabled SHAPER/3D and BLEND LUTs as below:
>>>>>
>>>>> diff --git i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>>>> index b276fec3e479..96b4f3239fb1 100644
>>>>> --- i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>>>> +++ w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>>>> @@ -2256,8 +2256,8 @@ static bool dcn32_resource_construct(
>>>>> dc->caps.color.dpp.gamma_corr = 1;
>>>>> dc->caps.color.dpp.dgam_rom_for_yuv = 0;
>>>>>
>>>>> - dc->caps.color.dpp.hw_3d_lut = 0;
>>>>> - dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN1
>>>>> + dc->caps.color.dpp.hw_3d_lut = 1;
>>>>> + dc->caps.color.dpp.ogam_ram = 1; // no OGAM in DPP since DCN1
>>>>> // no OGAM ROM on DCN2 and later ASICs
>>>>> dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
>>>>> dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
>>>>>
>>>>> In short, you need to change `caps.color.dpp.hw_3d_lut` and `caps.color.dpp.ogam_ram` to 1 in the dcnX_resource.c file to say there is a "plane" color caps.
>>>>> The thing is that, in DCN32+, these color caps are not part of DPP anymore, they are MPC capabilities in MCM that can be moved before or after blending.
>>>>> But the current kernel implementation checks DPP color caps to expose plane color proprerties.
>>>>> Checking MPC and where the MCM is positioned would be more complex, but not impossible. Something to improve in the future yes.
>>>> Just found this: dpp_color_caps.hw_3d_lut || dm->dc->caps.color.mpc.preblend (https://gitlab.freedesktop.org/agd5f/linux/-/blob/amd-staging-drm-next/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c#L1636)
>>>>
>>>> Should be enough for new kernel versions. So you might need only the blend LUT hack.
>>>>
>>>>> You need to confirm that your `drm_info` shows all AMD plane color properties, but gamescope basically checks CTM and BLEND_TF as you can see here:
>>>>> https://github.com/ValveSoftware/gamescope/blob/master/src/Backends/DRMBackend.cpp#L3347
>>>>>
>>> Are you testing this with AMD_PRIVATE_COLOR, or with the newly merged color pipeline API? If it's the former, then the kernel needs to be built with an explicit -DAMD_PRIVATE_COLOR for this to work.
>> I'm testing with cflags, but AFAIU Matthew is using a downstream kernel version where there is an extra commit that enables AMD_PRIVATE_COLOR via config option ("CONFIG_DRM_AMD_COLOR_STEAMDECK=y").
>> Depends on this kernel version, the hack for 3D LUT and BLEND LUT are both necessary.
> Thanks, I had such a change locally to add back AMD_PLANE_BLEND_TF but I was seeing some color banding in Ori and the Will of the Wisps menu around the sun in the upper left corner which gave me pause. I see you mentioned something similar in one of the threads [1] though, so we're all on the same page now.
>
> I'm not sure if you've also tried this, but gamescopectl drm_debug_disable_output_tf 1 seems to work around the color banding in that case. From what I could tell, this bypasses the hardware LUTs while HDR scanout continues working in gamescope. We lose blending on the MangoHud overlay by disabling that though. I was thinking maybe it's due to the MCM block only doing preblend unlike DPP blending, but I could definitely be on the wrong track here...
I didn't try it, but you gave an idea to bypass each transfer_func one
by one to identify in which block the issue comes from.
Just to let you know that I also see the same banding on Ori with Steam
Deck OLED if plugged in a external monitor with HDR. Steam Deck hw
doesn't have the MCM structure.
I'll try to narrow down this issue a bit more.
Still, the patches in this series address shaper LUT issues that are
present in DCN32 but not in DCN301.
Melissa
>
> [1]: https://lore.kernel.org/amd-gfx/7ad74d3d-5a63-462b-8243-f8f26441b04b@igalia.com/
>
>>> Harry
>>>
>>>>> Let me know if it works for you.
>>>>>
>>>>> BR,
>>>>>
>>>>> Melissa
>>>>>
>>>>>> Thanks,
>>>>>> Matt
>>>>>>
>>>>>>> Lemme know your thoughts!
>>>>>>>
>>>>>>> Melissa
>>>>>>>
>>>>>>> Melissa Wen (2):
>>>>>>> drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
>>>>>>> drm/amd/display: extend delta clamping logic to CM3 LUT helper
>>>>>>>
>>>>>>> .../amd/display/dc/dcn30/dcn30_cm_common.c | 32 +++++++++++++++----
>>>>>>> .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
>>>>>>> .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
>>>>>>> .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++----
>>>>>>> .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 ++++++----
>>>>>>> 5 files changed, 50 insertions(+), 26 deletions(-)
>>>>>>>
>>>>>>> --
>>>>>>> 2.51.0
>>>>>>>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT
2025-12-10 20:46 ` Melissa Wen
@ 2025-12-10 20:56 ` Matthew Schwartz
0 siblings, 0 replies; 16+ messages in thread
From: Matthew Schwartz @ 2025-12-10 20:56 UTC (permalink / raw)
To: Melissa Wen
Cc: Matthew Schwartz, Harry Wentland, airlied, alexander.deucher,
christian.koenig, simona, siqueira, sunpeng.li, kernel-dev,
amd-gfx, dri-devel
> On Dec 10, 2025, at 12:48 PM, Melissa Wen <mwen@igalia.com> wrote:
>
>
>
>> On 09/12/2025 15:19, Matthew Schwartz wrote:
>>> On 12/9/25 7:18 AM, Melissa Wen wrote:
>>>
>>> On 09/12/2025 12:12, Harry Wentland wrote:
>>>> On 2025-12-09 09:44, Melissa Wen wrote:
>>>>> On 09/12/2025 11:31, Melissa Wen wrote:
>>>>>> On 08/12/2025 22:34, Matthew Schwartz wrote:
>>>>>>>> On Dec 8, 2025, at 3:48 PM, Melissa Wen <mwen@igalia.com> wrote:
>>>>>>>>
>>>>>>>> There are some unexpected banding and shimmer effects when using
>>>>>>>> steamOS/gamescope color pipeline for HDR on DCN32 or newer families.
>>>>>>>> Those problems are not present in Steam Deck (DCN301). It happens on
>>>>>>>> DCN32 because plane shaper LUT uses DCN30 CM3 helper to translate curves
>>>>>>>> instead of DCN10 CM helper. This series identifies the necessary changes
>>>>>>>> on CM3 helper to reduce differences on color transformation made by
>>>>>>>> those two helpers.
>>>>>>>>
>>>>>>>> Patch 1 aims to solve the shimmer/colorful points that looks like a
>>>>>>>> wrong map of black values on red/green/blue colors. Patch 2 extends the
>>>>>>>> delta clamping fix made in commit 27fc10d1095f ("drm/amd/display: Fix
>>>>>>>> the delta clamping for shaper LUT") to solve some banding effects.
>>>>>>>>
>>>>>>>> Banding is not fully solved by any helper and needs further
>>>>>>>> investigation.
>>>>>>>>
>>>>>>>> One easy way to check the current and expected behavior is moving the
>>>>>>>> cursor (doing composition) to get the expected result from GFX. When the
>>>>>>>> cursor disappears, those color transformations are back to be done by
>>>>>>>> the display hw.
>>>>>>> Hi Melissa,
>>>>>>>
>>>>>>> Could you share how you’re testing the gamescope color pipeline with HDR on DCN32, i.e display and connection type? Are any extra gamescope or kernel patches required?
>>>>>>>
>>>>>>> At least on my own DCN32 setup (AMD 7900XTX) + my primary monitor (an LG 45gx950a-b) via DisplayPort or my DCN35 setup + integrated HDR OLED screen (Legion Go 2), gamescope always composites when HDR is enabled. I applied your patches on top of kernel 6.18, and my kernel is built with CONFIG_DRM_AMD_COLOR_STEAMDECK=y (the downstream name of AMD_PRIVATE_COLOR for SteamOS), so that shouldn't be an issue. I tried everything from 1280x720p -> 5120x2160p, and it does not work on any resolution.
>>>>>> Hi Matt,
>>>>>>
>>>>>> You need to hack the DPP color caps to enabled SHAPER/3D and BLEND LUTs as below:
>>>>>>
>>>>>> diff --git i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>>>>> index b276fec3e479..96b4f3239fb1 100644
>>>>>> --- i/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>>>>> +++ w/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
>>>>>> @@ -2256,8 +2256,8 @@ static bool dcn32_resource_construct(
>>>>>> dc->caps.color.dpp.gamma_corr = 1;
>>>>>> dc->caps.color.dpp.dgam_rom_for_yuv = 0;
>>>>>>
>>>>>> - dc->caps.color.dpp.hw_3d_lut = 0;
>>>>>> - dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN1
>>>>>> + dc->caps.color.dpp.hw_3d_lut = 1;
>>>>>> + dc->caps.color.dpp.ogam_ram = 1; // no OGAM in DPP since DCN1
>>>>>> // no OGAM ROM on DCN2 and later ASICs
>>>>>> dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
>>>>>> dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
>>>>>>
>>>>>> In short, you need to change `caps.color.dpp.hw_3d_lut` and `caps.color.dpp.ogam_ram` to 1 in the dcnX_resource.c file to say there is a "plane" color caps.
>>>>>> The thing is that, in DCN32+, these color caps are not part of DPP anymore, they are MPC capabilities in MCM that can be moved before or after blending.
>>>>>> But the current kernel implementation checks DPP color caps to expose plane color proprerties.
>>>>>> Checking MPC and where the MCM is positioned would be more complex, but not impossible. Something to improve in the future yes.
>>>>> Just found this: dpp_color_caps.hw_3d_lut || dm->dc->caps.color.mpc.preblend (https://gitlab.freedesktop.org/agd5f/linux/-/blob/amd-staging-drm-next/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c#L1636)
>>>>>
>>>>> Should be enough for new kernel versions. So you might need only the blend LUT hack.
>>>>>
>>>>>> You need to confirm that your `drm_info` shows all AMD plane color properties, but gamescope basically checks CTM and BLEND_TF as you can see here:
>>>>>> https://github.com/ValveSoftware/gamescope/blob/master/src/Backends/DRMBackend.cpp#L3347
>>>>>>
>>>> Are you testing this with AMD_PRIVATE_COLOR, or with the newly merged color pipeline API? If it's the former, then the kernel needs to be built with an explicit -DAMD_PRIVATE_COLOR for this to work.
>>> I'm testing with cflags, but AFAIU Matthew is using a downstream kernel version where there is an extra commit that enables AMD_PRIVATE_COLOR via config option ("CONFIG_DRM_AMD_COLOR_STEAMDECK=y").
>>> Depends on this kernel version, the hack for 3D LUT and BLEND LUT are both necessary.
>> Thanks, I had such a change locally to add back AMD_PLANE_BLEND_TF but I was seeing some color banding in Ori and the Will of the Wisps menu around the sun in the upper left corner which gave me pause. I see you mentioned something similar in one of the threads [1] though, so we're all on the same page now.
>>
>> I'm not sure if you've also tried this, but gamescopectl drm_debug_disable_output_tf 1 seems to work around the color banding in that case. From what I could tell, this bypasses the hardware LUTs while HDR scanout continues working in gamescope. We lose blending on the MangoHud overlay by disabling that though. I was thinking maybe it's due to the MCM block only doing preblend unlike DPP blending, but I could definitely be on the wrong track here...
> I didn't try it, but you gave an idea to bypass each transfer_func one by one to identify in which block the issue comes from.
> Just to let you know that I also see the same banding on Ori with Steam Deck OLED if plugged in an external monitor with HDR. Steam Deck hw doesn't have the MCM structure.
Interesting, was not aware of banding present in that scenario with OLED Deck as well so that’s definitely good to know.
>
> I'll try to narrow down this issue a bit more.
> Still, the patches in this series address shaper LUT issues that are present in DCN32 but not in DCN301.
Yep, all clear now given the above info. I’ll give it some testing as well. Thanks!
>
> Melissa
>>
>> [1]: https://lore.kernel.org/amd-gfx/7ad74d3d-5a63-462b-8243-f8f26441b04b@igalia.com/
>>
>>>> Harry
>>>>
>>>>>> Let me know if it works for you.
>>>>>>
>>>>>> BR,
>>>>>>
>>>>>> Melissa
>>>>>>
>>>>>>> Thanks,
>>>>>>> Matt
>>>>>>>
>>>>>>>> Lemme know your thoughts!
>>>>>>>>
>>>>>>>> Melissa
>>>>>>>>
>>>>>>>> Melissa Wen (2):
>>>>>>>> drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
>>>>>>>> drm/amd/display: extend delta clamping logic to CM3 LUT helper
>>>>>>>>
>>>>>>>> .../amd/display/dc/dcn30/dcn30_cm_common.c | 32 +++++++++++++++----
>>>>>>>> .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
>>>>>>>> .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
>>>>>>>> .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++----
>>>>>>>> .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 ++++++----
>>>>>>>> 5 files changed, 50 insertions(+), 26 deletions(-)
>>>>>>>>
>>>>>>>> --
>>>>>>>> 2.51.0
>>>>>>>>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT
2025-12-08 23:44 [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT Melissa Wen
` (2 preceding siblings ...)
2025-12-09 1:34 ` [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT Matthew Schwartz
@ 2026-01-16 17:08 ` Melissa Wen
3 siblings, 0 replies; 16+ messages in thread
From: Melissa Wen @ 2026-01-16 17:08 UTC (permalink / raw)
To: airlied, alexander.deucher, christian.koenig, harry.wentland,
simona, siqueira, sunpeng.li
Cc: kernel-dev, amd-gfx, dri-devel
On 08/12/2025 20:44, Melissa Wen wrote:
> There are some unexpected banding and shimmer effects when using
> steamOS/gamescope color pipeline for HDR on DCN32 or newer families.
> Those problems are not present in Steam Deck (DCN301). It happens on
> DCN32 because plane shaper LUT uses DCN30 CM3 helper to translate curves
> instead of DCN10 CM helper. This series identifies the necessary changes
> on CM3 helper to reduce differences on color transformation made by
> those two helpers.
>
> Patch 1 aims to solve the shimmer/colorful points that looks like a
> wrong map of black values on red/green/blue colors. Patch 2 extends the
> delta clamping fix made in commit 27fc10d1095f ("drm/amd/display: Fix
> the delta clamping for shaper LUT") to solve some banding effects.
Hey,
Any news about these two color issues and respective fixes?
Melissa
>
> Banding is not fully solved by any helper and needs further
> investigation.
>
> One easy way to check the current and expected behavior is moving the
> cursor (doing composition) to get the expected result from GFX. When the
> cursor disappears, those color transformations are back to be done by
> the display hw.
>
> Lemme know your thoughts!
>
> Melissa
>
> Melissa Wen (2):
> drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
> drm/amd/display: extend delta clamping logic to CM3 LUT helper
>
> .../amd/display/dc/dcn30/dcn30_cm_common.c | 32 +++++++++++++++----
> .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
> .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
> .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++----
> .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 ++++++----
> 5 files changed, 50 insertions(+), 26 deletions(-)
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 2/2] drm/amd/display: extend delta clamping logic to CM3 LUT helper
2025-12-08 23:44 ` [RFC PATCH 2/2] drm/amd/display: extend delta clamping logic to CM3 LUT helper Melissa Wen
@ 2026-01-16 20:27 ` Harry Wentland
2026-01-16 23:52 ` Alex Hung
0 siblings, 1 reply; 16+ messages in thread
From: Harry Wentland @ 2026-01-16 20:27 UTC (permalink / raw)
To: Melissa Wen, airlied, alexander.deucher, christian.koenig, simona,
siqueira, sunpeng.li
Cc: kernel-dev, amd-gfx, dri-devel
On 2025-12-08 18:44, Melissa Wen wrote:
> Commit 27fc10d1095f ("drm/amd/display: Fix the delta clamping for shaper
> LUT") fixed banding when using plane shaper LUT in DCN10 CM helper. The
> problem is also present in DCN30 CM helper, fix banding by extending the
> same bug delta clamping fix to CM3.
>
> Signed-off-by: Melissa Wen <mwen@igalia.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Harry
> ---
> .../amd/display/dc/dcn30/dcn30_cm_common.c | 30 +++++++++++++++----
> .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
> .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
> .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++-----
> .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 +++++-----
> 5 files changed, 49 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
> index ba20575be214..b1c2c8da1937 100644
> --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
> +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
> @@ -105,9 +105,12 @@ void cm_helper_program_gamcor_xfer_func(
> #define NUMBER_REGIONS 32
> #define NUMBER_SW_SEGMENTS 16
>
> -bool cm3_helper_translate_curve_to_hw_format(
> - const struct dc_transfer_func *output_tf,
> - struct pwl_params *lut_params, bool fixpoint)
> +#define DC_LOGGER \
> + ctx->logger
> +
> +bool cm3_helper_translate_curve_to_hw_format(struct dc_context *ctx,
> + const struct dc_transfer_func *output_tf,
> + struct pwl_params *lut_params, bool fixpoint)
> {
> struct curve_points3 *corner_points;
> struct pwl_result_data *rgb_resulted;
> @@ -248,6 +251,10 @@ bool cm3_helper_translate_curve_to_hw_format(
> if (fixpoint == true) {
> i = 1;
> while (i != hw_points + 2) {
> + uint32_t red_clamp;
> + uint32_t green_clamp;
> + uint32_t blue_clamp;
> +
> if (i >= hw_points) {
> if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
> rgb_plus_1->red = dc_fixpt_add(rgb->red,
> @@ -260,9 +267,20 @@ bool cm3_helper_translate_curve_to_hw_format(
> rgb_minus_1->delta_blue);
> }
>
> - rgb->delta_red_reg = dc_fixpt_clamp_u0d10(rgb->delta_red);
> - rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green);
> - rgb->delta_blue_reg = dc_fixpt_clamp_u0d10(rgb->delta_blue);
> + rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red);
> + rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
> + rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue);
> +
> + red_clamp = dc_fixpt_clamp_u0d14(rgb->delta_red);
> + green_clamp = dc_fixpt_clamp_u0d14(rgb->delta_green);
> + blue_clamp = dc_fixpt_clamp_u0d14(rgb->delta_blue);
> +
> + if (red_clamp >> 10 || green_clamp >> 10 || blue_clamp >> 10)
> + DC_LOG_ERROR("Losing delta precision while programming shaper LUT.");
> +
> + rgb->delta_red_reg = red_clamp & 0x3ff;
> + rgb->delta_green_reg = green_clamp & 0x3ff;
> + rgb->delta_blue_reg = blue_clamp & 0x3ff;
> rgb->red_reg = dc_fixpt_clamp_u0d14(rgb->red);
> rgb->green_reg = dc_fixpt_clamp_u0d14(rgb->green);
> rgb->blue_reg = dc_fixpt_clamp_u0d14(rgb->blue);
> diff --git a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h
> index b86347c9b038..95f9318a54ef 100644
> --- a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h
> +++ b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h
> @@ -59,7 +59,7 @@ void cm_helper_program_gamcor_xfer_func(
> const struct pwl_params *params,
> const struct dcn3_xfer_func_reg *reg);
>
> -bool cm3_helper_translate_curve_to_hw_format(
> +bool cm3_helper_translate_curve_to_hw_format(struct dc_context *ctx,
> const struct dc_transfer_func *output_tf,
> struct pwl_params *lut_params, bool fixpoint);
>
> diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
> index 81bcadf5e57e..f2d4cd527874 100644
> --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
> +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
> @@ -239,7 +239,7 @@ bool dcn30_set_blend_lut(
> if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
> blend_lut = &plane_state->blend_tf.pwl;
> else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
> - result = cm3_helper_translate_curve_to_hw_format(
> + result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
> &plane_state->blend_tf, &dpp_base->regamma_params, false);
> if (!result)
> return result;
> @@ -334,8 +334,9 @@ bool dcn30_set_input_transfer_func(struct dc *dc,
> if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL)
> params = &plane_state->in_transfer_func.pwl;
> else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS &&
> - cm3_helper_translate_curve_to_hw_format(&plane_state->in_transfer_func,
> - &dpp_base->degamma_params, false))
> + cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
> + &plane_state->in_transfer_func,
> + &dpp_base->degamma_params, false))
> params = &dpp_base->degamma_params;
>
> result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
> @@ -406,7 +407,7 @@ bool dcn30_set_output_transfer_func(struct dc *dc,
> params = &stream->out_transfer_func.pwl;
> else if (pipe_ctx->stream->out_transfer_func.type ==
> TF_TYPE_DISTRIBUTED_POINTS &&
> - cm3_helper_translate_curve_to_hw_format(
> + cm3_helper_translate_curve_to_hw_format(stream->ctx,
> &stream->out_transfer_func,
> &mpc->blender_params, false))
> params = &mpc->blender_params;
> diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
> index b213a2ac827a..27abc08918bc 100644
> --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
> +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
> @@ -486,8 +486,9 @@ bool dcn32_set_mcm_luts(
> if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
> lut_params = &plane_state->blend_tf.pwl;
> else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
> - result = cm3_helper_translate_curve_to_hw_format(&plane_state->blend_tf,
> - &dpp_base->regamma_params, false);
> + result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
> + &plane_state->blend_tf,
> + &dpp_base->regamma_params, false);
> if (!result)
> return result;
>
> @@ -502,8 +503,9 @@ bool dcn32_set_mcm_luts(
> else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
> // TODO: dpp_base replace
> ASSERT(false);
> - cm3_helper_translate_curve_to_hw_format(&plane_state->in_shaper_func,
> - &dpp_base->shaper_params, true);
> + cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
> + &plane_state->in_shaper_func,
> + &dpp_base->shaper_params, true);
> lut_params = &dpp_base->shaper_params;
> }
>
> @@ -543,8 +545,9 @@ bool dcn32_set_input_transfer_func(struct dc *dc,
> if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL)
> params = &plane_state->in_transfer_func.pwl;
> else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS &&
> - cm3_helper_translate_curve_to_hw_format(&plane_state->in_transfer_func,
> - &dpp_base->degamma_params, false))
> + cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
> + &plane_state->in_transfer_func,
> + &dpp_base->degamma_params, false))
> params = &dpp_base->degamma_params;
>
> dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
> @@ -575,7 +578,7 @@ bool dcn32_set_output_transfer_func(struct dc *dc,
> params = &stream->out_transfer_func.pwl;
> else if (pipe_ctx->stream->out_transfer_func.type ==
> TF_TYPE_DISTRIBUTED_POINTS &&
> - cm3_helper_translate_curve_to_hw_format(
> + cm3_helper_translate_curve_to_hw_format(stream->ctx,
> &stream->out_transfer_func,
> &mpc->blender_params, false))
> params = &mpc->blender_params;
> diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
> index 2fbc22afb89c..5eda7648d0d2 100644
> --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
> +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
> @@ -430,7 +430,7 @@ void dcn401_populate_mcm_luts(struct dc *dc,
> if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL)
> m_lut_params.pwl = &mcm_luts.lut1d_func->pwl;
> else if (mcm_luts.lut1d_func->type == TF_TYPE_DISTRIBUTED_POINTS) {
> - rval = cm3_helper_translate_curve_to_hw_format(
> + rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx,
> mcm_luts.lut1d_func,
> &dpp_base->regamma_params, false);
> m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
> @@ -450,7 +450,7 @@ void dcn401_populate_mcm_luts(struct dc *dc,
> m_lut_params.pwl = &mcm_luts.shaper->pwl;
> else if (mcm_luts.shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
> ASSERT(false);
> - rval = cm3_helper_translate_curve_to_hw_format(
> + rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx,
> mcm_luts.shaper,
> &dpp_base->regamma_params, true);
> m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
> @@ -627,8 +627,9 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
> if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
> lut_params = &plane_state->blend_tf.pwl;
> else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
> - rval = cm3_helper_translate_curve_to_hw_format(&plane_state->blend_tf,
> - &dpp_base->regamma_params, false);
> + rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
> + &plane_state->blend_tf,
> + &dpp_base->regamma_params, false);
> lut_params = rval ? &dpp_base->regamma_params : NULL;
> }
> result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id);
> @@ -639,8 +640,9 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
> lut_params = &plane_state->in_shaper_func.pwl;
> else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
> // TODO: dpp_base replace
> - rval = cm3_helper_translate_curve_to_hw_format(&plane_state->in_shaper_func,
> - &dpp_base->shaper_params, true);
> + rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
> + &plane_state->in_shaper_func,
> + &dpp_base->shaper_params, true);
> lut_params = rval ? &dpp_base->shaper_params : NULL;
> }
> result &= mpc->funcs->program_shaper(mpc, lut_params, mpcc_id);
> @@ -674,7 +676,7 @@ bool dcn401_set_output_transfer_func(struct dc *dc,
> params = &stream->out_transfer_func.pwl;
> else if (pipe_ctx->stream->out_transfer_func.type ==
> TF_TYPE_DISTRIBUTED_POINTS &&
> - cm3_helper_translate_curve_to_hw_format(
> + cm3_helper_translate_curve_to_hw_format(stream->ctx,
> &stream->out_transfer_func,
> &mpc->blender_params, false))
> params = &mpc->blender_params;
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 1/2] drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
2025-12-08 23:44 ` [RFC PATCH 1/2] drm/amd/display: fix wrong color value mapping on DCN32 " Melissa Wen
@ 2026-01-16 20:29 ` Harry Wentland
2026-01-16 23:54 ` Alex Hung
0 siblings, 1 reply; 16+ messages in thread
From: Harry Wentland @ 2026-01-16 20:29 UTC (permalink / raw)
To: Melissa Wen, airlied, alexander.deucher, christian.koenig, simona,
siqueira, sunpeng.li
Cc: kernel-dev, amd-gfx, dri-devel
On 2025-12-08 18:44, Melissa Wen wrote:
> We've seen some shimmer points on DCN32 when using the steamOS color
> pipeline for HDR on gaming. Looks like black values being wrongly mapped
> to red/blue/green values. Fiz that by using the exact number of
> hw_points computed in the LUT segmentation. Probably the whole logic
> that adds +1 to the latest points should be revisited.
>
> Signed-off-by: Melissa Wen <mwen@igalia.com>
I haven't had a chance to trace the hw_points logic but am
inclined to take the patch if it fixes things. My only concern
is that it reverts part of Kruno's change to increase the points
by 1 so I wonder if it could break something else subtly.
Alex Hung will follow up and get back on it.
Harry
> ---
> drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
> index 0690c346f2c5..ba20575be214 100644
> --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
> +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
> @@ -225,7 +225,7 @@ bool cm3_helper_translate_curve_to_hw_format(
>
> // DCN3+ have 257 pts in lieu of no separate slope registers
> // Prior HW had 256 base+slope pairs
> - lut_params->hw_points_num = hw_points + 1;
> + lut_params->hw_points_num = hw_points;
>
> k = 0;
> for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 2/2] drm/amd/display: extend delta clamping logic to CM3 LUT helper
2026-01-16 20:27 ` Harry Wentland
@ 2026-01-16 23:52 ` Alex Hung
0 siblings, 0 replies; 16+ messages in thread
From: Alex Hung @ 2026-01-16 23:52 UTC (permalink / raw)
To: amd-gfx
I tested this patch and it fixes kms_colorop tests. Thanks Melissa.
I will forward this to next week's promotion test.
On 1/16/26 13:27, Harry Wentland wrote:
>
>
> On 2025-12-08 18:44, Melissa Wen wrote:
>> Commit 27fc10d1095f ("drm/amd/display: Fix the delta clamping for shaper
>> LUT") fixed banding when using plane shaper LUT in DCN10 CM helper. The
>> problem is also present in DCN30 CM helper, fix banding by extending the
>> same bug delta clamping fix to CM3.
>>
>> Signed-off-by: Melissa Wen <mwen@igalia.com>
>
> Reviewed-by: Harry Wentland <harry.wentland@amd.com>
>
> Harry
>
>> ---
>> .../amd/display/dc/dcn30/dcn30_cm_common.c | 30 +++++++++++++++----
>> .../display/dc/dwb/dcn30/dcn30_cm_common.h | 2 +-
>> .../amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 9 +++---
>> .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 17 ++++++-----
>> .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 16 +++++-----
>> 5 files changed, 49 insertions(+), 25 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
>> index ba20575be214..b1c2c8da1937 100644
>> --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
>> +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
>> @@ -105,9 +105,12 @@ void cm_helper_program_gamcor_xfer_func(
>> #define NUMBER_REGIONS 32
>> #define NUMBER_SW_SEGMENTS 16
>>
>> -bool cm3_helper_translate_curve_to_hw_format(
>> - const struct dc_transfer_func *output_tf,
>> - struct pwl_params *lut_params, bool fixpoint)
>> +#define DC_LOGGER \
>> + ctx->logger
>> +
>> +bool cm3_helper_translate_curve_to_hw_format(struct dc_context *ctx,
>> + const struct dc_transfer_func *output_tf,
>> + struct pwl_params *lut_params, bool fixpoint)
>> {
>> struct curve_points3 *corner_points;
>> struct pwl_result_data *rgb_resulted;
>> @@ -248,6 +251,10 @@ bool cm3_helper_translate_curve_to_hw_format(
>> if (fixpoint == true) {
>> i = 1;
>> while (i != hw_points + 2) {
>> + uint32_t red_clamp;
>> + uint32_t green_clamp;
>> + uint32_t blue_clamp;
>> +
>> if (i >= hw_points) {
>> if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
>> rgb_plus_1->red = dc_fixpt_add(rgb->red,
>> @@ -260,9 +267,20 @@ bool cm3_helper_translate_curve_to_hw_format(
>> rgb_minus_1->delta_blue);
>> }
>>
>> - rgb->delta_red_reg = dc_fixpt_clamp_u0d10(rgb->delta_red);
>> - rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green);
>> - rgb->delta_blue_reg = dc_fixpt_clamp_u0d10(rgb->delta_blue);
>> + rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red);
>> + rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
>> + rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue);
>> +
>> + red_clamp = dc_fixpt_clamp_u0d14(rgb->delta_red);
>> + green_clamp = dc_fixpt_clamp_u0d14(rgb->delta_green);
>> + blue_clamp = dc_fixpt_clamp_u0d14(rgb->delta_blue);
>> +
>> + if (red_clamp >> 10 || green_clamp >> 10 || blue_clamp >> 10)
>> + DC_LOG_ERROR("Losing delta precision while programming shaper LUT.");
>> +
>> + rgb->delta_red_reg = red_clamp & 0x3ff;
>> + rgb->delta_green_reg = green_clamp & 0x3ff;
>> + rgb->delta_blue_reg = blue_clamp & 0x3ff;
>> rgb->red_reg = dc_fixpt_clamp_u0d14(rgb->red);
>> rgb->green_reg = dc_fixpt_clamp_u0d14(rgb->green);
>> rgb->blue_reg = dc_fixpt_clamp_u0d14(rgb->blue);
>> diff --git a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h
>> index b86347c9b038..95f9318a54ef 100644
>> --- a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h
>> +++ b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h
>> @@ -59,7 +59,7 @@ void cm_helper_program_gamcor_xfer_func(
>> const struct pwl_params *params,
>> const struct dcn3_xfer_func_reg *reg);
>>
>> -bool cm3_helper_translate_curve_to_hw_format(
>> +bool cm3_helper_translate_curve_to_hw_format(struct dc_context *ctx,
>> const struct dc_transfer_func *output_tf,
>> struct pwl_params *lut_params, bool fixpoint);
>>
>> diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
>> index 81bcadf5e57e..f2d4cd527874 100644
>> --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
>> +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
>> @@ -239,7 +239,7 @@ bool dcn30_set_blend_lut(
>> if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
>> blend_lut = &plane_state->blend_tf.pwl;
>> else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
>> - result = cm3_helper_translate_curve_to_hw_format(
>> + result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
>> &plane_state->blend_tf, &dpp_base->regamma_params, false);
>> if (!result)
>> return result;
>> @@ -334,8 +334,9 @@ bool dcn30_set_input_transfer_func(struct dc *dc,
>> if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL)
>> params = &plane_state->in_transfer_func.pwl;
>> else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS &&
>> - cm3_helper_translate_curve_to_hw_format(&plane_state->in_transfer_func,
>> - &dpp_base->degamma_params, false))
>> + cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
>> + &plane_state->in_transfer_func,
>> + &dpp_base->degamma_params, false))
>> params = &dpp_base->degamma_params;
>>
>> result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
>> @@ -406,7 +407,7 @@ bool dcn30_set_output_transfer_func(struct dc *dc,
>> params = &stream->out_transfer_func.pwl;
>> else if (pipe_ctx->stream->out_transfer_func.type ==
>> TF_TYPE_DISTRIBUTED_POINTS &&
>> - cm3_helper_translate_curve_to_hw_format(
>> + cm3_helper_translate_curve_to_hw_format(stream->ctx,
>> &stream->out_transfer_func,
>> &mpc->blender_params, false))
>> params = &mpc->blender_params;
>> diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
>> index b213a2ac827a..27abc08918bc 100644
>> --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
>> +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
>> @@ -486,8 +486,9 @@ bool dcn32_set_mcm_luts(
>> if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
>> lut_params = &plane_state->blend_tf.pwl;
>> else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
>> - result = cm3_helper_translate_curve_to_hw_format(&plane_state->blend_tf,
>> - &dpp_base->regamma_params, false);
>> + result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
>> + &plane_state->blend_tf,
>> + &dpp_base->regamma_params, false);
>> if (!result)
>> return result;
>>
>> @@ -502,8 +503,9 @@ bool dcn32_set_mcm_luts(
>> else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
>> // TODO: dpp_base replace
>> ASSERT(false);
>> - cm3_helper_translate_curve_to_hw_format(&plane_state->in_shaper_func,
>> - &dpp_base->shaper_params, true);
>> + cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
>> + &plane_state->in_shaper_func,
>> + &dpp_base->shaper_params, true);
>> lut_params = &dpp_base->shaper_params;
>> }
>>
>> @@ -543,8 +545,9 @@ bool dcn32_set_input_transfer_func(struct dc *dc,
>> if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL)
>> params = &plane_state->in_transfer_func.pwl;
>> else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS &&
>> - cm3_helper_translate_curve_to_hw_format(&plane_state->in_transfer_func,
>> - &dpp_base->degamma_params, false))
>> + cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
>> + &plane_state->in_transfer_func,
>> + &dpp_base->degamma_params, false))
>> params = &dpp_base->degamma_params;
>>
>> dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
>> @@ -575,7 +578,7 @@ bool dcn32_set_output_transfer_func(struct dc *dc,
>> params = &stream->out_transfer_func.pwl;
>> else if (pipe_ctx->stream->out_transfer_func.type ==
>> TF_TYPE_DISTRIBUTED_POINTS &&
>> - cm3_helper_translate_curve_to_hw_format(
>> + cm3_helper_translate_curve_to_hw_format(stream->ctx,
>> &stream->out_transfer_func,
>> &mpc->blender_params, false))
>> params = &mpc->blender_params;
>> diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
>> index 2fbc22afb89c..5eda7648d0d2 100644
>> --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
>> +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
>> @@ -430,7 +430,7 @@ void dcn401_populate_mcm_luts(struct dc *dc,
>> if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL)
>> m_lut_params.pwl = &mcm_luts.lut1d_func->pwl;
>> else if (mcm_luts.lut1d_func->type == TF_TYPE_DISTRIBUTED_POINTS) {
>> - rval = cm3_helper_translate_curve_to_hw_format(
>> + rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx,
>> mcm_luts.lut1d_func,
>> &dpp_base->regamma_params, false);
>> m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
>> @@ -450,7 +450,7 @@ void dcn401_populate_mcm_luts(struct dc *dc,
>> m_lut_params.pwl = &mcm_luts.shaper->pwl;
>> else if (mcm_luts.shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
>> ASSERT(false);
>> - rval = cm3_helper_translate_curve_to_hw_format(
>> + rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx,
>> mcm_luts.shaper,
>> &dpp_base->regamma_params, true);
>> m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
>> @@ -627,8 +627,9 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
>> if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
>> lut_params = &plane_state->blend_tf.pwl;
>> else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
>> - rval = cm3_helper_translate_curve_to_hw_format(&plane_state->blend_tf,
>> - &dpp_base->regamma_params, false);
>> + rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
>> + &plane_state->blend_tf,
>> + &dpp_base->regamma_params, false);
>> lut_params = rval ? &dpp_base->regamma_params : NULL;
>> }
>> result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id);
>> @@ -639,8 +640,9 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
>> lut_params = &plane_state->in_shaper_func.pwl;
>> else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
>> // TODO: dpp_base replace
>> - rval = cm3_helper_translate_curve_to_hw_format(&plane_state->in_shaper_func,
>> - &dpp_base->shaper_params, true);
>> + rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
>> + &plane_state->in_shaper_func,
>> + &dpp_base->shaper_params, true);
>> lut_params = rval ? &dpp_base->shaper_params : NULL;
>> }
>> result &= mpc->funcs->program_shaper(mpc, lut_params, mpcc_id);
>> @@ -674,7 +676,7 @@ bool dcn401_set_output_transfer_func(struct dc *dc,
>> params = &stream->out_transfer_func.pwl;
>> else if (pipe_ctx->stream->out_transfer_func.type ==
>> TF_TYPE_DISTRIBUTED_POINTS &&
>> - cm3_helper_translate_curve_to_hw_format(
>> + cm3_helper_translate_curve_to_hw_format(stream->ctx,
>> &stream->out_transfer_func,
>> &mpc->blender_params, false))
>> params = &mpc->blender_params;
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 1/2] drm/amd/display: fix wrong color value mapping on DCN32 shaper LUT
2026-01-16 20:29 ` Harry Wentland
@ 2026-01-16 23:54 ` Alex Hung
0 siblings, 0 replies; 16+ messages in thread
From: Alex Hung @ 2026-01-16 23:54 UTC (permalink / raw)
To: Harry Wentland, Melissa Wen, airlied, alexander.deucher,
christian.koenig, simona, siqueira, sunpeng.li
Cc: kernel-dev, amd-gfx, dri-devel
On 1/16/26 13:29, Harry Wentland wrote:
>
>
> On 2025-12-08 18:44, Melissa Wen wrote:
>> We've seen some shimmer points on DCN32 when using the steamOS color
>> pipeline for HDR on gaming. Looks like black values being wrongly mapped
>> to red/blue/green values. Fiz that by using the exact number of
>> hw_points computed in the LUT segmentation. Probably the whole logic
>> that adds +1 to the latest points should be revisited.
>>
>> Signed-off-by: Melissa Wen <mwen@igalia.com>
>
> I haven't had a chance to trace the hw_points logic but am
> inclined to take the patch if it fixes things. My only concern
> is that it reverts part of Kruno's change to increase the points
> by 1 so I wonder if it could break something else subtly.
>
> Alex Hung will follow up and get back on it.
I will check with Kruno and forward this to next week's promotion test.
>
> Harry
>
>> ---
>> drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
>> index 0690c346f2c5..ba20575be214 100644
>> --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
>> +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
>> @@ -225,7 +225,7 @@ bool cm3_helper_translate_curve_to_hw_format(
>>
>> // DCN3+ have 257 pts in lieu of no separate slope registers
>> // Prior HW had 256 base+slope pairs
>> - lut_params->hw_points_num = hw_points + 1;
>> + lut_params->hw_points_num = hw_points;
>>
>> k = 0;
>> for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
>
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-01-16 23:54 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-08 23:44 [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT Melissa Wen
2025-12-08 23:44 ` [RFC PATCH 1/2] drm/amd/display: fix wrong color value mapping on DCN32 " Melissa Wen
2026-01-16 20:29 ` Harry Wentland
2026-01-16 23:54 ` Alex Hung
2025-12-08 23:44 ` [RFC PATCH 2/2] drm/amd/display: extend delta clamping logic to CM3 LUT helper Melissa Wen
2026-01-16 20:27 ` Harry Wentland
2026-01-16 23:52 ` Alex Hung
2025-12-09 1:34 ` [RFC PATCH 0/2] Fixes on CM3 helper for plane shaper LUT Matthew Schwartz
2025-12-09 14:31 ` Melissa Wen
2025-12-09 14:44 ` Melissa Wen
2025-12-09 15:12 ` Harry Wentland
2025-12-09 15:18 ` Melissa Wen
2025-12-09 18:19 ` Matthew Schwartz
2025-12-10 20:46 ` Melissa Wen
2025-12-10 20:56 ` Matthew Schwartz
2026-01-16 17:08 ` Melissa Wen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox