Mesa (master): WIP: freedreno/a3xx: incorrect scissor for binning pass

Rob Clark robclark at kemper.freedesktop.org
Wed Mar 5 17:54:41 UTC 2014


Module: Mesa
Branch: master
Commit: 4de1e5eddcb76e377cffbb7f3bd87a88a575dae2
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=4de1e5eddcb76e377cffbb7f3bd87a88a575dae2

Author: Rob Clark <robclark at freedesktop.org>
Date:   Wed Mar  5 11:29:45 2014 -0500

WIP: freedreno/a3xx: incorrect scissor for binning pass

If scissor optimization is used (to avoid bringing scissored portions of
the render target into GMEM and then back out to system memory) in
combination with hw binning pass, the result would be a scissor mismatch
between binning pass and rendering pass.  This would cause rendering
bugs in some scenarios with (for example) gnome-shell.

I would have expected that simply using the correct screen-scissor
during the binning pass would be enough, but seems like there is
something else missing.  So for now disable binning pass if scissor
optimization is used.

---

 src/gallium/drivers/freedreno/a3xx/fd3_gmem.c  |   40 +++++++++++++++++++-----
 src/gallium/drivers/freedreno/freedreno_gmem.c |    2 ++
 src/gallium/drivers/freedreno/freedreno_gmem.h |    1 +
 3 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c b/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c
index dde71ba..72fe6f7 100644
--- a/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c
+++ b/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c
@@ -115,6 +115,24 @@ static bool
 use_hw_binning(struct fd_context *ctx)
 {
 	struct fd_gmem_stateobj *gmem = &ctx->gmem;
+
+	/* workaround: combining scissor optimization and hw binning
+	 * seems problematic.  Seems like we end up with a mismatch
+	 * between binning pass and rendering pass, wrt. where the hw
+	 * thinks the vertices belong.  And the blob driver doesn't
+	 * seem to implement anything like scissor optimization, so
+	 * not entirely sure what I might be missing.
+	 *
+	 * But scissor optimization is mainly for window managers,
+	 * which don't have many vertices (and therefore doesn't
+	 * benefit much from binning pass).
+	 *
+	 * So for now just disable binning if scissor optimization is
+	 * used.
+	 */
+	if (gmem->minx || gmem->miny)
+		return false;
+
 	return fd_binning_enabled && ((gmem->nbins_x * gmem->nbins_y) > 2);
 }
 
@@ -644,10 +662,16 @@ update_vsc_pipe(struct fd_context *ctx)
 static void
 emit_binning_pass(struct fd_context *ctx)
 {
+	struct fd_gmem_stateobj *gmem = &ctx->gmem;
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
 	struct fd_ringbuffer *ring = ctx->ring;
 	int i;
 
+	uint32_t x1 = gmem->minx;
+	uint32_t y1 = gmem->miny;
+	uint32_t x2 = gmem->minx + gmem->width - 1;
+	uint32_t y2 = gmem->miny + gmem->height - 1;
+
 	if (ctx->screen->gpu_id == 320) {
 		emit_binning_workaround(ctx);
 
@@ -670,21 +694,21 @@ emit_binning_pass(struct fd_context *ctx)
 	OUT_PKT0(ring, REG_A3XX_RB_RENDER_CONTROL, 1);
 	OUT_RING(ring, A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC(FUNC_NEVER) |
 			A3XX_RB_RENDER_CONTROL_DISABLE_COLOR_PIPE |
-			A3XX_RB_RENDER_CONTROL_BIN_WIDTH(ctx->gmem.bin_w));
+			A3XX_RB_RENDER_CONTROL_BIN_WIDTH(gmem->bin_w));
 
 	/* setup scissor/offset for whole screen: */
 	OUT_PKT0(ring, REG_A3XX_RB_WINDOW_OFFSET, 1);
-	OUT_RING(ring, A3XX_RB_WINDOW_OFFSET_X(0) |
-			A3XX_RB_WINDOW_OFFSET_Y(0));
+	OUT_RING(ring, A3XX_RB_WINDOW_OFFSET_X(x1) |
+			A3XX_RB_WINDOW_OFFSET_Y(y1));
 
 	OUT_PKT0(ring, REG_A3XX_RB_LRZ_VSC_CONTROL, 1);
 	OUT_RING(ring, A3XX_RB_LRZ_VSC_CONTROL_BINNING_ENABLE);
 
 	OUT_PKT0(ring, REG_A3XX_GRAS_SC_SCREEN_SCISSOR_TL, 2);
-	OUT_RING(ring, A3XX_GRAS_SC_SCREEN_SCISSOR_TL_X(0) |
-			A3XX_GRAS_SC_SCREEN_SCISSOR_TL_Y(0));
-	OUT_RING(ring, A3XX_GRAS_SC_SCREEN_SCISSOR_BR_X(pfb->width - 1) |
-			A3XX_GRAS_SC_SCREEN_SCISSOR_BR_Y(pfb->height - 1));
+	OUT_RING(ring, A3XX_GRAS_SC_SCREEN_SCISSOR_TL_X(x1) |
+			A3XX_GRAS_SC_SCREEN_SCISSOR_TL_Y(y1));
+	OUT_RING(ring, A3XX_GRAS_SC_SCREEN_SCISSOR_BR_X(x2) |
+			A3XX_GRAS_SC_SCREEN_SCISSOR_BR_Y(y2));
 
 	OUT_PKT0(ring, REG_A3XX_RB_MODE_CONTROL, 1);
 	OUT_RING(ring, A3XX_RB_MODE_CONTROL_RENDER_MODE(RB_TILING_PASS) |
@@ -731,7 +755,7 @@ emit_binning_pass(struct fd_context *ctx)
 			A3XX_RB_MODE_CONTROL_MARB_CACHE_SPLIT_MODE);
 	OUT_RING(ring, A3XX_RB_RENDER_CONTROL_ENABLE_GMEM |
 			A3XX_RB_RENDER_CONTROL_ALPHA_TEST_FUNC(FUNC_NEVER) |
-			A3XX_RB_RENDER_CONTROL_BIN_WIDTH(ctx->gmem.bin_w));
+			A3XX_RB_RENDER_CONTROL_BIN_WIDTH(gmem->bin_w));
 
 	OUT_PKT3(ring, CP_EVENT_WRITE, 1);
 	OUT_RING(ring, CACHE_FLUSH);
diff --git a/src/gallium/drivers/freedreno/freedreno_gmem.c b/src/gallium/drivers/freedreno/freedreno_gmem.c
index 80cf7c8..2d4de44 100644
--- a/src/gallium/drivers/freedreno/freedreno_gmem.c
+++ b/src/gallium/drivers/freedreno/freedreno_gmem.c
@@ -143,6 +143,8 @@ calculate_tiles(struct fd_context *ctx)
 	gmem->bin_w = bin_w;
 	gmem->nbins_x = nbins_x;
 	gmem->nbins_y = nbins_y;
+	gmem->minx = minx;
+	gmem->miny = miny;
 	gmem->width = width;
 	gmem->height = height;
 
diff --git a/src/gallium/drivers/freedreno/freedreno_gmem.h b/src/gallium/drivers/freedreno/freedreno_gmem.h
index b52557c..c7c6874 100644
--- a/src/gallium/drivers/freedreno/freedreno_gmem.h
+++ b/src/gallium/drivers/freedreno/freedreno_gmem.h
@@ -50,6 +50,7 @@ struct fd_gmem_stateobj {
 	uint cpp;
 	uint16_t bin_h, nbins_y;
 	uint16_t bin_w, nbins_x;
+	uint16_t minx, miny;
 	uint16_t width, height;
 	bool has_zs;  /* gmem config using depth/stencil? */
 };




More information about the mesa-commit mailing list