[PATCH v2] drm/amd/display: add Coverage blend mode for overlay plane

Melissa Wen mwen at igalia.com
Thu May 19 20:00:10 UTC 2022


On 05/13, Sung Joon Kim wrote:
> Issue fixed: Overlay plane alpha channel blending is incorrect
> 
> Issue tracker: https://gitlab.freedesktop.org/drm/amd/-/issues/1769
> 
> According to the KMS man page, there is a
> "Coverage" alpha blend mode that assumes the
> pixel color values have NOT been pre-multiplied
> and will be done when the actual blending to
> the background color values happens.
> 
> Previously, this mode hasn't been enabled
> in our driver and it was assumed that all
> normal overlay planes are pre-multiplied
> by default.
> 
> When a 3rd party app is used to input a image
> in a specific format, e.g. PNG, as a source
> of a overlay plane to blend with the background
> primary plane, the pixel color values are not
> pre-multiplied. So by adding "Coverage" blend
> mode, our driver will support those cases.
> 
Hi,

overall lgtm. I would move those "Issue" points to here (after change
description).

> Reference:
> https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#plane-composition-properties
> 
> Adding Coverage support also enables IGT
> kms_plane_alpha_blend Coverage subtests:
> 1. coverage-7efc
> 2. coverage-vs-premult-vs-constant

.. and include a summary of changes from v1 here.
> 
> Signed-off-by: Sung Joon Kim <Sungjoon.Kim at amd.com>
> ---
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 17 ++++++++----
>  .../gpu/drm/amd/display/dc/core/dc_surface.c  |  2 ++
>  drivers/gpu/drm/amd/display/dc/dc.h           |  2 ++
>  .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 27 ++++++++++---------
>  .../drm/amd/display/dc/dcn20/dcn20_hwseq.c    | 16 ++++++-----
>  5 files changed, 40 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index 2ea20dd7fccf..af2b5d232742 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -5380,17 +5380,19 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev,
>  
>  static void
>  fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
> -			       bool *per_pixel_alpha, bool *global_alpha,
> -			       int *global_alpha_value)
> +			       bool *per_pixel_alpha, bool *pre_multiplied_alpha,
> +			       bool *global_alpha, int *global_alpha_value)
>  {
>  	*per_pixel_alpha = false;
> +	*pre_multiplied_alpha = true;
>  	*global_alpha = false;
>  	*global_alpha_value = 0xff;
>  
>  	if (plane_state->plane->type != DRM_PLANE_TYPE_OVERLAY)
>  		return;
>  
> -	if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) {
> +	if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
> +		plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
>  		static const uint32_t alpha_formats[] = {
>  			DRM_FORMAT_ARGB8888,
>  			DRM_FORMAT_RGBA8888,
> @@ -5405,6 +5407,9 @@ fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
>  				break;
>  			}
>  		}
> +
> +		if (per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
> +			*pre_multiplied_alpha = false;
>  	}
>  
>  	if (plane_state->alpha < 0xffff) {
> @@ -5567,7 +5572,7 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
>  		return ret;
>  
>  	fill_blending_from_plane_state(
> -		plane_state, &plane_info->per_pixel_alpha,
> +		plane_state, &plane_info->per_pixel_alpha, &plane_info->pre_multiplied_alpha,
>  		&plane_info->global_alpha, &plane_info->global_alpha_value);
>  
>  	return 0;
> @@ -5614,6 +5619,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
>  	dc_plane_state->tiling_info = plane_info.tiling_info;
>  	dc_plane_state->visible = plane_info.visible;
>  	dc_plane_state->per_pixel_alpha = plane_info.per_pixel_alpha;
> +	dc_plane_state->pre_multiplied_alpha = plane_info.pre_multiplied_alpha;
>  	dc_plane_state->global_alpha = plane_info.global_alpha;
>  	dc_plane_state->global_alpha_value = plane_info.global_alpha_value;
>  	dc_plane_state->dcc = plane_info.dcc;
> @@ -7905,7 +7911,8 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
>  	if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
>  	    plane_cap && plane_cap->per_pixel_alpha) {
>  		unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
> -					  BIT(DRM_MODE_BLEND_PREMULTI);
> +					  BIT(DRM_MODE_BLEND_PREMULTI) |
> +					  BIT(DRM_MODE_BLEND_COVERAGE);
>  
>  		drm_plane_create_alpha_property(plane);
>  		drm_plane_create_blend_mode_property(plane, blend_caps);
> diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
> index e6b9c6a71841..5bc6ff2fa73e 100644
> --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
> +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
> @@ -61,6 +61,8 @@ static void dc_plane_construct(struct dc_context *ctx, struct dc_plane_state *pl
>  		plane_state->blend_tf->type = TF_TYPE_BYPASS;
>  	}
>  
> +	plane_state->pre_multiplied_alpha = true;
> +
>  }
>  
>  static void dc_plane_destruct(struct dc_plane_state *plane_state)
> diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
> index 26c24db8f1da..c353842d5c40 100644
> --- a/drivers/gpu/drm/amd/display/dc/dc.h
> +++ b/drivers/gpu/drm/amd/display/dc/dc.h
> @@ -1011,6 +1011,7 @@ struct dc_plane_state {
>  
>  	bool is_tiling_rotated;
>  	bool per_pixel_alpha;
> +	bool pre_multiplied_alpha;
>  	bool global_alpha;
>  	int  global_alpha_value;
>  	bool visible;
> @@ -1045,6 +1046,7 @@ struct dc_plane_info {
>  	bool horizontal_mirror;
>  	bool visible;
>  	bool per_pixel_alpha;
> +	bool pre_multiplied_alpha;
>  	bool global_alpha;
>  	int  global_alpha_value;
>  	bool input_csc_enabled;
> diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
> index e02ac75afbf7..e3a62873c0e7 100644
> --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
> +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
> @@ -2550,12 +2550,21 @@ void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
>  	blnd_cfg.overlap_only = false;
>  	blnd_cfg.global_gain = 0xff;
>  
> -	if (per_pixel_alpha && pipe_ctx->plane_state->global_alpha) {
> -		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
> -		blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
> -	} else if (per_pixel_alpha) {
> -		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
> +	if (per_pixel_alpha) {
> +		/* DCN1.0 has output CM before MPC which seems to screw with
> +		 * pre-multiplied alpha.
> +		 */
> +		blnd_cfg.pre_multiplied_alpha = (is_rgb_cspace(
> +				pipe_ctx->stream->output_color_space)
> +						&& pipe_ctx->plane_state->pre_multiplied_alpha);
> +		if (pipe_ctx->plane_state->global_alpha) {
> +			blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
> +			blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
> +		} else {
> +			blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
> +		}
>  	} else {
> +		blnd_cfg.pre_multiplied_alpha = false;
>  		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
>  	}
>  
> @@ -2564,14 +2573,6 @@ void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
>  	else
>  		blnd_cfg.global_alpha = 0xff;
>  
> -	/* DCN1.0 has output CM before MPC which seems to screw with
> -	 * pre-multiplied alpha.
> -	 */
> -	blnd_cfg.pre_multiplied_alpha = is_rgb_cspace(
> -			pipe_ctx->stream->output_color_space)
> -					&& per_pixel_alpha;
> -
> -
>  	/*
>  	 * TODO: remove hack
>  	 * Note: currently there is a bug in init_hw such that
> diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
> index e1f87bd72e4a..c117830b8b9d 100644
> --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
> +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
> @@ -2346,12 +2346,16 @@ void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
>  	blnd_cfg.overlap_only = false;
>  	blnd_cfg.global_gain = 0xff;
>  
> -	if (per_pixel_alpha && pipe_ctx->plane_state->global_alpha) {
> -		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
> -		blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
> -	} else if (per_pixel_alpha) {
> -		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
> +	if (per_pixel_alpha) {
> +		blnd_cfg.pre_multiplied_alpha = pipe_ctx->plane_state->pre_multiplied_alpha;
> +		if (pipe_ctx->plane_state->global_alpha) {
> +			blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
> +			blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
> +		} else {
> +			blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
> +		}
>  	} else {
> +		blnd_cfg.pre_multiplied_alpha = false;
>  		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
>  	}
>  
> @@ -2365,7 +2369,7 @@ void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
>  	blnd_cfg.top_gain = 0x1f000;
>  	blnd_cfg.bottom_inside_gain = 0x1f000;
>  	blnd_cfg.bottom_outside_gain = 0x1f000;
> -	blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
> +	
^ checkpatch complains about `trailing whitespace` here.

Anyway, after addressing these minor comments, the patch is

Reviewed-by: Melissa Wen <mwen at igalia.com>

Thanks a lot!

Next, I'm going to refactor the IGT coverage-7efc test to match the
changes done to alpha-7efc (pre-multiplied).

>  	if (pipe_ctx->plane_state->format
>  			== SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA)
>  		blnd_cfg.pre_multiplied_alpha = false;
> -- 
> 2.20.1
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/amd-gfx/attachments/20220519/0d0f0542/attachment.sig>


More information about the amd-gfx mailing list