[Mesa-dev] [PATCH 1/2] radeonsi: decompress DCC in set_framebuffer_state instead of create_surface (v2)

Marek Olšák maraeo at gmail.com
Thu Mar 30 14:30:39 UTC 2017


From: Marek Olšák <marek.olsak at amd.com>

for threaded gallium, which can't use pipe_context in create_surface

v2: don't add a new decompress helper function
---
 src/gallium/drivers/radeon/r600_pipe_common.h |  4 ++++
 src/gallium/drivers/radeon/r600_texture.c     | 22 ++++++++++++++------
 src/gallium/drivers/radeonsi/si_state.c       | 29 +++++++++++++++++++++++++++
 3 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/src/gallium/drivers/radeon/r600_pipe_common.h b/src/gallium/drivers/radeon/r600_pipe_common.h
index 2feca01..6a52247 100644
--- a/src/gallium/drivers/radeon/r600_pipe_common.h
+++ b/src/gallium/drivers/radeon/r600_pipe_common.h
@@ -280,20 +280,21 @@ struct r600_surface {
 	unsigned height0;
 
 	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 */
@@ -794,20 +795,23 @@ void r600_texture_get_cmask_info(struct r600_common_screen *rscreen,
 				 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_common_screen *rscreen,
 			     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_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 width0, unsigned height0,
 						unsigned width, unsigned height);
 unsigned r600_translate_colorswap(enum pipe_format format, bool do_endian_swap);
diff --git a/src/gallium/drivers/radeon/r600_texture.c b/src/gallium/drivers/radeon/r600_texture.c
index 75e8c77..0c3e2dc 100644
--- a/src/gallium/drivers/radeon/r600_texture.c
+++ b/src/gallium/drivers/radeon/r600_texture.c
@@ -1898,64 +1898,74 @@ 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);
+}
+
+/* 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 width0, unsigned height0,
 						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;
 
 	surface->width0 = width0;
 	surface->height0 = height0;
 
-	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);
 	unsigned height = u_minify(tex->height0, level);
diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c
index 866c206..2c2e3c7 100644
--- a/src/gallium/drivers/radeonsi/si_state.c
+++ b/src/gallium/drivers/radeonsi/si_state.c
@@ -2432,31 +2432,60 @@ 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];
+		rtex = (struct r600_texture*)surf->base.texture;
+
+		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;
+		}
+
+		if (vi_dcc_enabled(rtex, surf->base.u.tex.level))
+			if (!r600_texture_disable_dcc(&sctx->b, rtex))
+				sctx->b.decompress_dcc(ctx, rtex);
+
+		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 |
-- 
2.7.4



More information about the mesa-dev mailing list