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, ...@@ -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. * when a modeset is needed, to ensure it gets reprogrammed.
*/ */
if (dm_new_crtc_state->base.color_mgmt_changed || 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)) { drm_atomic_crtc_needs_modeset(new_crtc_state)) {
ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state); ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state);
if (ret) if (ret)
......
...@@ -490,16 +490,18 @@ static int __set_output_tf(struct dc_transfer_func *func, ...@@ -490,16 +490,18 @@ static int __set_output_tf(struct dc_transfer_func *func,
struct calculate_buffer cal_buffer = {0}; struct calculate_buffer cal_buffer = {0};
bool res; bool res;
ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES);
cal_buffer.buffer_index = -1; cal_buffer.buffer_index = -1;
if (lut_size) {
ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES);
gamma = dc_create_gamma(); gamma = dc_create_gamma();
if (!gamma) if (!gamma)
return -ENOMEM; return -ENOMEM;
gamma->num_entries = lut_size; gamma->num_entries = lut_size;
__drm_lut_to_dc_gamma(lut, gamma, false); __drm_lut_to_dc_gamma(lut, gamma, false);
}
if (func->tf == TRANSFER_FUNCTION_LINEAR) { if (func->tf == TRANSFER_FUNCTION_LINEAR) {
/* /*
...@@ -507,19 +509,22 @@ static int __set_output_tf(struct dc_transfer_func *func, ...@@ -507,19 +509,22 @@ static int __set_output_tf(struct dc_transfer_func *func,
* on top of a linear input. But degamma params can be used * on top of a linear input. But degamma params can be used
* instead to simulate this. * instead to simulate this.
*/ */
if (gamma)
gamma->type = GAMMA_CUSTOM; gamma->type = GAMMA_CUSTOM;
res = mod_color_calculate_degamma_params(NULL, func, res = mod_color_calculate_degamma_params(NULL, func,
gamma, true); gamma, gamma != NULL);
} else { } else {
/* /*
* Assume sRGB. The actual mapping will depend on whether the * Assume sRGB. The actual mapping will depend on whether the
* input was legacy or not. * input was legacy or not.
*/ */
if (gamma)
gamma->type = GAMMA_CS_TFM_1D; gamma->type = GAMMA_CS_TFM_1D;
res = mod_color_calculate_regamma_params(func, gamma, false, res = mod_color_calculate_regamma_params(func, gamma, gamma != NULL,
has_rom, NULL, &cal_buffer); has_rom, NULL, &cal_buffer);
} }
if (gamma)
dc_gamma_release(&gamma); dc_gamma_release(&gamma);
return res ? 0 : -ENOMEM; return res ? 0 : -ENOMEM;
...@@ -527,21 +532,26 @@ static int __set_output_tf(struct dc_transfer_func *func, ...@@ -527,21 +532,26 @@ static int __set_output_tf(struct dc_transfer_func *func,
static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream,
const struct drm_color_lut *regamma_lut, 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; struct dc_transfer_func *out_tf = stream->out_transfer_func;
int ret = 0; int ret = 0;
if (regamma_size) { if (regamma_size || tf != TRANSFER_FUNCTION_LINEAR) {
/* /*
* CRTC RGM goes into RGM LUT. * CRTC RGM goes into RGM LUT.
* *
* Note: there is no implicit sRGB regamma here. We are using * Note: there is no implicit sRGB regamma here. We are using
* degamma calculation from color module to calculate the curve * 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->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); ret = __set_output_tf(out_tf, regamma_lut, regamma_size, has_rom);
} else { } else {
...@@ -587,6 +597,36 @@ static int __set_input_tf(struct dc_transfer_func *func, ...@@ -587,6 +597,36 @@ static int __set_input_tf(struct dc_transfer_func *func,
return res ? 0 : -ENOMEM; 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 * amdgpu_dm_verify_lut_sizes - verifies if DRM luts match the hw supported sizes
* @crtc_state: the DRM CRTC state * @crtc_state: the DRM CRTC state
...@@ -654,9 +694,12 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) ...@@ -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; const struct drm_color_lut *degamma_lut, *regamma_lut;
uint32_t degamma_size, regamma_size; uint32_t degamma_size, regamma_size;
bool has_regamma, has_degamma; bool has_regamma, has_degamma;
enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_LINEAR;
bool is_legacy; bool is_legacy;
int r; int r;
tf = amdgpu_tf_to_dc_tf(crtc->regamma_tf);
r = amdgpu_dm_verify_lut_sizes(&crtc->base); r = amdgpu_dm_verify_lut_sizes(&crtc->base);
if (r) if (r)
return r; return r;
...@@ -706,7 +749,7 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) ...@@ -706,7 +749,7 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc)
} else { } else {
regamma_size = has_regamma ? regamma_size : 0; regamma_size = has_regamma ? regamma_size : 0;
r = amdgpu_dm_set_atomic_regamma(stream, regamma_lut, r = amdgpu_dm_set_atomic_regamma(stream, regamma_lut,
regamma_size, has_rom); regamma_size, has_rom, tf);
if (r) if (r)
return 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