On Tue, Mar 8, 2016 at 4:41 AM, Michel Dänzer <[email protected]> wrote:
> On 03.03.2016 01:36, Marek Olšák wrote:
>> From: Marek Olšák <[email protected]>
>>
>> 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.
>
> The list seems a bit overkill. How about having dirty_fb_counter in the
> screen and last_dirty_fb_counter in the context, incrementing the former
> in r600_dirty_all_framebuffer_states and emitting the framebuffer state
> if the two counters don't match?

Thanks. The updated patch is attached. Please review.

Marek
From 24ce54f6c47d97efc058d5928d39508040e781a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= <[email protected]>
Date: Wed, 24 Feb 2016 22:04:47 +0100
Subject: [PATCH] gallium/radeon: disable CMASK on handle export if sharing
 doesn't allow it (v2)

v2: remove the list of all contexts
---
 src/gallium/drivers/r600/r600_state_common.c  |  9 ++++++-
 src/gallium/drivers/radeon/r600_pipe_common.h |  8 ++++++
 src/gallium/drivers/radeon/r600_texture.c     | 35 +++++++++++++++++++++++++++
 src/gallium/drivers/radeonsi/si_state_draw.c  | 12 ++++++++-
 4 files changed, 62 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..e3314bb 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.screen->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.h b/src/gallium/drivers/radeon/r600_pipe_common.h
index 3bbbfbb..0f230e0 100644
--- a/src/gallium/drivers/radeon/r600_pipe_common.h
+++ b/src/gallium/drivers/radeon/r600_pipe_common.h
@@ -325,6 +325,13 @@ struct r600_common_screen {
 
 	/* Performance counters. */
 	struct r600_perfcounters	*perfcounters;
+
+	/* If pipe_screen wants to re-emit the framebuffer state of all
+	 * contexts, it should atomically this. Each context will compare
+	 * this with its own last known value of the counter before drawing
+	 * and re-emit the framebuffer state accordingly.
+	 */
+	unsigned			dirty_fb_counter;
 };
 
 /* This encapsulates a state or an operation which can emitted into the GPU
@@ -392,6 +399,7 @@ struct r600_common_context {
 	struct pipe_fence_handle	*last_sdma_fence;
 	unsigned			initial_gfx_cs_size;
 	unsigned			gpu_reset_counter;
+	unsigned			last_dirty_fb_counter;
 
 	struct u_upload_mgr		*uploader;
 	struct u_suballocator		*allocator_so_filled_size;
diff --git a/src/gallium/drivers/radeon/r600_texture.c b/src/gallium/drivers/radeon/r600_texture.c
index ec2f245..679cd71 100644
--- a/src/gallium/drivers/radeon/r600_texture.c
+++ b/src/gallium/drivers/radeon/r600_texture.c
@@ -249,6 +249,11 @@ 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)
+{
+	p_atomic_inc(&rscreen->dirty_fb_counter);
+}
+
 static void r600_eliminate_fast_color_clear(struct r600_common_screen *rscreen,
 				      struct r600_texture *rtex)
 {
@@ -260,6 +265,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 +315,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..5d094c7 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.screen->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

_______________________________________________
mesa-dev mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to