Mesa (master): freedreno: prepare for hw binning

Rob Clark robclark at kemper.freedesktop.org
Thu Dec 26 17:15:40 UTC 2013


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

Author: Rob Clark <robclark at freedesktop.org>
Date:   Fri Dec 20 20:48:18 2013 -0500

freedreno: prepare for hw binning

Actually assign VSC_PIPE's properly, which will be needed for tiling.
And introduce fd_tile for per-tile state (including the assignment of
tile to VSC_PIPE).  This gives us the proper pipe setup that we'll
need for hw binning pass, and also cleans things up a bit by not having
to pass so many parameters around.  And will also make it easier to
introduce different tiling patterns (since we may no longer render
tiles in a simple left-to-right top-to-bottom pattern).

Signed-off-by: Rob Clark <robclark at freedesktop.org>

---

 src/gallium/drivers/freedreno/a2xx/fd2_gmem.c     |   38 ++++----
 src/gallium/drivers/freedreno/a3xx/fd3_context.c  |    4 -
 src/gallium/drivers/freedreno/a3xx/fd3_context.h  |    7 +-
 src/gallium/drivers/freedreno/a3xx/fd3_gmem.c     |   73 +++++++--------
 src/gallium/drivers/freedreno/a3xx/fd3_program.c  |   27 +-----
 src/gallium/drivers/freedreno/freedreno_context.c |    8 ++
 src/gallium/drivers/freedreno/freedreno_context.h |   24 ++---
 src/gallium/drivers/freedreno/freedreno_gmem.c    |   98 +++++++++++++++------
 src/gallium/drivers/freedreno/freedreno_gmem.h    |   22 +++++
 9 files changed, 159 insertions(+), 142 deletions(-)

diff --git a/src/gallium/drivers/freedreno/a2xx/fd2_gmem.c b/src/gallium/drivers/freedreno/a2xx/fd2_gmem.c
index 1fcb766..c494bf1 100644
--- a/src/gallium/drivers/freedreno/a2xx/fd2_gmem.c
+++ b/src/gallium/drivers/freedreno/a2xx/fd2_gmem.c
@@ -95,8 +95,7 @@ emit_gmem2mem_surf(struct fd_context *ctx, uint32_t base,
 }
 
 static void
-fd2_emit_tile_gmem2mem(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-		uint32_t bin_w, uint32_t bin_h)
+fd2_emit_tile_gmem2mem(struct fd_context *ctx, struct fd_tile *tile)
 {
 	struct fd2_context *fd2_ctx = fd2_context(ctx);
 	struct fd_ringbuffer *ring = ctx->ring;
@@ -157,11 +156,11 @@ fd2_emit_tile_gmem2mem(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
 
 	OUT_PKT3(ring, CP_SET_CONSTANT, 2);
 	OUT_RING(ring, CP_REG(REG_A2XX_RB_COPY_DEST_OFFSET));
-	OUT_RING(ring, A2XX_RB_COPY_DEST_OFFSET_X(xoff) |
-			A2XX_RB_COPY_DEST_OFFSET_Y(yoff));
+	OUT_RING(ring, A2XX_RB_COPY_DEST_OFFSET_X(tile->xoff) |
+			A2XX_RB_COPY_DEST_OFFSET_Y(tile->yoff));
 
 	if (ctx->resolve & (FD_BUFFER_DEPTH | FD_BUFFER_STENCIL))
-		emit_gmem2mem_surf(ctx, bin_w * bin_h, pfb->zsbuf);
+		emit_gmem2mem_surf(ctx, tile->bin_w * tile->bin_h, pfb->zsbuf);
 
 	if (ctx->resolve & FD_BUFFER_COLOR)
 		emit_gmem2mem_surf(ctx, 0, pfb->cbufs[0]);
@@ -218,12 +217,13 @@ emit_mem2gmem_surf(struct fd_context *ctx, uint32_t base,
 }
 
 static void
-fd2_emit_tile_mem2gmem(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-		uint32_t bin_w, uint32_t bin_h)
+fd2_emit_tile_mem2gmem(struct fd_context *ctx, struct fd_tile *tile)
 {
 	struct fd2_context *fd2_ctx = fd2_context(ctx);
 	struct fd_ringbuffer *ring = ctx->ring;
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
+	unsigned bin_w = tile->bin_w;
+	unsigned bin_h = tile->bin_h;
 	float x0, y0, x1, y1;
 
 	fd2_emit_vertex_bufs(ring, 0x9c, (struct fd2_vertex_buf[]) {
@@ -232,10 +232,10 @@ fd2_emit_tile_mem2gmem(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
 		}, 2);
 
 	/* write texture coordinates to vertexbuf: */
-	x0 = ((float)xoff) / ((float)pfb->width);
-	x1 = ((float)xoff + bin_w) / ((float)pfb->width);
-	y0 = ((float)yoff) / ((float)pfb->height);
-	y1 = ((float)yoff + bin_h) / ((float)pfb->height);
+	x0 = ((float)tile->xoff) / ((float)pfb->width);
+	x1 = ((float)tile->xoff + bin_w) / ((float)pfb->width);
+	y0 = ((float)tile->yoff) / ((float)pfb->height);
+	y1 = ((float)tile->yoff + bin_h) / ((float)pfb->height);
 	OUT_PKT3(ring, CP_MEM_WRITE, 9);
 	OUT_RELOC(ring, fd_resource(fd2_ctx->solid_vertexbuf)->bo, 0x60, 0, 0);
 	OUT_RING(ring, fui(x0));
@@ -349,8 +349,7 @@ fd2_emit_tile_init(struct fd_context *ctx)
 
 /* before mem2gmem */
 static void
-fd2_emit_tile_prep(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-		uint32_t bin_w, uint32_t bin_h)
+fd2_emit_tile_prep(struct fd_context *ctx, struct fd_tile *tile)
 {
 	struct fd_ringbuffer *ring = ctx->ring;
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
@@ -364,14 +363,15 @@ fd2_emit_tile_prep(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
 	/* setup screen scissor for current tile (same for mem2gmem): */
 	OUT_PKT3(ring, CP_SET_CONSTANT, 3);
 	OUT_RING(ring, CP_REG(REG_A2XX_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, A2XX_PA_SC_SCREEN_SCISSOR_TL_X(0) |
+			A2XX_PA_SC_SCREEN_SCISSOR_TL_Y(0));
+	OUT_RING(ring, A2XX_PA_SC_SCREEN_SCISSOR_BR_X(tile->bin_w) |
+			A2XX_PA_SC_SCREEN_SCISSOR_BR_Y(tile->bin_h));
 }
 
 /* before IB to rendering cmds: */
 static void
-fd2_emit_tile_renderprep(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-		uint32_t bin_w, uint32_t bin_h)
+fd2_emit_tile_renderprep(struct fd_context *ctx, struct fd_tile *tile)
 {
 	struct fd_ringbuffer *ring = ctx->ring;
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
@@ -387,8 +387,8 @@ fd2_emit_tile_renderprep(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
 	 */
 	OUT_PKT3(ring, CP_SET_CONSTANT, 2);
 	OUT_RING(ring, CP_REG(REG_A2XX_PA_SC_WINDOW_OFFSET));
-	OUT_RING(ring, A2XX_PA_SC_WINDOW_OFFSET_X(-xoff) |
-			A2XX_PA_SC_WINDOW_OFFSET_Y(-yoff));
+	OUT_RING(ring, A2XX_PA_SC_WINDOW_OFFSET_X(-tile->xoff) |
+			A2XX_PA_SC_WINDOW_OFFSET_Y(-tile->yoff));
 }
 
 void
diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_context.c b/src/gallium/drivers/freedreno/a3xx/fd3_context.c
index 13f91e9..2346719 100644
--- a/src/gallium/drivers/freedreno/a3xx/fd3_context.c
+++ b/src/gallium/drivers/freedreno/a3xx/fd3_context.c
@@ -47,7 +47,6 @@ fd3_context_destroy(struct pipe_context *pctx)
 	fd_bo_del(fd3_ctx->vs_pvt_mem);
 	fd_bo_del(fd3_ctx->fs_pvt_mem);
 	fd_bo_del(fd3_ctx->vsc_size_mem);
-	fd_bo_del(fd3_ctx->vsc_pipe_mem);
 
 	pipe_resource_reference(&fd3_ctx->solid_vbuf, NULL);
 	pipe_resource_reference(&fd3_ctx->blit_texcoord_vbuf, NULL);
@@ -129,9 +128,6 @@ fd3_context_create(struct pipe_screen *pscreen, void *priv)
 	fd3_ctx->vsc_size_mem = fd_bo_new(screen->dev, 0x1000,
 			DRM_FREEDRENO_GEM_TYPE_KMEM);
 
-	fd3_ctx->vsc_pipe_mem = fd_bo_new(screen->dev, 0x40000,
-			DRM_FREEDRENO_GEM_TYPE_KMEM);
-
 	fd3_ctx->solid_vbuf = create_solid_vertexbuf(pctx);
 	fd3_ctx->blit_texcoord_vbuf = create_blit_texcoord_vertexbuf(pctx);
 
diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_context.h b/src/gallium/drivers/freedreno/a3xx/fd3_context.h
index 3829ab5..3599fe1 100644
--- a/src/gallium/drivers/freedreno/a3xx/fd3_context.h
+++ b/src/gallium/drivers/freedreno/a3xx/fd3_context.h
@@ -38,14 +38,11 @@ struct fd3_context {
 
 	struct fd_bo *vs_pvt_mem, *fs_pvt_mem;
 
-	/* not sure how big this actually needs to be.. the blob driver
-	 * combines it w/ the solid_vertexbuf, we could probably do the
-	 * same to save an extra bo allocation..
+	/* This only needs to be 4 * num_of_pipes bytes (ie. 32 bytes).  We
+	 * could combine it with another allocation.
 	 */
 	struct fd_bo *vsc_size_mem;
 
-	struct fd_bo *vsc_pipe_mem;
-
 	/* vertex buf used for clear/gmem->mem vertices, and mem->gmem
 	 * vertices:
 	 */
diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c b/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c
index 7be0b68..4a5a241 100644
--- a/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c
+++ b/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c
@@ -134,8 +134,7 @@ emit_gmem2mem_surf(struct fd_context *ctx,
 }
 
 static void
-fd3_emit_tile_gmem2mem(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-		uint32_t bin_w, uint32_t bin_h)
+fd3_emit_tile_gmem2mem(struct fd_context *ctx, struct fd_tile *tile)
 {
 	struct fd3_context *fd3_ctx = fd3_context(ctx);
 	struct fd_ringbuffer *ring = ctx->ring;
@@ -256,21 +255,22 @@ emit_mem2gmem_surf(struct fd_context *ctx, uint32_t base,
 }
 
 static void
-fd3_emit_tile_mem2gmem(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-		uint32_t bin_w, uint32_t bin_h)
+fd3_emit_tile_mem2gmem(struct fd_context *ctx, struct fd_tile *tile)
 {
 	struct fd3_context *fd3_ctx = fd3_context(ctx);
 	struct fd_gmem_stateobj *gmem = &ctx->gmem;
 	struct fd_ringbuffer *ring = ctx->ring;
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
 	float x0, y0, x1, y1;
+	unsigned bin_w = tile->bin_w;
+	unsigned bin_h = tile->bin_h;
 	unsigned i;
 
 	/* write texture coordinates to vertexbuf: */
-	x0 = ((float)xoff) / ((float)pfb->width);
-	x1 = ((float)xoff + bin_w) / ((float)pfb->width);
-	y0 = ((float)yoff) / ((float)pfb->height);
-	y1 = ((float)yoff + bin_h) / ((float)pfb->height);
+	x0 = ((float)tile->xoff) / ((float)pfb->width);
+	x1 = ((float)tile->xoff + bin_w) / ((float)pfb->width);
+	y0 = ((float)tile->yoff) / ((float)pfb->height);
+	y1 = ((float)tile->yoff + bin_h) / ((float)pfb->height);
 
 	OUT_PKT3(ring, CP_MEM_WRITE, 5);
 	OUT_RELOC(ring, fd_resource(fd3_ctx->blit_texcoord_vbuf)->bo, 0, 0, 0);
@@ -384,29 +384,23 @@ static void
 update_vsc_pipe(struct fd_context *ctx)
 {
 	struct fd_ringbuffer *ring = ctx->ring;
-	struct fd_gmem_stateobj *gmem = &ctx->gmem;
-	struct fd_bo *bo = fd3_context(ctx)->vsc_pipe_mem;
 	int i;
 
-	/* since we aren't using binning, just try to assign all bins
-	 * to same pipe for now:
-	 */
-	OUT_PKT0(ring, REG_A3XX_VSC_PIPE(0), 3);
-	OUT_RING(ring, A3XX_VSC_PIPE_CONFIG_X(0) |
-			A3XX_VSC_PIPE_CONFIG_Y(0) |
-			A3XX_VSC_PIPE_CONFIG_W(gmem->nbins_x) |
-			A3XX_VSC_PIPE_CONFIG_H(gmem->nbins_y));
-	OUT_RELOC(ring, bo, 0, 0, 0);           /* VSC_PIPE[0].DATA_ADDRESS */
-	OUT_RING(ring, fd_bo_size(bo) - 32);    /* VSC_PIPE[0].DATA_LENGTH */
-
-	for (i = 1; i < 8; i++) {
-		OUT_PKT0(ring, REG_A3XX_VSC_PIPE(i), 3);
-		OUT_RING(ring, A3XX_VSC_PIPE_CONFIG_X(0) |
-				A3XX_VSC_PIPE_CONFIG_Y(0) |
-				A3XX_VSC_PIPE_CONFIG_W(0) |
-				A3XX_VSC_PIPE_CONFIG_H(0));
-		OUT_RING(ring, 0x00000000);         /* VSC_PIPE[i].DATA_ADDRESS */
-		OUT_RING(ring, 0x00000000);         /* VSC_PIPE[i].DATA_LENGTH */
+	for (i = 0; i < 8; i++) {
+		struct fd_vsc_pipe *pipe = &ctx->pipe[i];
+
+		if (!pipe->bo) {
+			pipe->bo = fd_bo_new(ctx->screen->dev, 0x40000,
+					DRM_FREEDRENO_GEM_TYPE_KMEM);
+		}
+
+		OUT_PKT0(ring, REG_A3XX_VSC_PIPE(0), 3);
+		OUT_RING(ring, A3XX_VSC_PIPE_CONFIG_X(pipe->x) |
+				A3XX_VSC_PIPE_CONFIG_Y(pipe->y) |
+				A3XX_VSC_PIPE_CONFIG_W(pipe->w) |
+				A3XX_VSC_PIPE_CONFIG_H(pipe->h));
+		OUT_RELOC(ring, pipe->bo, 0, 0, 0);        /* VSC_PIPE[i].DATA_ADDRESS */
+		OUT_RING(ring, fd_bo_size(pipe->bo) - 32); /* VSC_PIPE[i].DATA_LENGTH */
 	}
 }
 
@@ -465,16 +459,12 @@ fd3_emit_tile_init(struct fd_context *ctx)
 	OUT_RING(ring, A3XX_VSC_BIN_SIZE_WIDTH(gmem->bin_w) |
 			A3XX_VSC_BIN_SIZE_HEIGHT(gmem->bin_h));
 
-	/* TODO we only need to do this if gmem stateobj changes.. or in
-	 * particular if the # of bins changes..
-	 */
 	update_vsc_pipe(ctx);
 }
 
 /* before mem2gmem */
 static void
-fd3_emit_tile_prep(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-		uint32_t bin_w, uint32_t bin_h)
+fd3_emit_tile_prep(struct fd_context *ctx, struct fd_tile *tile)
 {
 	struct fd_ringbuffer *ring = ctx->ring;
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
@@ -506,17 +496,16 @@ fd3_emit_tile_prep(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
 
 /* before IB to rendering cmds: */
 static void
-fd3_emit_tile_renderprep(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-		uint32_t bin_w, uint32_t bin_h)
+fd3_emit_tile_renderprep(struct fd_context *ctx, struct fd_tile *tile)
 {
 	struct fd_ringbuffer *ring = ctx->ring;
 	struct fd_gmem_stateobj *gmem = &ctx->gmem;
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
 
-	uint32_t x1 = xoff;
-	uint32_t y1 = yoff;
-	uint32_t x2 = xoff + bin_w - 1;
-	uint32_t y2 = yoff + bin_h - 1;
+	uint32_t x1 = tile->xoff;
+	uint32_t y1 = tile->yoff;
+	uint32_t x2 = tile->xoff + tile->bin_w - 1;
+	uint32_t y2 = tile->yoff + tile->bin_h - 1;
 
 	OUT_PKT3(ring, CP_SET_BIN, 3);
 	OUT_RING(ring, 0x00000000);
@@ -531,8 +520,8 @@ fd3_emit_tile_renderprep(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
 
 	/* setup scissor/offset for current tile: */
 	OUT_PKT0(ring, REG_A3XX_RB_WINDOW_OFFSET, 1);
-	OUT_RING(ring, A3XX_RB_WINDOW_OFFSET_X(xoff) |
-			A3XX_RB_WINDOW_OFFSET_Y(yoff));
+	OUT_RING(ring, A3XX_RB_WINDOW_OFFSET_X(tile->xoff) |
+			A3XX_RB_WINDOW_OFFSET_Y(tile->yoff));
 
 	OUT_PKT0(ring, REG_A3XX_GRAS_SC_SCREEN_SCISSOR_TL, 2);
 	OUT_RING(ring, A3XX_GRAS_SC_SCREEN_SCISSOR_TL_X(x1) |
diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_program.c b/src/gallium/drivers/freedreno/a3xx/fd3_program.c
index 17659af..c02b14c 100644
--- a/src/gallium/drivers/freedreno/a3xx/fd3_program.c
+++ b/src/gallium/drivers/freedreno/a3xx/fd3_program.c
@@ -266,17 +266,6 @@ fd3_program_emit(struct fd_ringbuffer *ring,
 			// XXX sometimes 0, sometimes 1:
 			A3XX_SP_SP_CTRL_REG_LOMODE(1));
 
-	/* emit unknown sequence of perfcounter disables that the blob
-	 * emits as part of the program state..
-	 */
-	for (i = 0; i < 6; i++) {
-		OUT_PKT0(ring, REG_A3XX_SP_PERFCOUNTER0_SELECT, 1);
-		OUT_RING(ring, 0x00000000);    /* SP_PERFCOUNTER0_SELECT */
-
-		OUT_PKT0(ring, REG_A3XX_SP_PERFCOUNTER4_SELECT, 1);
-		OUT_RING(ring, 0x00000000);    /* SP_PERFCOUNTER4_SELECT */
-	}
-
 	OUT_PKT0(ring, REG_A3XX_SP_VS_LENGTH_REG, 1);
 	OUT_RING(ring, A3XX_SP_VS_LENGTH_REG_SHADERLENGTH(vp->instrlen));
 
@@ -329,22 +318,10 @@ fd3_program_emit(struct fd_ringbuffer *ring,
 		OUT_RING(ring, reg);
 	}
 
-#if 0
-	/* for some reason, when I write SP_{VS,FS}_OBJ_START_REG I get:
-[  666.663665] kgsl kgsl-3d0: |a3xx_err_callback| RBBM | AHB bus error | READ | addr=201 | ports=1:3
-[  666.664001] kgsl kgsl-3d0: |a3xx_err_callback| ringbuffer AHB error interrupt
-[  670.680909] kgsl kgsl-3d0: |adreno_idle| spun too long waiting for RB to idle
-[  670.681062] kgsl kgsl-3d0: |kgsl-3d0| Dump Started
-[  670.681123] kgsl kgsl-3d0: POWER: FLAGS = 00000007 | ACTIVE POWERLEVEL = 00000001
-[  670.681214] kgsl kgsl-3d0: POWER: INTERVAL TIMEOUT = 0000000A
-[  670.681367] kgsl kgsl-3d0: GRP_CLK = 325000000
-[  670.681489] kgsl kgsl-3d0: BUS CLK = 0
-	 */
 	OUT_PKT0(ring, REG_A3XX_SP_VS_OBJ_OFFSET_REG, 2);
 	OUT_RING(ring, A3XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(0) |
 			A3XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET(0));
 	OUT_RELOC(ring, vp->bo, 0, 0, 0);  /* SP_VS_OBJ_START_REG */
-#endif
 
 	OUT_PKT0(ring, REG_A3XX_SP_FS_LENGTH_REG, 1);
 	OUT_RING(ring, A3XX_SP_FS_LENGTH_REG_SHADERLENGTH(fp->instrlen));
@@ -364,12 +341,10 @@ fd3_program_emit(struct fd_ringbuffer *ring,
 			A3XX_SP_FS_CTRL_REG1_CONSTFOOTPRINT(MAX2(fsi->max_const, 0)) |
 			A3XX_SP_FS_CTRL_REG1_HALFPRECVAROFFSET(63));
 
-#if 0
 	OUT_PKT0(ring, REG_A3XX_SP_FS_OBJ_OFFSET_REG, 2);
 	OUT_RING(ring, A3XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(128) |
-			A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(128 - fp->instrlen));
+			A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(0));
 	OUT_RELOC(ring, fp->bo, 0, 0, 0);  /* SP_FS_OBJ_START_REG */
-#endif
 
 	OUT_PKT0(ring, REG_A3XX_SP_FS_FLAT_SHAD_MODE_REG_0, 2);
 	OUT_RING(ring, 0x00000000);        /* SP_FS_FLAT_SHAD_MODE_REG_0 */
diff --git a/src/gallium/drivers/freedreno/freedreno_context.c b/src/gallium/drivers/freedreno/freedreno_context.c
index ddb8a0b..c959ccf 100644
--- a/src/gallium/drivers/freedreno/freedreno_context.c
+++ b/src/gallium/drivers/freedreno/freedreno_context.c
@@ -117,6 +117,7 @@ void
 fd_context_destroy(struct pipe_context *pctx)
 {
 	struct fd_context *ctx = fd_context(pctx);
+	unsigned i;
 
 	DBG("");
 
@@ -130,6 +131,13 @@ fd_context_destroy(struct pipe_context *pctx)
 	fd_ringmarker_del(ctx->draw_end);
 	fd_ringbuffer_del(ctx->ring);
 
+	for (i = 0; i < ARRAY_SIZE(ctx->pipe); i++) {
+		struct fd_vsc_pipe *pipe = &ctx->pipe[i];
+		if (!pipe->bo)
+			break;
+		fd_bo_del(pipe->bo);
+	}
+
 	FREE(ctx);
 }
 
diff --git a/src/gallium/drivers/freedreno/freedreno_context.h b/src/gallium/drivers/freedreno/freedreno_context.h
index d3a01fc..db37f9c 100644
--- a/src/gallium/drivers/freedreno/freedreno_context.h
+++ b/src/gallium/drivers/freedreno/freedreno_context.h
@@ -37,6 +37,7 @@
 #include "util/u_string.h"
 
 #include "freedreno_screen.h"
+#include "freedreno_gmem.h"
 
 struct fd_vertex_stateobj;
 
@@ -80,15 +81,6 @@ struct fd_vertex_stateobj {
 	unsigned num_elements;
 };
 
-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;
-	uint16_t width, height;
-};
-
 struct fd_context {
 	struct pipe_context base;
 
@@ -176,6 +168,8 @@ struct fd_context {
 	 * if out of date with current maximal-scissor/cpp:
 	 */
 	struct fd_gmem_stateobj gmem;
+	struct fd_vsc_pipe      pipe[8];
+	struct fd_tile          tile[64];
 
 	/* which state objects need to be re-emit'd: */
 	enum {
@@ -221,14 +215,10 @@ struct fd_context {
 
 	/* GMEM/tile handling fxns: */
 	void (*emit_tile_init)(struct fd_context *ctx);
-	void (*emit_tile_prep)(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-			uint32_t bin_w, uint32_t bin_h);
-	void (*emit_tile_mem2gmem)(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-			uint32_t bin_w, uint32_t bin_h);
-	void (*emit_tile_renderprep)(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-			uint32_t bin_w, uint32_t bin_h);
-	void (*emit_tile_gmem2mem)(struct fd_context *ctx, uint32_t xoff, uint32_t yoff,
-			uint32_t bin_w, uint32_t bin_h);
+	void (*emit_tile_prep)(struct fd_context *ctx, struct fd_tile *tile);
+	void (*emit_tile_mem2gmem)(struct fd_context *ctx, struct fd_tile *tile);
+	void (*emit_tile_renderprep)(struct fd_context *ctx, struct fd_tile *tile);
+	void (*emit_tile_gmem2mem)(struct fd_context *ctx, struct fd_tile *tile);
 
 	/* optional, for GMEM bypass: */
 	void (*emit_sysmem_prep)(struct fd_context *ctx);
diff --git a/src/gallium/drivers/freedreno/freedreno_gmem.c b/src/gallium/drivers/freedreno/freedreno_gmem.c
index 8455b73..68b4eb6 100644
--- a/src/gallium/drivers/freedreno/freedreno_gmem.c
+++ b/src/gallium/drivers/freedreno/freedreno_gmem.c
@@ -78,6 +78,7 @@ calculate_tiles(struct fd_context *ctx)
 	uint32_t bin_w, bin_h;
 	uint32_t max_width = 992;
 	uint32_t cpp = 4;
+	uint32_t i, j, t, p, n, xoff, yoff;
 
 	if (pfb->cbufs[0])
 		cpp = util_format_get_blocksize(pfb->cbufs[0]->format);
@@ -129,57 +130,96 @@ calculate_tiles(struct fd_context *ctx)
 
 	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;
-}
 
-static void
-render_tiles(struct fd_context *ctx)
-{
-	struct fd_gmem_stateobj *gmem = &ctx->gmem;
-	uint32_t i, yoff = gmem->miny;
+	/* Assign tiles and pipes:
+	 * NOTE we currently take a rather simplistic approach of
+	 * mapping rows of tiles to a pipe.  At some point it might
+	 * be worth playing with different strategies and seeing if
+	 * that makes much impact on performance.
+	 */
+	t = p = n = 0;
+	yoff = miny;
+	for (i = 0; i < nbins_y; i++) {
+		struct fd_vsc_pipe *pipe = &ctx->pipe[p];
+		uint32_t bw, bh;
 
-	ctx->emit_tile_init(ctx);
+		assert(p < ARRAY_SIZE(ctx->pipe));
 
-	for (i = 0; i < gmem->nbins_y; i++) {
-		uint32_t j, xoff = gmem->minx;
-		uint32_t bh = gmem->bin_h;
+		xoff = minx;
 
 		/* clip bin height: */
-		bh = MIN2(bh, gmem->miny + gmem->height - yoff);
+		bh = MIN2(bin_h, miny + height - yoff);
+
+		for (j = 0; j < nbins_x; j++) {
+			struct fd_tile *tile = &ctx->tile[t];
 
-		for (j = 0; j < gmem->nbins_x; j++) {
-			uint32_t bw = gmem->bin_w;
+			assert(t < ARRAY_SIZE(ctx->tile));
 
 			/* clip bin width: */
-			bw = MIN2(bw, gmem->minx + gmem->width - xoff);
+			bw = MIN2(bin_w, minx + width - xoff);
 
-			DBG("bin_h=%d, yoff=%d, bin_w=%d, xoff=%d",
-					bh, yoff, bw, xoff);
+			tile->n = n++;
+			tile->p = p;
+			tile->bin_w = bw;
+			tile->bin_h = bh;
+			tile->xoff = xoff;
+			tile->yoff = yoff;
 
-			ctx->emit_tile_prep(ctx, xoff, yoff, bw, bh);
+			t++;
 
-			if (ctx->restore)
-				ctx->emit_tile_mem2gmem(ctx, xoff, yoff, bw, bh);
+			xoff += bw;
+		}
 
-			ctx->emit_tile_renderprep(ctx, xoff, yoff, bw, bh);
+		/* one pipe per row: */
+		pipe->x = 0;
+		pipe->y = i;
+		pipe->w = nbins_x;
+		pipe->h = 1;
 
-			/* emit IB to drawcmds: */
-			OUT_IB(ctx->ring, ctx->draw_start, ctx->draw_end);
+		p++;
+		n = 0;
 
-			/* emit gmem2mem to transfer tile back to system memory: */
-			ctx->emit_tile_gmem2mem(ctx, xoff, yoff, bw, bh);
+		yoff += bh;
+	}
 
-			xoff += bw;
-		}
+	for (; p < ARRAY_SIZE(ctx->pipe); p++) {
+		struct fd_vsc_pipe *pipe = &ctx->pipe[p];
+		pipe->x = pipe->y = pipe->w = pipe->h = 0;
+	}
+}
 
-		yoff += bh;
+static void
+render_tiles(struct fd_context *ctx)
+{
+	struct fd_gmem_stateobj *gmem = &ctx->gmem;
+	int i;
+
+	ctx->emit_tile_init(ctx);
+
+	for (i = 0; i < (gmem->nbins_x * gmem->nbins_y); i++) {
+		struct fd_tile *tile = &ctx->tile[i];
+
+		DBG("bin_h=%d, yoff=%d, bin_w=%d, xoff=%d",
+			tile->bin_h, tile->yoff, tile->bin_w, tile->xoff);
+
+		ctx->emit_tile_prep(ctx, tile);
+
+		if (ctx->restore)
+			ctx->emit_tile_mem2gmem(ctx, tile);
+
+		ctx->emit_tile_renderprep(ctx, tile);
+
+		/* emit IB to drawcmds: */
+		OUT_IB(ctx->ring, ctx->draw_start, ctx->draw_end);
+
+		/* emit gmem2mem to transfer tile back to system memory: */
+		ctx->emit_tile_gmem2mem(ctx, tile);
 	}
 }
 
diff --git a/src/gallium/drivers/freedreno/freedreno_gmem.h b/src/gallium/drivers/freedreno/freedreno_gmem.h
index 0c978a4..1082d54 100644
--- a/src/gallium/drivers/freedreno/freedreno_gmem.h
+++ b/src/gallium/drivers/freedreno/freedreno_gmem.h
@@ -31,6 +31,28 @@
 
 #include "pipe/p_context.h"
 
+/* per-pipe configuration for hw binning: */
+struct fd_vsc_pipe {
+	struct fd_bo *bo;
+	uint8_t x, y, w, h;      /* VSC_PIPE[p].CONFIG */
+};
+
+/* per-tile configuration for hw binning: */
+struct fd_tile {
+	uint8_t p;               /* index into vsc_pipe[]s */
+	uint8_t n;               /* slot within pipe */
+	uint16_t bin_w, bin_h;
+	uint16_t xoff, yoff;
+};
+
+struct fd_gmem_stateobj {
+	struct pipe_scissor_state scissor;
+	uint cpp;
+	uint16_t bin_h, nbins_y;
+	uint16_t bin_w, nbins_x;
+	uint16_t width, height;
+};
+
 void fd_gmem_render_tiles(struct pipe_context *pctx);
 
 #endif /* FREEDRENO_GMEM_H_ */




More information about the mesa-commit mailing list