Commit 6bd20f0f authored by Joshua Ashton's avatar Joshua Ashton Committed by Alex Deucher

drm/amd/display: add CRTC gamma TF support

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: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarJoshua Ashton <joshua@froggi.es>
Co-developed-by: default avatarMelissa Wen <mwen@igalia.com>
Signed-off-by: default avatarMelissa Wen <mwen@igalia.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 8b6b3f66
......@@ -9860,6 +9860,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)
......
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment