From: Joshua Ashton <jos...@froggi.es>

Add predefined transfer function programming. There is no post-blending
out gamma ROM for hardcoded curves, but we can use AMD color modules to
program LUT parameters from pre-defined coefficients and an empty
regamma LUT (or bump up LUT parameters with pre-defined TF values).

v2:
- update crtc color mgmt if regamma TF differs between states (Joshua)
- map inverse EOTF to DC transfer function (Melissa)

v3:
- update AMDGPU TF list

v4:
- update comment regarding regamma behavior

Reviewed-by: Harry Wentland <harry.wentl...@amd.com>
Signed-off-by: Joshua Ashton <jos...@froggi.es>
Co-developed-by: Melissa Wen <m...@igalia.com>
Signed-off-by: Melissa Wen <m...@igalia.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  1 +
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 77 +++++++++++++++----
 2 files changed, 61 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 56053de2aaea..8bf7866ee1af 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -9564,6 +9564,7 @@ static int dm_update_crtc_state(struct 
amdgpu_display_manager *dm,
         * when a modeset is needed, to ensure it gets reprogrammed.
         */
        if (dm_new_crtc_state->base.color_mgmt_changed ||
+           dm_old_crtc_state->regamma_tf != dm_new_crtc_state->regamma_tf ||
            drm_atomic_crtc_needs_modeset(new_crtc_state)) {
                ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state);
                if (ret)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index dec734f03832..9b930e3eb79d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -490,16 +490,18 @@ static int __set_output_tf(struct dc_transfer_func *func,
        struct calculate_buffer cal_buffer = {0};
        bool res;
 
-       ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES);
-
        cal_buffer.buffer_index = -1;
 
-       gamma = dc_create_gamma();
-       if (!gamma)
-               return -ENOMEM;
+       if (lut_size) {
+               ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES);
 
-       gamma->num_entries = lut_size;
-       __drm_lut_to_dc_gamma(lut, gamma, false);
+               gamma = dc_create_gamma();
+               if (!gamma)
+                       return -ENOMEM;
+
+               gamma->num_entries = lut_size;
+               __drm_lut_to_dc_gamma(lut, gamma, false);
+       }
 
        if (func->tf == TRANSFER_FUNCTION_LINEAR) {
                /*
@@ -507,41 +509,49 @@ static int __set_output_tf(struct dc_transfer_func *func,
                 * on top of a linear input. But degamma params can be used
                 * instead to simulate this.
                 */
-               gamma->type = GAMMA_CUSTOM;
+               if (gamma)
+                       gamma->type = GAMMA_CUSTOM;
                res = mod_color_calculate_degamma_params(NULL, func,
-                                                       gamma, true);
+                                                        gamma, gamma != NULL);
        } else {
                /*
                 * Assume sRGB. The actual mapping will depend on whether the
                 * input was legacy or not.
                 */
-               gamma->type = GAMMA_CS_TFM_1D;
-               res = mod_color_calculate_regamma_params(func, gamma, false,
+               if (gamma)
+                       gamma->type = GAMMA_CS_TFM_1D;
+               res = mod_color_calculate_regamma_params(func, gamma, gamma != 
NULL,
                                                         has_rom, NULL, 
&cal_buffer);
        }
 
-       dc_gamma_release(&gamma);
+       if (gamma)
+               dc_gamma_release(&gamma);
 
        return res ? 0 : -ENOMEM;
 }
 
 static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream,
                                        const struct drm_color_lut *regamma_lut,
-                                       uint32_t regamma_size, bool has_rom)
+                                       uint32_t regamma_size, bool has_rom,
+                                       enum dc_transfer_func_predefined tf)
 {
        struct dc_transfer_func *out_tf = stream->out_transfer_func;
        int ret = 0;
 
-       if (regamma_size) {
+       if (regamma_size || tf != TRANSFER_FUNCTION_LINEAR) {
                /*
                 * CRTC RGM goes into RGM LUT.
                 *
                 * Note: there is no implicit sRGB regamma here. We are using
                 * degamma calculation from color module to calculate the curve
-                * from a linear base.
+                * from a linear base if gamma TF is not set. However, if gamma
+                * TF (!= Linear) and LUT are set at the same time, we will use
+                * regamma calculation, and the color module will combine the
+                * pre-defined TF and the custom LUT values into the LUT that's
+                * actually programmed.
                 */
                out_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
-               out_tf->tf = TRANSFER_FUNCTION_LINEAR;
+               out_tf->tf = tf;
 
                ret = __set_output_tf(out_tf, regamma_lut, regamma_size, 
has_rom);
        } else {
@@ -587,6 +597,36 @@ static int __set_input_tf(struct dc_transfer_func *func,
        return res ? 0 : -ENOMEM;
 }
 
+static enum dc_transfer_func_predefined
+amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
+{
+       switch (tf)
+       {
+       default:
+       case AMDGPU_TRANSFER_FUNCTION_DEFAULT:
+       case AMDGPU_TRANSFER_FUNCTION_IDENTITY:
+               return TRANSFER_FUNCTION_LINEAR;
+       case AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF:
+       case AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF:
+               return TRANSFER_FUNCTION_SRGB;
+       case AMDGPU_TRANSFER_FUNCTION_BT709_OETF:
+       case AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF:
+               return TRANSFER_FUNCTION_BT709;
+       case AMDGPU_TRANSFER_FUNCTION_PQ_EOTF:
+       case AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF:
+               return TRANSFER_FUNCTION_PQ;
+       case AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF:
+       case AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF:
+               return TRANSFER_FUNCTION_GAMMA22;
+       case AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF:
+       case AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF:
+               return TRANSFER_FUNCTION_GAMMA24;
+       case AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF:
+       case AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF:
+               return TRANSFER_FUNCTION_GAMMA26;
+       }
+}
+
 /**
  * amdgpu_dm_verify_lut_sizes - verifies if DRM luts match the hw supported 
sizes
  * @crtc_state: the DRM CRTC state
@@ -654,9 +694,12 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state 
*crtc)
        const struct drm_color_lut *degamma_lut, *regamma_lut;
        uint32_t degamma_size, regamma_size;
        bool has_regamma, has_degamma;
+       enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_LINEAR;
        bool is_legacy;
        int r;
 
+       tf = amdgpu_tf_to_dc_tf(crtc->regamma_tf);
+
        r = amdgpu_dm_verify_lut_sizes(&crtc->base);
        if (r)
                return r;
@@ -706,7 +749,7 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state 
*crtc)
        } else {
                regamma_size = has_regamma ? regamma_size : 0;
                r = amdgpu_dm_set_atomic_regamma(stream, regamma_lut,
-                                                regamma_size, has_rom);
+                                                regamma_size, has_rom, tf);
                if (r)
                        return r;
        }
-- 
2.40.1

Reply via email to