Mesa (master): freedreno: track maximal scissor bounds

Rob Clark robclark at kemper.freedesktop.org
Mon Mar 25 17:07:59 UTC 2013


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

Author: Rob Clark <robdclark at gmail.com>
Date:   Wed Mar  6 10:45:58 2013 -0500

freedreno: track maximal scissor bounds

Optimize out parts of the render target that are scissored out by taking
into account maximal scissor bounds in fd_gmem_render_tiles().

This is a big win on things like gnome-shell which frequently do partial
screen updates.

Signed-off-by: Rob Clark <robdclark at gmail.com>

---

 src/gallium/drivers/freedreno/freedreno_clear.c    |    7 +-
 src/gallium/drivers/freedreno/freedreno_context.c  |    8 +-
 src/gallium/drivers/freedreno/freedreno_context.h  |   21 ++-
 src/gallium/drivers/freedreno/freedreno_gmem.c     |  208 ++++++++++++--------
 src/gallium/drivers/freedreno/freedreno_gmem.h     |    1 -
 src/gallium/drivers/freedreno/freedreno_resource.c |    2 +-
 src/gallium/drivers/freedreno/freedreno_state.c    |   41 +---
 src/gallium/drivers/freedreno/freedreno_state.h    |    2 -
 src/gallium/drivers/freedreno/freedreno_vbo.c      |    8 +-
 9 files changed, 162 insertions(+), 136 deletions(-)

diff --git a/src/gallium/drivers/freedreno/freedreno_clear.c b/src/gallium/drivers/freedreno/freedreno_clear.c
index 545e8ad..f3fd1a2 100644
--- a/src/gallium/drivers/freedreno/freedreno_clear.c
+++ b/src/gallium/drivers/freedreno/freedreno_clear.c
@@ -54,7 +54,7 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
 {
 	struct fd_context *ctx = fd_context(pctx);
 	struct fd_ringbuffer *ring = ctx->ring;
-	struct pipe_framebuffer_state *fb = &ctx->framebuffer.base;
+	struct pipe_framebuffer_state *fb = &ctx->framebuffer;
 	uint32_t reg, colr = 0;
 
 	ctx->cleared |= buffers;
@@ -172,11 +172,6 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
 			fb->height));
 
 	OUT_PKT3(ring, CP_SET_CONSTANT, 2);
-	OUT_RING(ring, CP_REG(REG_RB_COLOR_INFO));
-	OUT_RING(ring, RB_COLOR_INFO_COLOR_SWAP(1) |
-			RB_COLOR_INFO_COLOR_FORMAT(fd_pipe2color(fb->cbufs[0]->format)));
-
-	OUT_PKT3(ring, CP_SET_CONSTANT, 2);
 	OUT_RING(ring, CP_REG(REG_RB_COLOR_MASK));
 	if (buffers & PIPE_CLEAR_COLOR) {
 		OUT_RING(ring, RB_COLOR_MASK_WRITE_RED |
diff --git a/src/gallium/drivers/freedreno/freedreno_context.c b/src/gallium/drivers/freedreno/freedreno_context.c
index cac10b7..4753f58 100644
--- a/src/gallium/drivers/freedreno/freedreno_context.c
+++ b/src/gallium/drivers/freedreno/freedreno_context.c
@@ -69,7 +69,7 @@ void
 fd_context_render(struct pipe_context *pctx)
 {
 	struct fd_context *ctx = fd_context(pctx);
-	struct pipe_framebuffer_state *fb = &ctx->framebuffer.base;
+	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
 
 	DBG("needs_flush: %d", ctx->needs_flush);
 
@@ -89,9 +89,9 @@ fd_context_render(struct pipe_context *pctx)
 	ctx->needs_flush = false;
 	ctx->cleared = ctx->restore = ctx->resolve = 0;
 
-	fd_resource(fb->cbufs[0]->texture)->dirty = false;
-	if (fb->zsbuf)
-		fd_resource(fb->zsbuf->texture)->dirty = false;
+	fd_resource(pfb->cbufs[0]->texture)->dirty = false;
+	if (pfb->zsbuf)
+		fd_resource(pfb->zsbuf->texture)->dirty = false;
 }
 
 static void
diff --git a/src/gallium/drivers/freedreno/freedreno_context.h b/src/gallium/drivers/freedreno/freedreno_context.h
index 6fff8f6..4ed3159 100644
--- a/src/gallium/drivers/freedreno/freedreno_context.h
+++ b/src/gallium/drivers/freedreno/freedreno_context.h
@@ -79,11 +79,13 @@ struct fd_vertexbuf_stateobj {
 	uint32_t dirty_mask;
 };
 
-struct fd_framebuffer_stateobj {
-	struct pipe_framebuffer_state base;
+struct fd_gmem_stateobj {
+	struct pipe_scissor_state scissor;
+	uint cpp;
+	uint16_t minx, miny;
 	uint16_t bin_h, nbins_y;
 	uint16_t bin_w, nbins_x;
-	uint32_t pa_su_sc_mode_cntl;
+	uint16_t width, height;
 };
 
 struct fd_context {
@@ -129,6 +131,17 @@ struct fd_context {
 	 */
 	struct pipe_scissor_state scissor;
 
+	/* Track the maximal bounds of the scissor of all the draws within a
+	 * batch.  Used at the tile rendering step (fd_gmem_render_tiles(),
+	 * mem2gmem/gmem2mem) to avoid needlessly moving data in/out of gmem.
+	 */
+	struct pipe_scissor_state max_scissor;
+
+	/* Current gmem/tiling configuration.. gets updated on render_tiles()
+	 * if out of date with current maximal-scissor/cpp:
+	 */
+	struct fd_gmem_stateobj gmem;
+
 	/* which state objects need to be re-emit'd: */
 	enum {
 		FD_DIRTY_BLEND       = (1 << 0),
@@ -163,7 +176,7 @@ struct fd_context {
 	struct pipe_blend_color blend_color;
 	struct pipe_stencil_ref stencil_ref;
 	unsigned sample_mask;
-	struct fd_framebuffer_stateobj framebuffer;
+	struct pipe_framebuffer_state framebuffer;
 	struct pipe_poly_stipple stipple;
 	struct pipe_viewport_state viewport;
 	struct fd_constbuf_stateobj constbuf[PIPE_SHADER_TYPES];
diff --git a/src/gallium/drivers/freedreno/freedreno_gmem.c b/src/gallium/drivers/freedreno/freedreno_gmem.c
index 52b6376..896e434 100644
--- a/src/gallium/drivers/freedreno/freedreno_gmem.c
+++ b/src/gallium/drivers/freedreno/freedreno_gmem.c
@@ -110,8 +110,7 @@ static void
 emit_gmem2mem(struct fd_context *ctx, struct fd_ringbuffer *ring,
 		uint32_t xoff, uint32_t yoff, uint32_t bin_w, uint32_t bin_h)
 {
-	struct fd_framebuffer_stateobj *fb = &ctx->framebuffer;
-	struct pipe_framebuffer_state *pfb = &fb->base;
+	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
 
 	fd_emit_vertex_bufs(ring, 0x9c, (struct fd_vertex_buf[]) {
 			{ .prsc = ctx->solid_vertexbuf, .size = 48 },
@@ -224,8 +223,7 @@ static void
 emit_mem2gmem(struct fd_context *ctx, struct fd_ringbuffer *ring,
 		uint32_t xoff, uint32_t yoff, uint32_t bin_w, uint32_t bin_h)
 {
-	struct fd_framebuffer_stateobj *fb = &ctx->framebuffer;
-	struct pipe_framebuffer_state *pfb = &fb->base;
+	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
 	float x0, y0, x1, y1;
 
 	fd_emit_vertex_bufs(ring, 0x9c, (struct fd_vertex_buf[]) {
@@ -328,50 +326,146 @@ emit_mem2gmem(struct fd_context *ctx, struct fd_ringbuffer *ring,
 	/* TODO blob driver seems to toss in a CACHE_FLUSH after each DRAW_INDX.. */
 }
 
+static void
+calculate_tiles(struct fd_context *ctx)
+{
+	struct fd_gmem_stateobj *gmem = &ctx->gmem;
+	struct pipe_scissor_state *scissor = &ctx->max_scissor;
+	uint32_t cpp = util_format_get_blocksize(ctx->framebuffer.cbufs[0]->format);
+	uint32_t gmem_size = ctx->screen->gmemsize_bytes;
+	uint32_t minx, miny, width, height;
+	uint32_t nbins_x = 1, nbins_y = 1;
+	uint32_t bin_w, bin_h;
+	uint32_t max_width = 992;
+
+	if ((gmem->cpp == cpp) &&
+			!memcmp(&gmem->scissor, scissor, sizeof(gmem->scissor))) {
+		/* everything is up-to-date */
+		return;
+	}
+
+	minx = scissor->minx & ~31; /* round down to multiple of 32 */
+	miny = scissor->miny & ~31;
+	width = scissor->maxx - minx;
+	height = scissor->maxy - miny;
+
+// TODO we probably could optimize this a bit if we know that
+// Z or stencil is not enabled for any of the draw calls..
+//	if (fd_stencil_enabled(ctx->zsa) || fd_depth_enabled(ctx->zsa)) {
+		gmem_size /= 2;
+		max_width = 256;
+//	}
+
+	bin_w = ALIGN(width, 32);
+	bin_h = ALIGN(height, 32);
+
+	/* first, find a bin width that satisfies the maximum width
+	 * restrictions:
+	 */
+	while (bin_w > max_width) {
+		nbins_x++;
+		bin_w = ALIGN(width / nbins_x, 32);
+	}
+
+	/* then find a bin height that satisfies the memory constraints:
+	 */
+	while ((bin_w * bin_h * cpp) > gmem_size) {
+		nbins_y++;
+		bin_h = ALIGN(height / nbins_y, 32);
+	}
+
+	DBG("using %d bins of size %dx%d", nbins_x*nbins_y, bin_w, bin_h);
+
+	gmem->scissor = *scissor;
+	gmem->cpp = cpp;
+	gmem->minx = minx;
+	gmem->miny = miny;
+	gmem->bin_h = bin_h;
+	gmem->bin_w = bin_w;
+	gmem->nbins_x = nbins_x;
+	gmem->nbins_y = nbins_y;
+	gmem->width = width;
+	gmem->height = height;
+}
+
 void
 fd_gmem_render_tiles(struct pipe_context *pctx)
 {
 	struct fd_context *ctx = fd_context(pctx);
-	struct fd_framebuffer_stateobj *fb = &ctx->framebuffer;
-	struct pipe_framebuffer_state *pfb = &fb->base;
-	struct fd_ringbuffer *ring;
-	uint32_t i, yoff = 0;
-	uint32_t timestamp;
-	ring = ctx->ring;
-
-	DBG("rendering %dx%d tiles (%s/%s)", fb->nbins_x, fb->nbins_y,
+	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
+	struct fd_gmem_stateobj *gmem = &ctx->gmem;
+	struct fd_ringbuffer *ring = ctx->ring;
+	enum rb_colorformatx colorformatx = fd_pipe2color(pfb->cbufs[0]->format);
+	uint32_t i, timestamp, yoff = 0;
+	uint32_t base, reg;
+
+	calculate_tiles(ctx);
+
+	/* this should be true because bin_w/bin_h should be multiples of 32: */
+	assert(((gmem->bin_w * gmem->bin_h) % 1024) == 0);
+
+	/* depth/stencil starts after color buffer in GMEM: */
+	base = (gmem->bin_w * gmem->bin_h) / 1024;
+
+	DBG("rendering %dx%d tiles (%s/%s)", gmem->nbins_x, gmem->nbins_y,
 			util_format_name(pfb->cbufs[0]->format),
 			pfb->zsbuf ? util_format_name(pfb->zsbuf->format) : "none");
 
 	/* mark the end of the clear/draw cmds before emitting per-tile cmds: */
 	fd_ringmarker_mark(ctx->draw_end);
 
-	for (i = 0; i < fb->nbins_y; i++) {
-		uint32_t j, xoff = 0;
-		uint32_t bin_h = fb->bin_h;
+	/* RB_SURFACE_INFO / RB_DEPTH_INFO can be emitted once per tile pass,
+	 * but RB_COLOR_INFO gets overwritten by gmem2mem and mem2gmem and so
+	 * needs to be emitted for each tile:
+	 */
+	OUT_PKT3(ring, CP_SET_CONSTANT, 4);
+	OUT_RING(ring, CP_REG(REG_RB_SURFACE_INFO));
+	OUT_RING(ring, gmem->bin_w);                 /* RB_SURFACE_INFO */
+	OUT_RING(ring, RB_COLOR_INFO_COLOR_SWAP(1) | /* RB_COLOR_INFO */
+			RB_COLOR_INFO_COLOR_FORMAT(colorformatx));
+	reg = RB_DEPTH_INFO_DEPTH_BASE(ALIGN(base, 4));
+	if (pfb->zsbuf)
+		reg |= RB_DEPTH_INFO_DEPTH_FORMAT(fd_pipe2depth(pfb->zsbuf->format));
+	OUT_RING(ring, reg);                         /* RB_DEPTH_INFO */
+
+	yoff= gmem->miny;
+	for (i = 0; i < gmem->nbins_y; i++) {
+		uint32_t j, xoff = gmem->minx;
+		uint32_t bh = gmem->bin_h;
 
 		/* clip bin height: */
-		bin_h = min(bin_h, pfb->height - yoff);
+		bh = min(bh, gmem->height - yoff);
 
-		for (j = 0; j < fb->nbins_x; j++) {
-			uint32_t bin_w = fb->bin_w;
+		for (j = 0; j < gmem->nbins_x; j++) {
+			uint32_t bw = gmem->bin_w;
 
 			/* clip bin width: */
-			bin_w = min(bin_w, pfb->width - xoff);
+			bw = min(bw, gmem->width - xoff);
 
 			DBG("bin_h=%d, yoff=%d, bin_w=%d, xoff=%d",
-					bin_h, yoff, bin_w, xoff);
+					bh, yoff, bw, xoff);
+
+			if ((i == 0) && (j == 0)) {
+				uint32_t reg;
 
-			fd_emit_framebuffer_state(ring, &ctx->framebuffer);
+
+			} else {
+
+			}
 
 			/* setup screen scissor for current tile (same for mem2gmem): */
 			OUT_PKT3(ring, CP_SET_CONSTANT, 3);
 			OUT_RING(ring, CP_REG(REG_PA_SC_SCREEN_SCISSOR_TL));
 			OUT_RING(ring, xy2d(0,0));           /* PA_SC_SCREEN_SCISSOR_TL */
-			OUT_RING(ring, xy2d(bin_w, bin_h));  /* PA_SC_SCREEN_SCISSOR_BR */
+			OUT_RING(ring, xy2d(bw, bh));        /* PA_SC_SCREEN_SCISSOR_BR */
 
 			if (ctx->restore)
-				emit_mem2gmem(ctx, ring, xoff, yoff, bin_w, bin_h);
+				emit_mem2gmem(ctx, ring, xoff, yoff, bw, bh);
+
+			OUT_PKT3(ring, CP_SET_CONSTANT, 2);
+			OUT_RING(ring, CP_REG(REG_RB_COLOR_INFO));
+			OUT_RING(ring, RB_COLOR_INFO_COLOR_SWAP(1) | /* RB_COLOR_INFO */
+					RB_COLOR_INFO_COLOR_FORMAT(colorformatx));
 
 			/* setup window scissor and offset for current tile (different
 			 * from mem2gmem):
@@ -389,12 +483,12 @@ fd_gmem_render_tiles(struct pipe_context *pctx)
 			OUT_RING(ring, 0x00000000);          /* PA_SC_WINDOW_OFFSET */
 
 			/* emit gmem2mem to transfer tile back to system memory: */
-			emit_gmem2mem(ctx, ring, xoff, yoff, bin_w, bin_h);
+			emit_gmem2mem(ctx, ring, xoff, yoff, bw, bh);
 
-			xoff += bin_w;
+			xoff += bw;
 		}
 
-		yoff += bin_h;
+		yoff += bh;
 	}
 
 	/* GPU executes starting from tile cmds, which IB back to draw cmds: */
@@ -409,6 +503,10 @@ fd_gmem_render_tiles(struct pipe_context *pctx)
 	if (pfb->zsbuf)
 		fd_resource(pfb->zsbuf->texture)->timestamp = timestamp;
 
+	/* reset maximal bounds: */
+	ctx->max_scissor.minx = ctx->max_scissor.miny = ~0;
+	ctx->max_scissor.maxx = ctx->max_scissor.maxy = 0;
+
 	/* Note that because the per-tile setup and mem2gmem/gmem2mem are emitted
 	 * after the draw/clear calls, but executed before, we need to preemptively
 	 * flag some state as dirty before the first draw/clear call.
@@ -431,61 +529,3 @@ fd_gmem_render_tiles(struct pipe_context *pctx)
 			FD_DIRTY_FRAGTEX |
 			FD_DIRTY_BLEND;
 }
-
-void
-fd_gmem_calculate_tiles(struct pipe_context *pctx)
-{
-	struct fd_context *ctx = fd_context(pctx);
-	struct fd_framebuffer_stateobj *fb = &ctx->framebuffer;
-	struct pipe_framebuffer_state *pfb = &fb->base;
-	uint32_t nbins_x = 1, nbins_y = 1;
-	uint32_t bin_w, bin_h;
-	uint32_t cpp = util_format_get_blocksize(pfb->cbufs[0]->format);
-	uint32_t gmem_size = ctx->screen->gmemsize_bytes;
-	uint32_t max_width = 992;
-
-// TODO we probably could optimize this a bit if we know that
-// Z or stencil is not enabled for any of the draw calls..
-//	if (fd_stencil_enabled(ctx->zsa) || fd_depth_enabled(ctx->zsa)) {
-		gmem_size /= 2;
-		max_width = 256;
-//	}
-
-	bin_w = ALIGN(pfb->width, 32);
-	bin_h = ALIGN(pfb->height, 32);
-
-	/* first, find a bin width that satisfies the maximum width
-	 * restrictions:
-	 */
-	while (bin_w > max_width) {
-		nbins_x++;
-		bin_w = ALIGN(pfb->width / nbins_x, 32);
-	}
-
-	/* then find a bin height that satisfies the memory constraints:
-	 */
-	while ((bin_w * bin_h * cpp) > gmem_size) {
-		nbins_y++;
-		bin_h = ALIGN(pfb->height / nbins_y, 32);
-	}
-
-	if ((nbins_x > 1) || (nbins_y > 1)) {
-		fb->pa_su_sc_mode_cntl |= PA_SU_SC_MODE_CNTL_VTX_WINDOW_OFFSET_ENABLE;
-	} else {
-		fb->pa_su_sc_mode_cntl &= ~PA_SU_SC_MODE_CNTL_VTX_WINDOW_OFFSET_ENABLE;
-	}
-
-	DBG("using %d bins of size %dx%d", nbins_x*nbins_y, bin_w, bin_h);
-
-//if we use hw binning, tile sizes (in multiple of 32) need to
-//fit in 5 bits.. for now don't care because we aren't using
-//that:
-//	assert(!(bin_h/32 & ~0x1f));
-//	assert(!(bin_w/32 & ~0x1f));
-
-	fb->nbins_x = nbins_x;
-	fb->nbins_y = nbins_y;
-	fb->bin_w = bin_w;
-	fb->bin_h = bin_h;
-
-}
diff --git a/src/gallium/drivers/freedreno/freedreno_gmem.h b/src/gallium/drivers/freedreno/freedreno_gmem.h
index 7b46f6b..0c978a4 100644
--- a/src/gallium/drivers/freedreno/freedreno_gmem.h
+++ b/src/gallium/drivers/freedreno/freedreno_gmem.h
@@ -32,6 +32,5 @@
 #include "pipe/p_context.h"
 
 void fd_gmem_render_tiles(struct pipe_context *pctx);
-void fd_gmem_calculate_tiles(struct pipe_context *pctx);
 
 #endif /* FREEDRENO_GMEM_H_ */
diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c
index 5159003..d89650a 100644
--- a/src/gallium/drivers/freedreno/freedreno_resource.c
+++ b/src/gallium/drivers/freedreno/freedreno_resource.c
@@ -260,7 +260,7 @@ fd_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
 	util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->zsa);
 	util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
 	util_blitter_save_sample_mask(ctx->blitter, ctx->sample_mask);
-	util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer.base);
+	util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer);
 	util_blitter_save_fragment_sampler_states(ctx->blitter,
 			ctx->fragtex.num_samplers,
 			(void **)ctx->fragtex.samplers);
diff --git a/src/gallium/drivers/freedreno/freedreno_state.c b/src/gallium/drivers/freedreno/freedreno_state.c
index 529e246..fcb04da 100644
--- a/src/gallium/drivers/freedreno/freedreno_state.c
+++ b/src/gallium/drivers/freedreno/freedreno_state.c
@@ -115,7 +115,7 @@ fd_set_framebuffer_state(struct pipe_context *pctx,
 		const struct pipe_framebuffer_state *framebuffer)
 {
 	struct fd_context *ctx = fd_context(pctx);
-	struct pipe_framebuffer_state *cso = &ctx->framebuffer.base;
+	struct pipe_framebuffer_state *cso = &ctx->framebuffer;
 	unsigned i;
 
 	DBG("%d: cbufs[0]=%p, zsbuf=%p", ctx->needs_flush,
@@ -125,7 +125,7 @@ fd_set_framebuffer_state(struct pipe_context *pctx,
 
 	for (i = 0; i < framebuffer->nr_cbufs; i++)
 		pipe_surface_reference(&cso->cbufs[i], framebuffer->cbufs[i]);
-	for (; i < ctx->framebuffer.base.nr_cbufs; i++)
+	for (; i < ctx->framebuffer.nr_cbufs; i++)
 		pipe_surface_reference(&cso->cbufs[i], NULL);
 
 	cso->nr_cbufs = framebuffer->nr_cbufs;
@@ -134,9 +134,6 @@ fd_set_framebuffer_state(struct pipe_context *pctx,
 
 	pipe_surface_reference(&cso->zsbuf, framebuffer->zsbuf);
 
-	if (cso->nr_cbufs > 0)
-		fd_gmem_calculate_tiles(pctx);
-
 	ctx->dirty |= FD_DIRTY_FRAMEBUFFER;
 }
 
@@ -355,30 +352,6 @@ fd_emit_vertex_bufs(struct fd_ringbuffer *ring, uint32_t val,
 }
 
 void
-fd_emit_framebuffer_state(struct fd_ringbuffer *ring,
-		struct fd_framebuffer_stateobj *fb)
-{
-	struct pipe_framebuffer_state *pfb = &fb->base;
-	uint32_t reg, base;
-
-	/* this should be true because bin_w/bin_h should be multiples of 32: */
-	assert(((fb->bin_w * fb->bin_h) % 1024) == 0);
-
-	/* depth/stencil starts after color buffer in GMEM: */
-	base = (fb->bin_w * fb->bin_h) / 1024;
-
-	OUT_PKT3(ring, CP_SET_CONSTANT, 4);
-	OUT_RING(ring, CP_REG(REG_RB_SURFACE_INFO));
-	OUT_RING(ring, fb->bin_w);                   /* RB_SURFACE_INFO */
-	OUT_RING(ring, RB_COLOR_INFO_COLOR_SWAP(1) | /* RB_COLOR_INFO */
-			RB_COLOR_INFO_COLOR_FORMAT(fd_pipe2color(pfb->cbufs[0]->format)));
-	reg = RB_DEPTH_INFO_DEPTH_BASE(ALIGN(base, 4));
-	if (pfb->zsbuf)
-		reg |= RB_DEPTH_INFO_DEPTH_FORMAT(fd_pipe2depth(pfb->zsbuf->format));
-	OUT_RING(ring, reg);                         /* RB_DEPTH_INFO */
-}
-
-void
 fd_state_emit(struct pipe_context *pctx, uint32_t dirty)
 {
 	struct fd_context *ctx = fd_context(pctx);
@@ -418,7 +391,7 @@ fd_state_emit(struct pipe_context *pctx, uint32_t dirty)
 		OUT_RING(ring, CP_REG(REG_PA_CL_CLIP_CNTL));
 		OUT_RING(ring, ctx->rasterizer->pa_cl_clip_cntl);
 		OUT_RING(ring, ctx->rasterizer->pa_su_sc_mode_cntl |
-				ctx->framebuffer.pa_su_sc_mode_cntl);
+				PA_SU_SC_MODE_CNTL_VTX_WINDOW_OFFSET_ENABLE);
 
 		OUT_PKT3(ring, CP_SET_CONSTANT, 5);
 		OUT_RING(ring, CP_REG(REG_PA_SU_POINT_SIZE));
@@ -436,9 +409,6 @@ fd_state_emit(struct pipe_context *pctx, uint32_t dirty)
 		OUT_RING(ring, f2d(1.0));                /* PA_CL_GB_HORZ_DISC_ADJ */
 	}
 
-	if (dirty & FD_DIRTY_FRAMEBUFFER)
-		fd_emit_framebuffer_state(ring, &ctx->framebuffer);
-
 	if (dirty & FD_DIRTY_SCISSOR) {
 		OUT_PKT3(ring, CP_SET_CONSTANT, 3);
 		OUT_RING(ring, CP_REG(REG_PA_SC_WINDOW_SCISSOR_TL));
@@ -446,6 +416,11 @@ fd_state_emit(struct pipe_context *pctx, uint32_t dirty)
 				ctx->scissor.miny));
 		OUT_RING(ring, xy2d(ctx->scissor.maxx,   /* PA_SC_WINDOW_SCISSOR_BR */
 				ctx->scissor.maxy));
+
+		ctx->max_scissor.minx = min(ctx->max_scissor.minx, ctx->scissor.minx);
+		ctx->max_scissor.miny = min(ctx->max_scissor.miny, ctx->scissor.miny);
+		ctx->max_scissor.maxx = max(ctx->max_scissor.maxx, ctx->scissor.maxx);
+		ctx->max_scissor.maxy = max(ctx->max_scissor.maxy, ctx->scissor.maxy);
 	}
 
 	if (dirty & FD_DIRTY_VIEWPORT) {
diff --git a/src/gallium/drivers/freedreno/freedreno_state.h b/src/gallium/drivers/freedreno/freedreno_state.h
index 4e68448..422f0ce 100644
--- a/src/gallium/drivers/freedreno/freedreno_state.h
+++ b/src/gallium/drivers/freedreno/freedreno_state.h
@@ -45,8 +45,6 @@ struct fd_vertex_buf {
 
 void fd_emit_vertex_bufs(struct fd_ringbuffer *ring, uint32_t val,
 		struct fd_vertex_buf *vbufs, uint32_t n);
-void fd_emit_framebuffer_state(struct fd_ringbuffer *ring,
-		struct fd_framebuffer_stateobj *fb);
 void fd_state_emit(struct pipe_context *pctx, uint32_t dirty);
 void fd_state_emit_setup(struct pipe_context *pctx);
 
diff --git a/src/gallium/drivers/freedreno/freedreno_vbo.c b/src/gallium/drivers/freedreno/freedreno_vbo.c
index fc33539..e992b8c 100644
--- a/src/gallium/drivers/freedreno/freedreno_vbo.c
+++ b/src/gallium/drivers/freedreno/freedreno_vbo.c
@@ -141,7 +141,7 @@ static void
 fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 {
 	struct fd_context *ctx = fd_context(pctx);
-	struct pipe_framebuffer_state *fb = &ctx->framebuffer.base;
+	struct pipe_framebuffer_state *fb = &ctx->framebuffer;
 	struct fd_ringbuffer *ring = ctx->ring;
 	struct fd_bo *idx_bo = NULL;
 	enum pc_di_index_size idx_type = INDEX_SIZE_IGN;
@@ -149,6 +149,12 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 	uint32_t idx_size, idx_offset;
 	unsigned buffers;
 
+	/* if we supported transform feedback, we'd have to disable this: */
+	if (((ctx->scissor.maxx - ctx->scissor.minx) *
+			(ctx->scissor.maxy - ctx->scissor.miny)) == 0) {
+		return;
+	}
+
 	ctx->needs_flush = true;
 
 	if (info->indexed) {




More information about the mesa-commit mailing list