[Mesa-dev] [PATCH 17/26] gallium/radeon: disable CMASK on handle export if sharing doesn't allow it

Marek Olšák maraeo at gmail.com
Wed Mar 2 16:36:26 UTC 2016


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

The disabling of CMASK is simple, but notifying all contexts about it is not:
- The screen must have a list of all contexts.
- Each context must have a monotonic counter that is incremented only when
  the screen wants to re-emit framebuffer states.
- Each context must check in draw_vbo if the counter has been changed and
  re-emit the framebuffer state accordingly.
---
 src/gallium/drivers/r600/r600_state_common.c  |  9 +++++-
 src/gallium/drivers/radeon/r600_pipe_common.c | 15 ++++++++++
 src/gallium/drivers/radeon/r600_pipe_common.h | 13 +++++++++
 src/gallium/drivers/radeon/r600_texture.c     | 41 +++++++++++++++++++++++++++
 src/gallium/drivers/radeonsi/si_state_draw.c  | 12 +++++++-
 5 files changed, 88 insertions(+), 2 deletions(-)

diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c
index aa3a085..a1645ee 100644
--- a/src/gallium/drivers/r600/r600_state_common.c
+++ b/src/gallium/drivers/r600/r600_state_common.c
@@ -1672,7 +1672,7 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info
 	struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
 	bool render_cond_bit = rctx->b.render_cond && !rctx->b.render_cond_force_off;
 	uint64_t mask;
-	unsigned num_patches;
+	unsigned num_patches, dirty_fb_counter;
 
 	if (!info.indirect && !info.count && (info.indexed || !info.count_from_stream_output)) {
 		return;
@@ -1688,6 +1688,13 @@ static void r600_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info
 		rctx->b.dma.flush(rctx, RADEON_FLUSH_ASYNC, NULL);
 	}
 
+	/* Re-emit the framebuffer state if needed. */
+	dirty_fb_counter = p_atomic_read(&rctx->b.dirty_fb_counter);
+	if (dirty_fb_counter != rctx->b.last_dirty_fb_counter) {
+		rctx->b.last_dirty_fb_counter = dirty_fb_counter;
+		r600_mark_atom_dirty(rctx, &rctx->framebuffer.atom);
+	}
+
 	if (!r600_update_derived_state(rctx)) {
 		/* useless to render because current rendering command
 		 * can't be achieved
diff --git a/src/gallium/drivers/radeon/r600_pipe_common.c b/src/gallium/drivers/radeon/r600_pipe_common.c
index ea02827..88e8e8e 100644
--- a/src/gallium/drivers/radeon/r600_pipe_common.c
+++ b/src/gallium/drivers/radeon/r600_pipe_common.c
@@ -322,11 +322,23 @@ bool r600_common_context_init(struct r600_common_context *rctx,
 		rctx->dma.flush = r600_flush_dma_ring;
 	}
 
+	/* Add the new context the the global list. */
+	pipe_mutex_lock(rscreen->context_list_lock);
+	LIST_ADD(&rctx->list_item, &rscreen->context_list);
+	pipe_mutex_unlock(rscreen->context_list_lock);
+
 	return true;
 }
 
 void r600_common_context_cleanup(struct r600_common_context *rctx)
 {
+	struct r600_common_screen *rscreen = rctx->screen;
+
+	/* Remove the context from the global list. */
+	pipe_mutex_lock(rscreen->context_list_lock);
+	LIST_DEL(&rctx->list_item);
+	pipe_mutex_unlock(rscreen->context_list_lock);
+
 	if (rctx->gfx.cs)
 		rctx->ws->cs_destroy(rctx->gfx.cs);
 	if (rctx->dma.cs)
@@ -892,6 +904,8 @@ bool r600_common_screen_init(struct r600_common_screen *rscreen,
 	util_format_s3tc_init();
 	pipe_mutex_init(rscreen->aux_context_lock);
 	pipe_mutex_init(rscreen->gpu_load_mutex);
+	pipe_mutex_init(rscreen->context_list_lock);
+	LIST_INITHEAD(&rscreen->context_list);
 
 	if (((rscreen->info.drm_major == 2 && rscreen->info.drm_minor >= 28) ||
 	     rscreen->info.drm_major == 3) &&
@@ -949,6 +963,7 @@ void r600_destroy_common_screen(struct r600_common_screen *rscreen)
 
 	pipe_mutex_destroy(rscreen->gpu_load_mutex);
 	pipe_mutex_destroy(rscreen->aux_context_lock);
+	pipe_mutex_destroy(rscreen->context_list_lock);
 	rscreen->aux_context->destroy(rscreen->aux_context);
 
 	if (rscreen->trace_bo)
diff --git a/src/gallium/drivers/radeon/r600_pipe_common.h b/src/gallium/drivers/radeon/r600_pipe_common.h
index 3bbbfbb..daf8798 100644
--- a/src/gallium/drivers/radeon/r600_pipe_common.h
+++ b/src/gallium/drivers/radeon/r600_pipe_common.h
@@ -325,6 +325,10 @@ struct r600_common_screen {
 
 	/* Performance counters. */
 	struct r600_perfcounters	*perfcounters;
+
+	/* All contexts. */
+	pipe_mutex			context_list_lock;
+	struct list_head		context_list;
 };
 
 /* This encapsulates a state or an operation which can emitted into the GPU
@@ -382,6 +386,7 @@ struct r600_ring {
 struct r600_common_context {
 	struct pipe_context b; /* base class */
 
+	struct list_head		list_item; /* part of the context list */
 	struct r600_common_screen	*screen;
 	struct radeon_winsys		*ws;
 	struct radeon_winsys_ctx	*ctx;
@@ -393,6 +398,14 @@ struct r600_common_context {
 	unsigned			initial_gfx_cs_size;
 	unsigned			gpu_reset_counter;
 
+	/* If pipe_screen wants to re-emit the framebuffer state of all
+	 * contexts, it should atomically increment dirty_fb_counter.
+	 * Each context will compare the current and last counter before draw
+	 * and re-emit the framebuffer state accordingly.
+	 */
+	unsigned			dirty_fb_counter;
+	unsigned			last_dirty_fb_counter;
+
 	struct u_upload_mgr		*uploader;
 	struct u_suballocator		*allocator_so_filled_size;
 	struct util_slab_mempool	pool_transfers;
diff --git a/src/gallium/drivers/radeon/r600_texture.c b/src/gallium/drivers/radeon/r600_texture.c
index ec2f245..395607b 100644
--- a/src/gallium/drivers/radeon/r600_texture.c
+++ b/src/gallium/drivers/radeon/r600_texture.c
@@ -249,6 +249,17 @@ static void r600_texture_init_metadata(struct r600_texture *rtex,
 	metadata->scanout = (surface->flags & RADEON_SURF_SCANOUT) != 0;
 }
 
+static void r600_dirty_all_framebuffer_states(struct r600_common_screen *rscreen)
+{
+	struct r600_common_context *iter;
+
+	pipe_mutex_lock(rscreen->context_list_lock);
+	LIST_FOR_EACH_ENTRY(iter, &rscreen->context_list, list_item) {
+		p_atomic_inc(&iter->dirty_fb_counter);
+	}
+	pipe_mutex_unlock(rscreen->context_list_lock);
+}
+
 static void r600_eliminate_fast_color_clear(struct r600_common_screen *rscreen,
 				      struct r600_texture *rtex)
 {
@@ -260,6 +271,31 @@ static void r600_eliminate_fast_color_clear(struct r600_common_screen *rscreen,
 	pipe_mutex_unlock(rscreen->aux_context_lock);
 }
 
+static void r600_texture_disable_cmask(struct r600_common_screen *rscreen,
+				       struct r600_texture *rtex)
+{
+
+	if (!rtex->cmask.size)
+		return;
+
+	assert(rtex->resource.b.b.nr_samples <= 1);
+
+	/* Disable CMASK. */
+	memset(&rtex->cmask, 0, sizeof(rtex->cmask));
+	rtex->cmask.base_address_reg = rtex->resource.gpu_address >> 8;
+
+	if (rscreen->chip_class >= SI)
+		rtex->cb_color_info &= ~SI_S_028C70_FAST_CLEAR(1);
+	else
+		rtex->cb_color_info &= ~EG_S_028C70_FAST_CLEAR(1);
+
+	if (rtex->cmask_buffer != &rtex->resource)
+	    pipe_resource_reference((struct pipe_resource**)&rtex->cmask_buffer, NULL);
+
+	/* Notify all contexts about the change. */
+	r600_dirty_all_framebuffer_states(rscreen);
+}
+
 static boolean r600_texture_get_handle(struct pipe_screen* screen,
 				       struct pipe_resource *resource,
 				       struct winsys_handle *whandle,
@@ -285,6 +321,11 @@ static boolean r600_texture_get_handle(struct pipe_screen* screen,
 			if (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH)) {
 				/* Eliminate fast clear (both CMASK and DCC) */
 				r600_eliminate_fast_color_clear(rscreen, rtex);
+
+				/* Disable CMASK if flush_resource isn't going
+				 * to be called.
+				 */
+				r600_texture_disable_cmask(rscreen, rtex);
 			}
 
 			r600_texture_init_metadata(rtex, &metadata);
diff --git a/src/gallium/drivers/radeonsi/si_state_draw.c b/src/gallium/drivers/radeonsi/si_state_draw.c
index 91ccd07..e901bdc 100644
--- a/src/gallium/drivers/radeonsi/si_state_draw.c
+++ b/src/gallium/drivers/radeonsi/si_state_draw.c
@@ -763,7 +763,7 @@ void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
 	struct si_context *sctx = (struct si_context *)ctx;
 	struct si_state_rasterizer *rs = sctx->queued.named.rasterizer;
 	struct pipe_index_buffer ib = {};
-	unsigned mask;
+	unsigned mask, dirty_fb_counter;
 
 	if (!info->count && !info->indirect &&
 	    (info->indexed || !info->count_from_stream_output))
@@ -782,6 +782,16 @@ void si_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
 		return;
 	}
 
+	/* Re-emit the framebuffer state if needed. */
+	dirty_fb_counter = p_atomic_read(&sctx->b.dirty_fb_counter);
+	if (dirty_fb_counter != sctx->b.last_dirty_fb_counter) {
+		sctx->b.last_dirty_fb_counter = dirty_fb_counter;
+		sctx->framebuffer.dirty_cbufs |=
+			((1 << sctx->framebuffer.state.nr_cbufs) - 1);
+		sctx->framebuffer.dirty_zsbuf = true;
+		si_mark_atom_dirty(sctx, &sctx->framebuffer.atom);
+	}
+
 	si_decompress_textures(sctx);
 
 	/* Set the rasterization primitive type.
-- 
2.5.0



More information about the mesa-dev mailing list