drm/amd/display: Implement color management
Implement color management functionalities within amdgpu_dm_color, and expose functions within amdgpu_dm.h. Signed-off-by: Leo (Sunpeng) Li <sunpeng.li@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
ec7e6bb814
commit
303afd2dbf
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o
|
AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o amdgpu_dm_color.o
|
||||||
|
|
||||||
ifneq ($(CONFIG_DRM_AMD_DC),)
|
ifneq ($(CONFIG_DRM_AMD_DC),)
|
||||||
AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o
|
AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o
|
||||||
|
|
|
@ -268,6 +268,11 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc);
|
||||||
#define amdgpu_dm_crtc_handle_crc_irq(x)
|
#define amdgpu_dm_crtc_handle_crc_irq(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state,
|
||||||
|
struct dc_plane_state *dc_plane_state);
|
||||||
|
void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc);
|
||||||
|
int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc);
|
||||||
|
|
||||||
extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs;
|
extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs;
|
||||||
|
|
||||||
#endif /* __AMDGPU_DM_H__ */
|
#endif /* __AMDGPU_DM_H__ */
|
||||||
|
|
218
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
Normal file
218
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Advanced Micro Devices, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* Authors: AMD
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "amdgpu_mode.h"
|
||||||
|
#include "amdgpu_dm.h"
|
||||||
|
#include "modules/color/color_gamma.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_LUT_ENTRIES 256
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true if the given lut is a linear mapping of values, i.e. it acts
|
||||||
|
* like a bypass LUT.
|
||||||
|
*
|
||||||
|
* It is considered linear if the lut represents:
|
||||||
|
* f(a) = (0xFF00/MAX_LUT_ENTRIES-1)a; for integer a in [0, MAX_LUT_ENTRIES)
|
||||||
|
*/
|
||||||
|
static bool __is_lut_linear(struct drm_color_lut *lut)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint32_t max_os = 0xFF00;
|
||||||
|
uint32_t expected;
|
||||||
|
int delta;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_LUT_ENTRIES; i++) {
|
||||||
|
/* All color values should equal */
|
||||||
|
if ((lut[i].red != lut[i].green) || (lut[i].green != lut[i].blue))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
expected = i * max_os / (MAX_LUT_ENTRIES-1);
|
||||||
|
|
||||||
|
/* Allow a +/-1 error. */
|
||||||
|
delta = lut[i].red - expected;
|
||||||
|
if (delta < -1 || 1 < delta)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* amdgpu_dm_set_regamma_lut: Set regamma lut for the given CRTC.
|
||||||
|
* @crtc: amdgpu_dm crtc state
|
||||||
|
*
|
||||||
|
* Update the underlying dc_stream_state's output transfer function (OTF) in
|
||||||
|
* preparation for hardware commit. If no lut is specified by user, we default
|
||||||
|
* to SRGB.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success, -ENOMEM if memory cannot be allocated to calculate the OTF.
|
||||||
|
*/
|
||||||
|
int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc)
|
||||||
|
{
|
||||||
|
struct drm_property_blob *blob = crtc->base.gamma_lut;
|
||||||
|
struct dc_stream_state *stream = crtc->stream;
|
||||||
|
struct drm_color_lut *lut;
|
||||||
|
struct dc_gamma *gamma;
|
||||||
|
enum dc_transfer_func_type old_type = stream->out_transfer_func->type;
|
||||||
|
|
||||||
|
uint32_t r, g, b;
|
||||||
|
int i;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
if (!blob) {
|
||||||
|
/* By default, use the SRGB predefined curve.*/
|
||||||
|
stream->out_transfer_func->type = TF_TYPE_PREDEFINED;
|
||||||
|
stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lut = (struct drm_color_lut *)blob->data;
|
||||||
|
|
||||||
|
if (__is_lut_linear(lut)) {
|
||||||
|
/* Set to bypass if lut is set to linear */
|
||||||
|
stream->out_transfer_func->type = TF_TYPE_BYPASS;
|
||||||
|
stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gamma = dc_create_gamma();
|
||||||
|
if (!gamma)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
gamma->num_entries = MAX_LUT_ENTRIES;
|
||||||
|
gamma->type = GAMMA_RGB_256;
|
||||||
|
|
||||||
|
/* Truncate, and store in dc_gamma for output tf calculation */
|
||||||
|
for (i = 0; i < gamma->num_entries; i++) {
|
||||||
|
r = drm_color_lut_extract(lut[i].red, 16);
|
||||||
|
g = drm_color_lut_extract(lut[i].green, 16);
|
||||||
|
b = drm_color_lut_extract(lut[i].blue, 16);
|
||||||
|
|
||||||
|
gamma->entries.red[i] = dal_fixed31_32_from_int(r);
|
||||||
|
gamma->entries.green[i] = dal_fixed31_32_from_int(g);
|
||||||
|
gamma->entries.blue[i] = dal_fixed31_32_from_int(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call color module to translate into something DC understands. Namely
|
||||||
|
* a transfer function.
|
||||||
|
*/
|
||||||
|
stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
|
||||||
|
ret = mod_color_calculate_regamma_params(stream->out_transfer_func,
|
||||||
|
gamma, true);
|
||||||
|
dc_gamma_release(&gamma);
|
||||||
|
if (!ret) {
|
||||||
|
stream->out_transfer_func->type = old_type;
|
||||||
|
DRM_ERROR("Out of memory when calculating regamma params\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* amdgpu_dm_set_ctm: Set the color transform matrix for the given CRTC.
|
||||||
|
* @crtc: amdgpu_dm crtc state
|
||||||
|
*
|
||||||
|
* Update the underlying dc_stream_state's gamut remap matrix in preparation
|
||||||
|
* for hardware commit. If no matrix is specified by user, gamut remap will be
|
||||||
|
* disabled.
|
||||||
|
*/
|
||||||
|
void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct drm_property_blob *blob = crtc->base.ctm;
|
||||||
|
struct dc_stream_state *stream = crtc->stream;
|
||||||
|
struct drm_color_ctm *ctm;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!blob) {
|
||||||
|
stream->gamut_remap_matrix.enable_remap = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->gamut_remap_matrix.enable_remap = true;
|
||||||
|
ctm = (struct drm_color_ctm *)blob->data;
|
||||||
|
/*
|
||||||
|
* DRM gives a 3x3 matrix, but DC wants 3x4. Assuming we're operating
|
||||||
|
* with homogeneous coordinates, augment the matrix with 0's.
|
||||||
|
*
|
||||||
|
* The format provided is S31.32, which is the same as our fixed31_32.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < 12; i++) {
|
||||||
|
/* Skip 4th element */
|
||||||
|
if (i % 4 == 3) {
|
||||||
|
stream->gamut_remap_matrix.matrix[i] = dal_fixed31_32_zero;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* csc[i] = ctm[i - floor(i/4)] */
|
||||||
|
stream->gamut_remap_matrix.matrix[i].value = ctm->matrix[i - (i/4)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* amdgpu_dm_set_degamma_lut: Set degamma lut for the given CRTC.
|
||||||
|
* @crtc: amdgpu_dm crtc state
|
||||||
|
*
|
||||||
|
* Update the underlying dc_stream_state's input transfer function (ITF) in
|
||||||
|
* preparation for hardware commit. If no lut is specified by user, we default
|
||||||
|
* to SRGB degamma.
|
||||||
|
*
|
||||||
|
* Currently, we only support degamma bypass, or preprogrammed SRGB degamma.
|
||||||
|
* Programmable degamma is not supported, and an attempt to do so will return
|
||||||
|
* -EINVAL.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success, -EINVAL if custom degamma curve is given.
|
||||||
|
*/
|
||||||
|
int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state,
|
||||||
|
struct dc_plane_state *dc_plane_state)
|
||||||
|
{
|
||||||
|
struct drm_property_blob *blob = crtc_state->degamma_lut;
|
||||||
|
struct drm_color_lut *lut;
|
||||||
|
|
||||||
|
if (!blob) {
|
||||||
|
/* Default to SRGB */
|
||||||
|
dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED;
|
||||||
|
dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lut = (struct drm_color_lut *)blob->data;
|
||||||
|
if (__is_lut_linear(lut)) {
|
||||||
|
dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
|
||||||
|
dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, assume SRGB, since programmable degamma is not
|
||||||
|
* supported.
|
||||||
|
*/
|
||||||
|
dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED;
|
||||||
|
dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue