Commit fed38757 authored by Andres Calderon Jaramillo's avatar Andres Calderon Jaramillo Committed by Ville Syrjälä

drm/i915/display: Prevent double YUV range correction on HDR planes

Prevent the ICL HDR plane pipeline from performing YUV color range
correction twice when the input is in limited range. This is done by
removing the limited-range code from icl_program_input_csc().

Before this patch the following could happen: user space gives us a YUV
buffer in limited range; per the pipeline in [1], the plane would first
go through a "YUV Range correct" stage that expands the range; the plane
would then go through the "Input CSC" stage which would also expand the
range because icl_program_input_csc() would use a matrix and an offset
that assume limited-range input; this would ultimately cause dark and
light colors to appear darker and lighter than they should respectively.

This is an issue because if a buffer switches between being scanned out
and being composited with the GPU, the user will see a color difference.
If this switching happens quickly and frequently, the user will perceive
this as a flickering.

[1] https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-icllp-vol12-displayengine_0.pdf#page=281

Cc: stable@vger.kernel.org
Signed-off-by: default avatarAndres Calderon Jaramillo <andrescj@chromium.org>
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20201215224219.3896256-1-andrescj@google.com
parent 2aa0f4fa
...@@ -3584,6 +3584,8 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, ...@@ -3584,6 +3584,8 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state,
plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
} else if (fb->format->is_yuv) { } else if (fb->format->is_yuv) {
plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE; plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE;
if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
} }
return plane_color_ctl; return plane_color_ctl;
......
...@@ -649,13 +649,19 @@ skl_program_scaler(struct intel_plane *plane, ...@@ -649,13 +649,19 @@ skl_program_scaler(struct intel_plane *plane,
/* Preoffset values for YUV to RGB Conversion */ /* Preoffset values for YUV to RGB Conversion */
#define PREOFF_YUV_TO_RGB_HI 0x1800 #define PREOFF_YUV_TO_RGB_HI 0x1800
#define PREOFF_YUV_TO_RGB_ME 0x1F00 #define PREOFF_YUV_TO_RGB_ME 0x0000
#define PREOFF_YUV_TO_RGB_LO 0x1800 #define PREOFF_YUV_TO_RGB_LO 0x1800
#define ROFF(x) (((x) & 0xffff) << 16) #define ROFF(x) (((x) & 0xffff) << 16)
#define GOFF(x) (((x) & 0xffff) << 0) #define GOFF(x) (((x) & 0xffff) << 0)
#define BOFF(x) (((x) & 0xffff) << 16) #define BOFF(x) (((x) & 0xffff) << 16)
/*
* Programs the input color space conversion stage for ICL HDR planes.
* Note that it is assumed that this stage always happens after YUV
* range correction. Thus, the input to this stage is assumed to be
* in full-range YCbCr.
*/
static void static void
icl_program_input_csc(struct intel_plane *plane, icl_program_input_csc(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
...@@ -703,52 +709,7 @@ icl_program_input_csc(struct intel_plane *plane, ...@@ -703,52 +709,7 @@ icl_program_input_csc(struct intel_plane *plane,
0x0, 0x7800, 0x7F10, 0x0, 0x7800, 0x7F10,
}, },
}; };
const u16 *csc = input_csc_matrix[plane_state->hw.color_encoding];
/* Matrix for Limited Range to Full Range Conversion */
static const u16 input_csc_matrix_lr[][9] = {
/*
* BT.601 Limted range YCbCr -> full range RGB
* The matrix required is :
* [1.164384, 0.000, 1.596027,
* 1.164384, -0.39175, -0.812813,
* 1.164384, 2.017232, 0.0000]
*/
[DRM_COLOR_YCBCR_BT601] = {
0x7CC8, 0x7950, 0x0,
0x8D00, 0x7950, 0x9C88,
0x0, 0x7950, 0x6810,
},
/*
* BT.709 Limited range YCbCr -> full range RGB
* The matrix required is :
* [1.164384, 0.000, 1.792741,
* 1.164384, -0.213249, -0.532909,
* 1.164384, 2.112402, 0.0000]
*/
[DRM_COLOR_YCBCR_BT709] = {
0x7E58, 0x7950, 0x0,
0x8888, 0x7950, 0xADA8,
0x0, 0x7950, 0x6870,
},
/*
* BT.2020 Limited range YCbCr -> full range RGB
* The matrix required is :
* [1.164, 0.000, 1.678,
* 1.164, -0.1873, -0.6504,
* 1.164, 2.1417, 0.0000]
*/
[DRM_COLOR_YCBCR_BT2020] = {
0x7D70, 0x7950, 0x0,
0x8A68, 0x7950, 0xAC00,
0x0, 0x7950, 0x6890,
},
};
const u16 *csc;
if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
csc = input_csc_matrix[plane_state->hw.color_encoding];
else
csc = input_csc_matrix_lr[plane_state->hw.color_encoding];
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0), intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0),
ROFF(csc[0]) | GOFF(csc[1])); ROFF(csc[0]) | GOFF(csc[1]));
...@@ -765,14 +726,8 @@ icl_program_input_csc(struct intel_plane *plane, ...@@ -765,14 +726,8 @@ icl_program_input_csc(struct intel_plane *plane,
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0), intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0),
PREOFF_YUV_TO_RGB_HI); PREOFF_YUV_TO_RGB_HI);
if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
intel_de_write_fw(dev_priv, PREOFF_YUV_TO_RGB_ME);
PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
0);
else
intel_de_write_fw(dev_priv,
PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
PREOFF_YUV_TO_RGB_ME);
intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2), intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2),
PREOFF_YUV_TO_RGB_LO); PREOFF_YUV_TO_RGB_LO);
intel_de_write_fw(dev_priv, intel_de_write_fw(dev_priv,
......
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