Re: [PATCH 2/4] drm/amd/display: use a separate helper to translate degamma curves
On 16/04/2026 16:22, Kovac, Krunoslav wrote:
Thanks Melissa for following up.
I like the changes themselves, just some clarifications.
We do have a LUT with predefined HW curve, but it has some
limitations: it cannot be used with subsampled 4:2:0/4:2:2 formats and
it affects the linearity of color space in which HW scaler operates.
In your case, we use the LUT after tone mapping in 3D LUT; that LUT
doesn't have predefined curve. So it's not uncommon that we need to
program our own degamma.
Hi Kruno,
Right, I reviewed this part in the cover letter after checking my notes
that there is a hw curve for degamma, but not for shaper, blend and
post-blend re-gamma, right? I forgot to correct this info here.
I wasn't aware about the subsampled limitation.
The motivation for the new segment distribution is best explained with
an 8-bit sRGB case. Input has 256 possible values and HW LUTs have 256
points. Ideally in this case we'd use the LUT as basically plain
indexing with no interpolation. The new distribution accomplishes
this, it aligns 256 HW points with 256 possible inputs. Due to float
representations of input, it's not aligned perfectly, but LERP-ing
between two HW entries where input is always within small epsilon from
one of entries doesn't materially change things.
I'll rewrite commit messages to include this explanation too.
Thanks for sharing these details.
Melissa
On 4/14/2026 17:55, Melissa Wen wrote:
In newer DCN families, there is no hw predefined curves. So, when
setting predefined TFs to gamm_corr, shaper, blend and regamma, the
driver resorts to the color modules and program those predefined curves
using LUTs. The driver is using the same LUT segmentation when
translating EOTF and inverse EOTF to hw points by using the same color
management helper to translate curve to hw points, however, LUT
representing EOTF may not follow the same region/segment distributions
of inverse EOTF. This is causing banding on blend when PQ predefined
curve is set. Use different helpers when linearizing and delinearizing.
This is the first step to fix banding but already mitigates the issue by
increase the number of points per segment from 8 to 16.
Signed-off-by: Melissa Wen
---
.../gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 10 --
1 file changed, 4 insertions(+), 6 deletions(-)
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 b45ceb570a5c..17d54aadb5e1 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
@@ -493,9 +493,8 @@ 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->ctx,
- &plane_state->blend_tf,
- &dpp_base->regamma_params, false);
+ result =
cm3_helper_translate_curve_to_degamma_hw_format(&plane_state->blend_tf,
+ &dpp_base->regamma_params);
if (!result)
return result;
@@ -551,9 +550,8 @@ 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->ctx,
- &plane_state->in_transfer_func,
- &dpp_base->degamma_params, false))
+
cm3_helper_translate_curve_to_degamma_hw_format(&plane_state->in_transfer_func,
+ &dpp_base->degamma_params))
params = &dpp_base->degamma_params;
dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
Re: [PATCH 2/4] drm/amd/display: use a separate helper to translate degamma curves
Thanks Melissa for following up.
I like the changes themselves, just some clarifications.
We do have a LUT with predefined HW curve, but it has some limitations: it
cannot be used with subsampled 4:2:0/4:2:2 formats and it affects the linearity
of color space in which HW scaler operates. In your case, we use the LUT after
tone mapping in 3D LUT; that LUT doesn't have predefined curve. So it's not
uncommon that we need to program our own degamma.
The motivation for the new segment distribution is best explained with an 8-bit
sRGB case. Input has 256 possible values and HW LUTs have 256 points. Ideally
in this case we'd use the LUT as basically plain indexing with no
interpolation. The new distribution accomplishes this, it aligns 256 HW points
with 256 possible inputs. Due to float representations of input, it's not
aligned perfectly, but LERP-ing between two HW entries where input is always
within small epsilon from one of entries doesn't materially change things.
On 4/14/2026 17:55, Melissa Wen wrote:
In newer DCN families, there is no hw predefined curves. So, when
setting predefined TFs to gamm_corr, shaper, blend and regamma, the
driver resorts to the color modules and program those predefined curves
using LUTs. The driver is using the same LUT segmentation when
translating EOTF and inverse EOTF to hw points by using the same color
management helper to translate curve to hw points, however, LUT
representing EOTF may not follow the same region/segment distributions
of inverse EOTF. This is causing banding on blend when PQ predefined
curve is set. Use different helpers when linearizing and delinearizing.
This is the first step to fix banding but already mitigates the issue by
increase the number of points per segment from 8 to 16.
Signed-off-by: Melissa Wen
---
.../gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c| 10 --
1 file changed, 4 insertions(+), 6 deletions(-)
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 b45ceb570a5c..17d54aadb5e1 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
@@ -493,9 +493,8 @@ 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->ctx,
-
&plane_state->blend_tf,
-
&dpp_base->regamma_params, false);
+ result =
cm3_helper_translate_curve_to_degamma_hw_format(&plane_state->blend_tf,
+
&dpp_base->regamma_params);
if (!result)
return result;
@@ -551,9 +550,8 @@ 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->ctx,
-
&plane_state->in_transfer_func,
-
&dpp_base->degamma_params, false))
+
cm3_helper_translate_curve_to_degamma_hw_format(&plane_state->in_transfer_func,
+
&dpp_base->degamma_params))
params = &dpp_base->degamma_params;
dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
[PATCH 2/4] drm/amd/display: use a separate helper to translate degamma curves
In newer DCN families, there is no hw predefined curves. So, when
setting predefined TFs to gamm_corr, shaper, blend and regamma, the
driver resorts to the color modules and program those predefined curves
using LUTs. The driver is using the same LUT segmentation when
translating EOTF and inverse EOTF to hw points by using the same color
management helper to translate curve to hw points, however, LUT
representing EOTF may not follow the same region/segment distributions
of inverse EOTF. This is causing banding on blend when PQ predefined
curve is set. Use different helpers when linearizing and delinearizing.
This is the first step to fix banding but already mitigates the issue by
increase the number of points per segment from 8 to 16.
Signed-off-by: Melissa Wen
---
.../gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c| 10 --
1 file changed, 4 insertions(+), 6 deletions(-)
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 b45ceb570a5c..17d54aadb5e1 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
@@ -493,9 +493,8 @@ 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->ctx,
-
&plane_state->blend_tf,
-
&dpp_base->regamma_params, false);
+ result =
cm3_helper_translate_curve_to_degamma_hw_format(&plane_state->blend_tf,
+
&dpp_base->regamma_params);
if (!result)
return result;
@@ -551,9 +550,8 @@ 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->ctx,
-
&plane_state->in_transfer_func,
-
&dpp_base->degamma_params, false))
+
cm3_helper_translate_curve_to_degamma_hw_format(&plane_state->in_transfer_func,
+
&dpp_base->degamma_params))
params = &dpp_base->degamma_params;
dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
--
2.53.0
