[Intel-gfx] [PATCH v3 18/20] drm/i915: Use gamma LUT for RGB limited range compression

Shankar, Uma uma.shankar at intel.com
Fri Nov 18 18:37:31 UTC 2022



> -----Original Message-----
> From: Intel-gfx <intel-gfx-bounces at lists.freedesktop.org> On Behalf Of Ville Syrjala
> Sent: Monday, November 14, 2022 9:08 PM
> To: intel-gfx at lists.freedesktop.org
> Subject: [Intel-gfx] [PATCH v3 18/20] drm/i915: Use gamma LUT for RGB limited
> range compression
> 
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
> 
> On ilk+ and glk class hardware we current make a mess of things when we have to
> both generate limited range output and use the hw gamma LUT. Since we do the
> range compression using the pipe CSC unit (which is situated before the gamma LUT
> in the pipe) we are in fact applying the gamma to the limited range data instead of
> the full range data as the user intended.
> 
> We can work around this by applying the range compression via the gamma LUT
> instead of using the pipe CSC for it.
> Fairly easy to do now that we have the internal post_csc_lut attachment point where
> we can stick our new cooked LUT.
> 
> On ilk+ this only needs to be dome when using the split gamma mode or when the

Nit: Typo in "done"

Looks Good to me.
Reviewed-by: Uma Shankar <uma.shankar at intel.com>

> ctm is enabled since otherwise we can simply reorder the LUT vs. CSC. On glk we
> need to do this any time a gamma LUT is used since no reordering is possible.
> We do lose a bit of coverage in intel_color_assert_luts(), but so be it.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_color.c | 133 +++++++++++++++++----
>  1 file changed, 111 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_color.c
> b/drivers/gpu/drm/i915/display/intel_color.c
> index c336524d9225..dee0382015a5 100644
> --- a/drivers/gpu/drm/i915/display/intel_color.c
> +++ b/drivers/gpu/drm/i915/display/intel_color.c
> @@ -249,17 +249,44 @@ static void icl_update_output_csc(struct intel_crtc *crtc,
>  	intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_LO(pipe), postoff[2]);
> }
> 
> +static bool ilk_limited_range(const struct intel_crtc_state
> +*crtc_state) {
> +	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
> +
> +	/* icl+ have dedicated output CSC */
> +	if (DISPLAY_VER(i915) >= 11)
> +		return false;
> +
> +	/* pre-hsw have PIPECONF_COLOR_RANGE_SELECT */
> +	if (DISPLAY_VER(i915) < 7 || IS_IVYBRIDGE(i915))
> +		return false;
> +
> +	return crtc_state->limited_color_range; }
> +
> +static bool ilk_lut_limited_range(const struct intel_crtc_state
> +*crtc_state) {
> +	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
> +
> +	if (!ilk_limited_range(crtc_state))
> +		return false;
> +
> +	if (crtc_state->c8_planes)
> +		return false;
> +
> +	if (DISPLAY_VER(i915) == 10)
> +		return crtc_state->hw.gamma_lut;
> +	else
> +		return crtc_state->hw.gamma_lut &&
> +			(crtc_state->hw.degamma_lut || crtc_state->hw.ctm); }
> +
>  static bool ilk_csc_limited_range(const struct intel_crtc_state *crtc_state)  {
> -	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
> +	if (!ilk_limited_range(crtc_state))
> +		return false;
> 
> -	/*
> -	 * FIXME if there's a gamma LUT after the CSC, we should
> -	 * do the range compression using the gamma LUT instead.
> -	 */
> -	return crtc_state->limited_color_range &&
> -		(IS_HASWELL(i915) || IS_BROADWELL(i915) ||
> -		 IS_DISPLAY_VER(i915, 9, 10));
> +	return !ilk_lut_limited_range(crtc_state);
>  }
> 
>  static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state, @@ -
> 603,9 +630,18 @@ create_linear_lut(struct drm_i915_private *i915, int lut_size)
>  	return blob;
>  }
> 
> +static u16 lut_limited_range(unsigned int value) {
> +	unsigned int min = 16 << 8;
> +	unsigned int max = 235 << 8;
> +
> +	return value * (max - min) / 0xffff + min; }
> +
>  static struct drm_property_blob *
>  create_resized_lut(struct drm_i915_private *i915,
> -		   const struct drm_property_blob *blob_in, int lut_out_size)
> +		   const struct drm_property_blob *blob_in, int lut_out_size,
> +		   bool limited_color_range)
>  {
>  	int i, lut_in_size = drm_color_lut_size(blob_in);
>  	struct drm_property_blob *blob_out;
> @@ -621,8 +657,18 @@ create_resized_lut(struct drm_i915_private *i915,
>  	lut_in = blob_in->data;
>  	lut_out = blob_out->data;
> 
> -	for (i = 0; i < lut_out_size; i++)
> -		lut_out[i] = lut_in[i * (lut_in_size - 1) / (lut_out_size - 1)];
> +	for (i = 0; i < lut_out_size; i++) {
> +		const struct drm_color_lut *entry =
> +			&lut_in[i * (lut_in_size - 1) / (lut_out_size - 1)];
> +
> +		if (limited_color_range) {
> +			lut_out[i].red = lut_limited_range(entry->red);
> +			lut_out[i].green = lut_limited_range(entry->green);
> +			lut_out[i].blue = lut_limited_range(entry->blue);
> +		} else {
> +			lut_out[i] = *entry;
> +		}
> +	}
> 
>  	return blob_out;
>  }
> @@ -1423,6 +1469,7 @@ void intel_color_assert_luts(const struct intel_crtc_state
> *crtc_state)
>  			    crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut
> &&
>  			    crtc_state->pre_csc_lut != i915-
> >display.color.glk_linear_degamma_lut);
>  		drm_WARN_ON(&i915->drm,
> +			    !ilk_lut_limited_range(crtc_state) &&
>  			    crtc_state->post_csc_lut != NULL &&
>  			    crtc_state->post_csc_lut != crtc_state->hw.gamma_lut);
>  	} else if (crtc_state->gamma_mode != GAMMA_MODE_MODE_SPLIT) { @@
> -1430,6 +1477,7 @@ void intel_color_assert_luts(const struct intel_crtc_state
> *crtc_state)
>  			    crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut
> &&
>  			    crtc_state->pre_csc_lut != crtc_state->hw.gamma_lut);
>  		drm_WARN_ON(&i915->drm,
> +			    !ilk_lut_limited_range(crtc_state) &&
>  			    crtc_state->post_csc_lut != crtc_state->hw.degamma_lut
> &&
>  			    crtc_state->post_csc_lut != crtc_state->hw.gamma_lut);
>  	}
> @@ -1563,8 +1611,28 @@ static u32 ilk_csc_mode(const struct intel_crtc_state
> *crtc_state)
>  		CSC_POSITION_BEFORE_GAMMA;
>  }
> 
> -static void ilk_assign_luts(struct intel_crtc_state *crtc_state)
> +static int ilk_assign_luts(struct intel_crtc_state *crtc_state)
>  {
> +	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
> +
> +	if (ilk_lut_limited_range(crtc_state)) {
> +		struct drm_property_blob *gamma_lut;
> +
> +		gamma_lut = create_resized_lut(i915, crtc_state->hw.gamma_lut,
> +					       drm_color_lut_size(crtc_state-
> >hw.gamma_lut),
> +					       true);
> +		if (IS_ERR(gamma_lut))
> +			return PTR_ERR(gamma_lut);
> +
> +		drm_property_replace_blob(&crtc_state->post_csc_lut,
> gamma_lut);
> +
> +		drm_property_blob_put(gamma_lut);
> +
> +		drm_property_replace_blob(&crtc_state->pre_csc_lut,
> +crtc_state->hw.degamma_lut);
> +
> +		return 0;
> +	}
> +
>  	if (crtc_state->hw.degamma_lut ||
>  	    crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) {
>  		drm_property_replace_blob(&crtc_state->pre_csc_lut,
> @@ -1577,6 +1645,8 @@ static void ilk_assign_luts(struct intel_crtc_state
> *crtc_state)
>  		drm_property_replace_blob(&crtc_state->post_csc_lut,
>  					  NULL);
>  	}
> +
> +	return 0;
>  }
> 
>  static int ilk_color_check(struct intel_crtc_state *crtc_state) @@ -1613,7 +1683,9
> @@ static int ilk_color_check(struct intel_crtc_state *crtc_state)
>  	if (ret)
>  		return ret;
> 
> -	ilk_assign_luts(crtc_state);
> +	ret = ilk_assign_luts(crtc_state);
> +	if (ret)
> +		return ret;
> 
>  	crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
> 
> @@ -1649,19 +1721,19 @@ static int ivb_assign_luts(struct intel_crtc_state
> *crtc_state)
>  	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
>  	struct drm_property_blob *degamma_lut, *gamma_lut;
> 
> -	if (crtc_state->gamma_mode != GAMMA_MODE_MODE_SPLIT) {
> -		ilk_assign_luts(crtc_state);
> -		return 0;
> -	}
> +	if (crtc_state->gamma_mode != GAMMA_MODE_MODE_SPLIT)
> +		return ilk_assign_luts(crtc_state);
> 
>  	drm_WARN_ON(&i915->drm, drm_color_lut_size(crtc_state-
> >hw.degamma_lut) != 1024);
>  	drm_WARN_ON(&i915->drm, drm_color_lut_size(crtc_state-
> >hw.gamma_lut) != 1024);
> 
> -	degamma_lut = create_resized_lut(i915, crtc_state->hw.degamma_lut,
> 512);
> +	degamma_lut = create_resized_lut(i915, crtc_state->hw.degamma_lut, 512,
> +					 false);
>  	if (IS_ERR(degamma_lut))
>  		return PTR_ERR(degamma_lut);
> 
> -	gamma_lut = create_resized_lut(i915, crtc_state->hw.gamma_lut, 512);
> +	gamma_lut = create_resized_lut(i915, crtc_state->hw.gamma_lut, 512,
> +				       ilk_lut_limited_range(crtc_state));
>  	if (IS_ERR(gamma_lut)) {
>  		drm_property_blob_put(degamma_lut);
>  		return PTR_ERR(gamma_lut);
> @@ -1750,7 +1822,8 @@ static int glk_assign_luts(struct intel_crtc_state
> *crtc_state)
>  		struct drm_property_blob *gamma_lut;
> 
>  		gamma_lut = create_resized_lut(i915, crtc_state->hw.gamma_lut,
> -					       INTEL_INFO(i915)-
> >display.color.degamma_lut_size);
> +					       INTEL_INFO(i915)-
> >display.color.degamma_lut_size,
> +					       false);
>  		if (IS_ERR(gamma_lut))
>  			return PTR_ERR(gamma_lut);
> 
> @@ -1762,7 +1835,23 @@ static int glk_assign_luts(struct intel_crtc_state
> *crtc_state)
>  		return 0;
>  	}
> 
> -	intel_assign_luts(crtc_state);
> +	if (ilk_lut_limited_range(crtc_state)) {
> +		struct drm_property_blob *gamma_lut;
> +
> +		gamma_lut = create_resized_lut(i915, crtc_state->hw.gamma_lut,
> +					       drm_color_lut_size(crtc_state-
> >hw.gamma_lut),
> +					       true);
> +		if (IS_ERR(gamma_lut))
> +			return PTR_ERR(gamma_lut);
> +
> +		drm_property_replace_blob(&crtc_state->post_csc_lut,
> gamma_lut);
> +
> +		drm_property_blob_put(gamma_lut);
> +	} else {
> +		drm_property_replace_blob(&crtc_state->post_csc_lut, crtc_state-
> >hw.gamma_lut);
> +	}
> +
> +	drm_property_replace_blob(&crtc_state->pre_csc_lut,
> +crtc_state->hw.degamma_lut);
> 
>  	/*
>  	 * On GLK+ both pipe CSC and degamma LUT are controlled @@ -1821,7
> +1910,7 @@ static int glk_color_check(struct intel_crtc_state *crtc_state)
>  		glk_use_pre_csc_lut_for_gamma(crtc_state) ||
>  		crtc_state->hw.degamma_lut ||
>  		crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB ||
> -		crtc_state->hw.ctm || crtc_state->limited_color_range;
> +		crtc_state->hw.ctm || ilk_csc_limited_range(crtc_state);
> 
>  	crtc_state->gamma_mode = glk_gamma_mode(crtc_state);
> 
> --
> 2.37.4



More information about the Intel-gfx mailing list