[Mesa-dev] [PATCH 8/9] radeonsi: decompress DCC in set_framebuffer_state instead of create_surface

Nicolai Hähnle nhaehnle at gmail.com
Thu Mar 30 07:46:13 UTC 2017


On 29.03.2017 19:58, Marek Olšák wrote:
> From: Marek Olšák <marek.olsak at amd.com>
>
> for threaded gallium, which can't use pipe_context in create_surface
> ---
>  src/gallium/drivers/radeon/r600_pipe_common.h |  8 +++++++
>  src/gallium/drivers/radeon/r600_texture.c     | 33 +++++++++++++++++++++++----
>  src/gallium/drivers/radeonsi/si_state.c       | 26 +++++++++++++++++++++
>  3 files changed, 62 insertions(+), 5 deletions(-)
>
> diff --git a/src/gallium/drivers/radeon/r600_pipe_common.h b/src/gallium/drivers/radeon/r600_pipe_common.h
> index 035ab1c..c9cb586 100644
> --- a/src/gallium/drivers/radeon/r600_pipe_common.h
> +++ b/src/gallium/drivers/radeon/r600_pipe_common.h
> @@ -276,20 +276,21 @@ struct r600_surface {
>  	struct pipe_surface		base;
>
>  	bool color_initialized;
>  	bool depth_initialized;
>
>  	/* Misc. color flags. */
>  	bool alphatest_bypass;
>  	bool export_16bpc;
>  	bool color_is_int8;
>  	bool color_is_int10;
> +	bool dcc_incompatible;
>
>  	/* Color registers. */
>  	unsigned cb_color_info;
>  	unsigned cb_color_base;
>  	unsigned cb_color_view;
>  	unsigned cb_color_size;		/* R600 only */
>  	unsigned cb_color_dim;		/* EG only */
>  	unsigned cb_color_pitch;	/* EG and later */
>  	unsigned cb_color_slice;	/* EG and later */
>  	unsigned cb_color_attrib;	/* EG and later */
> @@ -784,20 +785,27 @@ void r600_texture_get_cmask_info(struct r600_common_screen *rscreen,
>  				 struct r600_texture *rtex,
>  				 struct r600_cmask_info *out);
>  bool r600_init_flushed_depth_texture(struct pipe_context *ctx,
>  				     struct pipe_resource *texture,
>  				     struct r600_texture **staging);
>  void r600_print_texture_info(struct r600_texture *rtex, FILE *f);
>  struct pipe_resource *r600_texture_create(struct pipe_screen *screen,
>  					const struct pipe_resource *templ);
>  bool vi_dcc_formats_compatible(enum pipe_format format1,
>  			       enum pipe_format format2);
> +bool vi_dcc_formats_are_incompatible(struct pipe_resource *tex,
> +				     unsigned level,
> +				     enum pipe_format view_format);
> +void vi_disable_dcc_if_incompatible_flag(struct r600_common_context *rctx,
> +					 struct pipe_resource *tex,
> +					 unsigned level,
> +				         bool dcc_incompatible);

Why pass the dcc_incompatible flag as a parameter? It makes more sense 
for the callers to check this flag, and as far as I can tell, all 
callers actually do check it already.

Apart from that, the series is

Reviewed-by: Nicolai Hähnle <nicolai.haehnle at amd.com>


>  void vi_disable_dcc_if_incompatible_format(struct r600_common_context *rctx,
>  					   struct pipe_resource *tex,
>  					   unsigned level,
>  					   enum pipe_format view_format);
>  struct pipe_surface *r600_create_surface_custom(struct pipe_context *pipe,
>  						struct pipe_resource *texture,
>  						const struct pipe_surface *templ,
>  						unsigned width, unsigned height);
>  unsigned r600_translate_colorswap(enum pipe_format format, bool do_endian_swap);
>  void vi_separate_dcc_start_query(struct pipe_context *ctx,
> diff --git a/src/gallium/drivers/radeon/r600_texture.c b/src/gallium/drivers/radeon/r600_texture.c
> index 783f50c..1191a74 100644
> --- a/src/gallium/drivers/radeon/r600_texture.c
> +++ b/src/gallium/drivers/radeon/r600_texture.c
> @@ -1733,59 +1733,82 @@ bool vi_dcc_formats_compatible(enum pipe_format format1,
>  			return false;
>
>  	type1 = vi_get_dcc_channel_type(desc1);
>  	type2 = vi_get_dcc_channel_type(desc2);
>
>  	return type1 != dcc_channel_incompatible &&
>  	       type2 != dcc_channel_incompatible &&
>  	       type1 == type2;
>  }
>
> +bool vi_dcc_formats_are_incompatible(struct pipe_resource *tex,
> +				     unsigned level,
> +				     enum pipe_format view_format)
> +{
> +	struct r600_texture *rtex = (struct r600_texture *)tex;
> +
> +	return vi_dcc_enabled(rtex, level) &&
> +	       !vi_dcc_formats_compatible(tex->format, view_format);
> +}
> +
> +void vi_disable_dcc_if_incompatible_flag(struct r600_common_context *rctx,
> +					 struct pipe_resource *tex,
> +					 unsigned level,
> +				         bool dcc_incompatible)
> +{
> +	struct r600_texture *rtex = (struct r600_texture *)tex;
> +
> +	if (vi_dcc_enabled(rtex, level) && dcc_incompatible)
> +		if (!r600_texture_disable_dcc(rctx, (struct r600_texture*)tex))
> +			rctx->decompress_dcc(&rctx->b, rtex);
> +}
> +
> +/* This can't be merged with the above function, because
> + * vi_dcc_formats_compatible should be called only when DCC is enabled. */
>  void vi_disable_dcc_if_incompatible_format(struct r600_common_context *rctx,
>  					   struct pipe_resource *tex,
>  					   unsigned level,
>  					   enum pipe_format view_format)
>  {
>  	struct r600_texture *rtex = (struct r600_texture *)tex;
>
>  	if (vi_dcc_enabled(rtex, level) &&
>  	    !vi_dcc_formats_compatible(tex->format, view_format))
>  		if (!r600_texture_disable_dcc(rctx, (struct r600_texture*)tex))
>  			rctx->decompress_dcc(&rctx->b, rtex);
>  }
>
>  struct pipe_surface *r600_create_surface_custom(struct pipe_context *pipe,
>  						struct pipe_resource *texture,
>  						const struct pipe_surface *templ,
>  						unsigned width, unsigned height)
>  {
> -	struct r600_common_context *rctx = (struct r600_common_context*)pipe;
>  	struct r600_surface *surface = CALLOC_STRUCT(r600_surface);
>
>  	if (!surface)
>  		return NULL;
>
>  	assert(templ->u.tex.first_layer <= util_max_layer(texture, templ->u.tex.level));
>  	assert(templ->u.tex.last_layer <= util_max_layer(texture, templ->u.tex.level));
>
>  	pipe_reference_init(&surface->base.reference, 1);
>  	pipe_resource_reference(&surface->base.texture, texture);
>  	surface->base.context = pipe;
>  	surface->base.format = templ->format;
>  	surface->base.width = width;
>  	surface->base.height = height;
>  	surface->base.u = templ->u;
>
> -	if (texture->target != PIPE_BUFFER)
> -		vi_disable_dcc_if_incompatible_format(rctx, texture,
> -						      templ->u.tex.level,
> -						      templ->format);
> +	surface->dcc_incompatible =
> +		texture->target != PIPE_BUFFER &&
> +		vi_dcc_formats_are_incompatible(texture, templ->u.tex.level,
> +						templ->format);
>
>  	return &surface->base;
>  }
>
>  static struct pipe_surface *r600_create_surface(struct pipe_context *pipe,
>  						struct pipe_resource *tex,
>  						const struct pipe_surface *templ)
>  {
>  	unsigned level = templ->u.tex.level;
>  	unsigned width = u_minify(tex->width0, level);
> diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c
> index 9461a1c..39b9152 100644
> --- a/src/gallium/drivers/radeonsi/si_state.c
> +++ b/src/gallium/drivers/radeonsi/si_state.c
> @@ -2362,31 +2362,57 @@ static void si_dec_framebuffer_counters(const struct pipe_framebuffer_state *sta
>
>  static void si_set_framebuffer_state(struct pipe_context *ctx,
>  				     const struct pipe_framebuffer_state *state)
>  {
>  	struct si_context *sctx = (struct si_context *)ctx;
>  	struct pipe_constant_buffer constbuf = {0};
>  	struct r600_surface *surf = NULL;
>  	struct r600_texture *rtex;
>  	bool old_any_dst_linear = sctx->framebuffer.any_dst_linear;
>  	unsigned old_nr_samples = sctx->framebuffer.nr_samples;
> +	bool unbound = false;
>  	int i;
>
>  	for (i = 0; i < sctx->framebuffer.state.nr_cbufs; i++) {
>  		if (!sctx->framebuffer.state.cbufs[i])
>  			continue;
>
>  		rtex = (struct r600_texture*)sctx->framebuffer.state.cbufs[i]->texture;
>  		if (rtex->dcc_gather_statistics)
>  			vi_separate_dcc_stop_query(ctx, rtex);
>  	}
>
> +	/* Disable DCC if the formats are incompatible. */
> +	for (i = 0; i < state->nr_cbufs; i++) {
> +		if (!state->cbufs[i])
> +			continue;
> +
> +		surf = (struct r600_surface*)state->cbufs[i];
> +		if (!surf->dcc_incompatible)
> +			continue;
> +
> +		/* Since the DCC decompression calls back into set_framebuffer-
> +		 * _state, we need to unbind the framebuffer, so that
> +		 * vi_separate_dcc_stop_query isn't called twice with the same
> +		 * color buffer.
> +		 */
> +		if (!unbound) {
> +			util_copy_framebuffer_state(&sctx->framebuffer.state, NULL);
> +			unbound = true;
> +		}
> +
> +		vi_disable_dcc_if_incompatible_flag(&sctx->b, surf->base.texture,
> +						    surf->base.u.tex.level,
> +						    surf->dcc_incompatible);
> +		surf->dcc_incompatible = false;
> +	}
> +
>  	/* Only flush TC when changing the framebuffer state, because
>  	 * the only client not using TC that can change textures is
>  	 * the framebuffer.
>  	 *
>  	 * Flush all CB and DB caches here because all buffers can be used
>  	 * for write by both TC (with shader image stores) and CB/DB.
>  	 */
>  	sctx->b.flags |= SI_CONTEXT_INV_VMEM_L1 |
>  			 SI_CONTEXT_INV_GLOBAL_L2 |
>  			 SI_CONTEXT_FLUSH_AND_INV_CB |
>


-- 
Lerne, wie die Welt wirklich ist,
Aber vergiss niemals, wie sie sein sollte.


More information about the mesa-dev mailing list