[Mesa-dev] [PATCH 04/12] freedreno: introduce fd_batch

Rob Clark robdclark at gmail.com
Sat Jul 2 16:52:07 UTC 2016


From: Rob Clark <robclark at freedesktop.org>

Introduce the batch object, to track a batch/submit's worth of
ringbuffers and other bookkeeping.  In this first step, just move
the ringbuffers into batch, since that is mostly uninteresting
churn.

For now there is just a single batch at a time.  Note that one
outcome of this change is that rb's are allocated/freed on each
use.  But the expectation is that the bo pool in libdrm_freedreno
will save us the GEM bo alloc/free which was the initial reason
to implement a rb pool in gallium.

The purpose of the batch is to eventually facilitate out-of-order
rendering, with batches associated to framebuffer state, and
tracking the dependencies on other batches.

Signed-off-by: Rob Clark <robdclark at gmail.com>
---
 src/gallium/drivers/freedreno/Makefile.sources     |  2 +
 src/gallium/drivers/freedreno/a2xx/fd2_draw.c      |  6 +-
 src/gallium/drivers/freedreno/a2xx/fd2_emit.c      |  7 +-
 src/gallium/drivers/freedreno/a3xx/fd3_draw.c      |  8 +-
 src/gallium/drivers/freedreno/a3xx/fd3_emit.c      |  8 +-
 src/gallium/drivers/freedreno/a3xx/fd3_emit.h      |  2 +-
 src/gallium/drivers/freedreno/a3xx/fd3_gmem.c      |  7 +-
 src/gallium/drivers/freedreno/a4xx/fd4_draw.c      | 30 +++----
 src/gallium/drivers/freedreno/a4xx/fd4_emit.c      |  8 +-
 src/gallium/drivers/freedreno/a4xx/fd4_emit.h      |  2 +-
 src/gallium/drivers/freedreno/a4xx/fd4_gmem.c      |  7 +-
 src/gallium/drivers/freedreno/freedreno_batch.c    | 93 ++++++++++++++++++++++
 src/gallium/drivers/freedreno/freedreno_batch.h    | 72 +++++++++++++++++
 src/gallium/drivers/freedreno/freedreno_context.c  | 85 +++-----------------
 src/gallium/drivers/freedreno/freedreno_context.h  | 33 ++------
 src/gallium/drivers/freedreno/freedreno_draw.c     | 17 +---
 src/gallium/drivers/freedreno/freedreno_gmem.c     | 20 ++---
 src/gallium/drivers/freedreno/freedreno_query_hw.c |  4 +-
 src/gallium/drivers/freedreno/freedreno_resource.c |  4 +-
 src/gallium/drivers/freedreno/freedreno_util.h     |  9 +--
 20 files changed, 247 insertions(+), 177 deletions(-)
 create mode 100644 src/gallium/drivers/freedreno/freedreno_batch.c
 create mode 100644 src/gallium/drivers/freedreno/freedreno_batch.h

diff --git a/src/gallium/drivers/freedreno/Makefile.sources b/src/gallium/drivers/freedreno/Makefile.sources
index edba369..4ba8c9d 100644
--- a/src/gallium/drivers/freedreno/Makefile.sources
+++ b/src/gallium/drivers/freedreno/Makefile.sources
@@ -2,6 +2,8 @@ C_SOURCES := \
 	adreno_common.xml.h \
 	adreno_pm4.xml.h \
 	disasm.h \
+	freedreno_batch.c \
+	freedreno_batch.h \
 	freedreno_context.c \
 	freedreno_context.h \
 	freedreno_draw.c \
diff --git a/src/gallium/drivers/freedreno/a2xx/fd2_draw.c b/src/gallium/drivers/freedreno/a2xx/fd2_draw.c
index 14620ac..030e6f6 100644
--- a/src/gallium/drivers/freedreno/a2xx/fd2_draw.c
+++ b/src/gallium/drivers/freedreno/a2xx/fd2_draw.c
@@ -76,13 +76,13 @@ emit_vertexbufs(struct fd_context *ctx)
 	// NOTE I believe the 0x78 (or 0x9c in solid_vp) relates to the
 	// CONST(20,0) (or CONST(26,0) in soliv_vp)
 
-	fd2_emit_vertex_bufs(ctx->ring, 0x78, bufs, vtx->num_elements);
+	fd2_emit_vertex_bufs(ctx->batch->draw, 0x78, bufs, vtx->num_elements);
 }
 
 static bool
 fd2_draw_vbo(struct fd_context *ctx, const struct pipe_draw_info *info)
 {
-	struct fd_ringbuffer *ring = ctx->ring;
+	struct fd_ringbuffer *ring = ctx->batch->draw;
 
 	if (ctx->dirty & FD_DIRTY_VTXBUF)
 		emit_vertexbufs(ctx);
@@ -125,7 +125,7 @@ fd2_clear(struct fd_context *ctx, unsigned buffers,
 		const union pipe_color_union *color, double depth, unsigned stencil)
 {
 	struct fd2_context *fd2_ctx = fd2_context(ctx);
-	struct fd_ringbuffer *ring = ctx->ring;
+	struct fd_ringbuffer *ring = ctx->batch->draw;
 	struct pipe_framebuffer_state *fb = &ctx->framebuffer;
 	uint32_t reg, colr = 0;
 
diff --git a/src/gallium/drivers/freedreno/a2xx/fd2_emit.c b/src/gallium/drivers/freedreno/a2xx/fd2_emit.c
index f8d03ca..0327803 100644
--- a/src/gallium/drivers/freedreno/a2xx/fd2_emit.c
+++ b/src/gallium/drivers/freedreno/a2xx/fd2_emit.c
@@ -184,7 +184,7 @@ fd2_emit_state(struct fd_context *ctx, uint32_t dirty)
 {
 	struct fd2_blend_stateobj *blend = fd2_blend_stateobj(ctx->blend);
 	struct fd2_zsa_stateobj *zsa = fd2_zsa_stateobj(ctx->zsa);
-	struct fd_ringbuffer *ring = ctx->ring;
+	struct fd_ringbuffer *ring = ctx->batch->draw;
 
 	/* NOTE: we probably want to eventually refactor this so each state
 	 * object handles emitting it's own state..  although the mapping of
@@ -443,10 +443,9 @@ fd2_emit_restore(struct fd_context *ctx, struct fd_ringbuffer *ring)
 }
 
 static void
-fd2_emit_ib(struct fd_ringbuffer *ring, struct fd_ringmarker *start,
-		struct fd_ringmarker *end)
+fd2_emit_ib(struct fd_ringbuffer *ring, struct fd_ringbuffer *target)
 {
-	__OUT_IB(ring, false, start, end);
+	__OUT_IB(ring, false, target);
 }
 
 void
diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_draw.c b/src/gallium/drivers/freedreno/a3xx/fd3_draw.c
index 6723941..0593b25 100644
--- a/src/gallium/drivers/freedreno/a3xx/fd3_draw.c
+++ b/src/gallium/drivers/freedreno/a3xx/fd3_draw.c
@@ -169,14 +169,14 @@ fd3_draw_vbo(struct fd_context *ctx, const struct pipe_draw_info *info)
 
 	emit.key.binning_pass = false;
 	emit.dirty = dirty;
-	draw_impl(ctx, ctx->ring, &emit);
+	draw_impl(ctx, ctx->batch->draw, &emit);
 
 	/* and now binning pass: */
 	emit.key.binning_pass = true;
 	emit.dirty = dirty & ~(FD_DIRTY_BLEND);
 	emit.vp = NULL;   /* we changed key so need to refetch vp */
 	emit.fp = NULL;
-	draw_impl(ctx, ctx->binning_ring, &emit);
+	draw_impl(ctx, ctx->batch->binning, &emit);
 
 	return true;
 }
@@ -209,7 +209,7 @@ static void
 fd3_clear_binning(struct fd_context *ctx, unsigned dirty)
 {
 	struct fd3_context *fd3_ctx = fd3_context(ctx);
-	struct fd_ringbuffer *ring = ctx->binning_ring;
+	struct fd_ringbuffer *ring = ctx->batch->binning;
 	struct fd3_emit emit = {
 		.debug = &ctx->debug,
 		.vtx  = &fd3_ctx->solid_vbuf_state,
@@ -250,7 +250,7 @@ fd3_clear(struct fd_context *ctx, unsigned buffers,
 {
 	struct fd3_context *fd3_ctx = fd3_context(ctx);
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
-	struct fd_ringbuffer *ring = ctx->ring;
+	struct fd_ringbuffer *ring = ctx->batch->draw;
 	unsigned dirty = ctx->dirty;
 	unsigned i;
 	struct fd3_emit emit = {
diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_emit.c b/src/gallium/drivers/freedreno/a3xx/fd3_emit.c
index 03b9328..45185ed 100644
--- a/src/gallium/drivers/freedreno/a3xx/fd3_emit.c
+++ b/src/gallium/drivers/freedreno/a3xx/fd3_emit.c
@@ -756,10 +756,9 @@ fd3_emit_state(struct fd_context *ctx, struct fd_ringbuffer *ring,
  * state, there could have been a context switch between ioctls):
  */
 void
-fd3_emit_restore(struct fd_context *ctx)
+fd3_emit_restore(struct fd_context *ctx, struct fd_ringbuffer *ring)
 {
 	struct fd3_context *fd3_ctx = fd3_context(ctx);
-	struct fd_ringbuffer *ring = ctx->ring;
 	int i;
 
 	if (ctx->screen->gpu_id == 320) {
@@ -900,10 +899,9 @@ fd3_emit_restore(struct fd_context *ctx)
 }
 
 static void
-fd3_emit_ib(struct fd_ringbuffer *ring, struct fd_ringmarker *start,
-		struct fd_ringmarker *end)
+fd3_emit_ib(struct fd_ringbuffer *ring, struct fd_ringbuffer *target)
 {
-	__OUT_IB(ring, true, start, end);
+	__OUT_IB(ring, true, target);
 }
 
 void
diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_emit.h b/src/gallium/drivers/freedreno/a3xx/fd3_emit.h
index 17e1fef..110f30e 100644
--- a/src/gallium/drivers/freedreno/a3xx/fd3_emit.h
+++ b/src/gallium/drivers/freedreno/a3xx/fd3_emit.h
@@ -93,7 +93,7 @@ void fd3_emit_vertex_bufs(struct fd_ringbuffer *ring, struct fd3_emit *emit);
 void fd3_emit_state(struct fd_context *ctx, struct fd_ringbuffer *ring,
 		struct fd3_emit *emit);
 
-void fd3_emit_restore(struct fd_context *ctx);
+void fd3_emit_restore(struct fd_context *ctx, struct fd_ringbuffer *ring);
 
 void fd3_emit_init(struct pipe_context *pctx);
 
diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c b/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c
index 7b96d5e..2449a84 100644
--- a/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c
+++ b/src/gallium/drivers/freedreno/a3xx/fd3_gmem.c
@@ -732,7 +732,7 @@ fd3_emit_sysmem_prep(struct fd_context *ctx)
 		pitch = fd_resource(psurf->texture)->slices[psurf->u.tex.level].pitch;
 	}
 
-	fd3_emit_restore(ctx);
+	fd3_emit_restore(ctx, ring);
 
 	OUT_PKT0(ring, REG_A3XX_RB_FRAME_BUFFER_DIMENSION, 1);
 	OUT_RING(ring, A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH(pfb->width) |
@@ -794,6 +794,7 @@ emit_binning_pass(struct fd_context *ctx)
 {
 	struct fd_gmem_stateobj *gmem = &ctx->gmem;
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
+	struct fd_batch *batch = ctx->batch;
 	struct fd_ringbuffer *ring = ctx->ring;
 	int i;
 
@@ -857,7 +858,7 @@ emit_binning_pass(struct fd_context *ctx)
 			A3XX_PC_VSTREAM_CONTROL_N(0));
 
 	/* emit IB to binning drawcmds: */
-	ctx->emit_ib(ring, ctx->binning_start, ctx->binning_end);
+	ctx->emit_ib(ring, batch->binning);
 	fd_reset_wfi(ctx);
 
 	fd_wfi(ctx, ring);
@@ -923,7 +924,7 @@ fd3_emit_tile_init(struct fd_context *ctx)
 	struct fd_gmem_stateobj *gmem = &ctx->gmem;
 	uint32_t rb_render_control;
 
-	fd3_emit_restore(ctx);
+	fd3_emit_restore(ctx, ring);
 
 	/* note: use gmem->bin_w/h, the bin_w/h parameters may be truncated
 	 * at the right and bottom edge tiles
diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_draw.c b/src/gallium/drivers/freedreno/a4xx/fd4_draw.c
index b9bae8a..e051386 100644
--- a/src/gallium/drivers/freedreno/a4xx/fd4_draw.c
+++ b/src/gallium/drivers/freedreno/a4xx/fd4_draw.c
@@ -164,22 +164,24 @@ fd4_draw_vbo(struct fd_context *ctx, const struct pipe_draw_info *info)
 	emit.key.binning_pass = false;
 	emit.dirty = dirty;
 
+	struct fd_ringbuffer *ring = ctx->batch->draw;
+
 	if (ctx->rasterizer->rasterizer_discard) {
-		fd_wfi(ctx, ctx->ring);
-		OUT_PKT3(ctx->ring, CP_REG_RMW, 3);
-		OUT_RING(ctx->ring, REG_A4XX_RB_RENDER_CONTROL);
-		OUT_RING(ctx->ring, ~A4XX_RB_RENDER_CONTROL_DISABLE_COLOR_PIPE);
-		OUT_RING(ctx->ring, A4XX_RB_RENDER_CONTROL_DISABLE_COLOR_PIPE);
+		fd_wfi(ctx, ring);
+		OUT_PKT3(ring, CP_REG_RMW, 3);
+		OUT_RING(ring, REG_A4XX_RB_RENDER_CONTROL);
+		OUT_RING(ring, ~A4XX_RB_RENDER_CONTROL_DISABLE_COLOR_PIPE);
+		OUT_RING(ring, A4XX_RB_RENDER_CONTROL_DISABLE_COLOR_PIPE);
 	}
 
-	draw_impl(ctx, ctx->ring, &emit);
+	draw_impl(ctx, ctx->batch->draw, &emit);
 
 	if (ctx->rasterizer->rasterizer_discard) {
-		fd_wfi(ctx, ctx->ring);
-		OUT_PKT3(ctx->ring, CP_REG_RMW, 3);
-		OUT_RING(ctx->ring, REG_A4XX_RB_RENDER_CONTROL);
-		OUT_RING(ctx->ring, ~A4XX_RB_RENDER_CONTROL_DISABLE_COLOR_PIPE);
-		OUT_RING(ctx->ring, 0);
+		fd_wfi(ctx, ring);
+		OUT_PKT3(ring, CP_REG_RMW, 3);
+		OUT_RING(ring, REG_A4XX_RB_RENDER_CONTROL);
+		OUT_RING(ring, ~A4XX_RB_RENDER_CONTROL_DISABLE_COLOR_PIPE);
+		OUT_RING(ring, 0);
 	}
 
 	/* and now binning pass: */
@@ -187,7 +189,7 @@ fd4_draw_vbo(struct fd_context *ctx, const struct pipe_draw_info *info)
 	emit.dirty = dirty & ~(FD_DIRTY_BLEND);
 	emit.vp = NULL;   /* we changed key so need to refetch vp */
 	emit.fp = NULL;
-	draw_impl(ctx, ctx->binning_ring, &emit);
+	draw_impl(ctx, ctx->batch->binning, &emit);
 
 	return true;
 }
@@ -217,7 +219,7 @@ static void
 fd4_clear_binning(struct fd_context *ctx, unsigned dirty)
 {
 	struct fd4_context *fd4_ctx = fd4_context(ctx);
-	struct fd_ringbuffer *ring = ctx->binning_ring;
+	struct fd_ringbuffer *ring = ctx->batch->binning;
 	struct fd4_emit emit = {
 		.debug = &ctx->debug,
 		.vtx  = &fd4_ctx->solid_vbuf_state,
@@ -251,7 +253,7 @@ fd4_clear(struct fd_context *ctx, unsigned buffers,
 		const union pipe_color_union *color, double depth, unsigned stencil)
 {
 	struct fd4_context *fd4_ctx = fd4_context(ctx);
-	struct fd_ringbuffer *ring = ctx->ring;
+	struct fd_ringbuffer *ring = ctx->batch->draw;
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
 	unsigned char mrt_comp[A4XX_MAX_RENDER_TARGETS] = {0};
 	unsigned dirty = ctx->dirty;
diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_emit.c b/src/gallium/drivers/freedreno/a4xx/fd4_emit.c
index c8658f0..5bb712c 100644
--- a/src/gallium/drivers/freedreno/a4xx/fd4_emit.c
+++ b/src/gallium/drivers/freedreno/a4xx/fd4_emit.c
@@ -736,10 +736,9 @@ fd4_emit_state(struct fd_context *ctx, struct fd_ringbuffer *ring,
  * state, there could have been a context switch between ioctls):
  */
 void
-fd4_emit_restore(struct fd_context *ctx)
+fd4_emit_restore(struct fd_context *ctx, struct fd_ringbuffer *ring)
 {
 	struct fd4_context *fd4_ctx = fd4_context(ctx);
-	struct fd_ringbuffer *ring = ctx->ring;
 
 	OUT_PKT0(ring, REG_A4XX_RBBM_PERFCTR_CTL, 1);
 	OUT_RING(ring, 0x00000001);
@@ -892,10 +891,9 @@ fd4_emit_restore(struct fd_context *ctx)
 }
 
 static void
-fd4_emit_ib(struct fd_ringbuffer *ring, struct fd_ringmarker *start,
-		struct fd_ringmarker *end)
+fd4_emit_ib(struct fd_ringbuffer *ring, struct fd_ringbuffer *target)
 {
-	__OUT_IB(ring, true, start, end);
+	__OUT_IB(ring, true, target);
 }
 
 void
diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_emit.h b/src/gallium/drivers/freedreno/a4xx/fd4_emit.h
index a39697d..89dc51a 100644
--- a/src/gallium/drivers/freedreno/a4xx/fd4_emit.h
+++ b/src/gallium/drivers/freedreno/a4xx/fd4_emit.h
@@ -102,7 +102,7 @@ void fd4_emit_vertex_bufs(struct fd_ringbuffer *ring, struct fd4_emit *emit);
 void fd4_emit_state(struct fd_context *ctx, struct fd_ringbuffer *ring,
 		struct fd4_emit *emit);
 
-void fd4_emit_restore(struct fd_context *ctx);
+void fd4_emit_restore(struct fd_context *ctx, struct fd_ringbuffer *ring);
 
 void fd4_emit_init(struct pipe_context *pctx);
 
diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_gmem.c b/src/gallium/drivers/freedreno/a4xx/fd4_gmem.c
index e211545..524c35a 100644
--- a/src/gallium/drivers/freedreno/a4xx/fd4_gmem.c
+++ b/src/gallium/drivers/freedreno/a4xx/fd4_gmem.c
@@ -525,7 +525,7 @@ fd4_emit_sysmem_prep(struct fd_context *ctx)
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
 	struct fd_ringbuffer *ring = ctx->ring;
 
-	fd4_emit_restore(ctx);
+	fd4_emit_restore(ctx, ring);
 
 	OUT_PKT0(ring, REG_A4XX_RB_FRAME_BUFFER_DIMENSION, 1);
 	OUT_RING(ring, A4XX_RB_FRAME_BUFFER_DIMENSION_WIDTH(pfb->width) |
@@ -596,6 +596,7 @@ emit_binning_pass(struct fd_context *ctx)
 {
 	struct fd_gmem_stateobj *gmem = &ctx->gmem;
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
+	struct fd_batch *batch = ctx->batch;
 	struct fd_ringbuffer *ring = ctx->ring;
 	int i;
 
@@ -635,7 +636,7 @@ emit_binning_pass(struct fd_context *ctx)
 	}
 
 	/* emit IB to binning drawcmds: */
-	ctx->emit_ib(ring, ctx->binning_start, ctx->binning_end);
+	ctx->emit_ib(ring, batch->binning);
 
 	fd_reset_wfi(ctx);
 	fd_wfi(ctx, ring);
@@ -662,7 +663,7 @@ fd4_emit_tile_init(struct fd_context *ctx)
 	struct fd_ringbuffer *ring = ctx->ring;
 	struct fd_gmem_stateobj *gmem = &ctx->gmem;
 
-	fd4_emit_restore(ctx);
+	fd4_emit_restore(ctx, ring);
 
 	OUT_PKT0(ring, REG_A4XX_VSC_BIN_SIZE, 1);
 	OUT_RING(ring, A4XX_VSC_BIN_SIZE_WIDTH(gmem->bin_w) |
diff --git a/src/gallium/drivers/freedreno/freedreno_batch.c b/src/gallium/drivers/freedreno/freedreno_batch.c
new file mode 100644
index 0000000..c202ff0
--- /dev/null
+++ b/src/gallium/drivers/freedreno/freedreno_batch.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 Rob Clark <robclark at freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark at freedesktop.org>
+ */
+
+#include "util/u_string.h"
+
+#include "freedreno_batch.h"
+#include "freedreno_context.h"
+
+struct fd_batch *
+fd_batch_create(struct fd_context *ctx)
+{
+	struct fd_batch *batch = CALLOC_STRUCT(fd_batch);
+	static unsigned seqno = 0;
+
+	if (!batch)
+		return NULL;
+
+	pipe_reference_init(&batch->reference, 1);
+	batch->seqno = ++seqno;
+	batch->ctx = ctx;
+
+	/* TODO how to pick a good size?  Or maybe we should introduce
+	 * fd_ringlist?  Also, make sure size is aligned with bo-cache
+	 * bucket size, since otherwise that will round up size..
+	 */
+	batch->draw    = fd_ringbuffer_new(ctx->screen->pipe, 0x10000);
+	batch->binning = fd_ringbuffer_new(ctx->screen->pipe, 0x10000);
+	batch->gmem    = fd_ringbuffer_new(ctx->screen->pipe, 0x10000);
+
+	fd_ringbuffer_set_parent(batch->gmem, NULL);
+	fd_ringbuffer_set_parent(batch->draw, batch->gmem);
+	fd_ringbuffer_set_parent(batch->binning, batch->gmem);
+
+	return batch;
+}
+
+void
+__fd_batch_destroy(struct fd_batch *batch)
+{
+	fd_ringbuffer_del(batch->draw);
+	fd_ringbuffer_del(batch->binning);
+	fd_ringbuffer_del(batch->gmem);
+
+	free(batch);
+}
+
+void
+__fd_batch_describe(char* buf, const struct fd_batch *batch)
+{
+	util_sprintf(buf, "fd_batch<%u>", batch->seqno);
+}
+
+void
+fd_batch_flush(struct fd_batch *batch)
+{
+	fd_gmem_render_tiles(batch->ctx);
+}
+
+void
+fd_batch_check_size(struct fd_batch *batch)
+{
+	/* TODO eventually support having a list of draw/binning rb's
+	 * and if we are too close to the end, add another to the
+	 * list.  For now we just flush.
+	 */
+	struct fd_ringbuffer *ring = batch->draw;
+	if (((ring->cur - ring->start) > (ring->size/4 - 0x1000)) ||
+			(fd_mesa_debug & FD_DBG_FLUSH))
+		fd_context_render(&batch->ctx->base);
+}
diff --git a/src/gallium/drivers/freedreno/freedreno_batch.h b/src/gallium/drivers/freedreno/freedreno_batch.h
new file mode 100644
index 0000000..2134624
--- /dev/null
+++ b/src/gallium/drivers/freedreno/freedreno_batch.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 Rob Clark <robclark at freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark at freedesktop.org>
+ */
+
+#ifndef FREEDRENO_BATCH_H_
+#define FREEDRENO_BATCH_H_
+
+#include "util/u_inlines.h"
+
+#include "freedreno_util.h"
+
+struct fd_context;
+
+/* A batch tracks everything about a cmdstream batch/submit, including the
+ * ringbuffers used for binning, draw, and gmem cmds, list of associated
+ * fd_resource-s, etc.
+ */
+struct fd_batch {
+	struct pipe_reference reference;
+	unsigned seqno;
+	struct fd_context *ctx;
+
+	/** draw pass cmdstream: */
+	struct fd_ringbuffer *draw;
+	/** binning pass cmdstream: */
+	struct fd_ringbuffer *binning;
+	/** tiling/gmem (IB0) cmdstream: */
+	struct fd_ringbuffer *gmem;
+};
+
+struct fd_batch * fd_batch_create(struct fd_context *ctx);
+
+void fd_batch_flush(struct fd_batch *batch);
+void fd_batch_check_size(struct fd_batch *batch);
+
+/* not called directly: */
+void __fd_batch_describe(char* buf, const struct fd_batch *batch);
+void __fd_batch_destroy(struct fd_batch *batch);
+
+static inline void
+fd_batch_reference(struct fd_batch **ptr, struct fd_batch *batch)
+{
+	struct fd_batch *old_batch = *ptr;
+	if (pipe_reference_described(&(*ptr)->reference, &batch->reference,
+			(debug_reference_descriptor)__fd_batch_describe))
+		__fd_batch_destroy(old_batch);
+	*ptr = batch;
+}
+
+#endif /* FREEDRENO_BATCH_H_ */
diff --git a/src/gallium/drivers/freedreno/freedreno_context.c b/src/gallium/drivers/freedreno/freedreno_context.c
index 52557d1..70af52e 100644
--- a/src/gallium/drivers/freedreno/freedreno_context.c
+++ b/src/gallium/drivers/freedreno/freedreno_context.c
@@ -38,55 +38,6 @@
 #include "freedreno_query_hw.h"
 #include "freedreno_util.h"
 
-static struct fd_ringbuffer *next_rb(struct fd_context *ctx)
-{
-	struct fd_ringbuffer *ring;
-	uint32_t ts;
-
-	/* grab next ringbuffer: */
-	ring = ctx->rings[(ctx->rings_idx++) % ARRAY_SIZE(ctx->rings)];
-
-	/* wait for new rb to be idle: */
-	ts = fd_ringbuffer_timestamp(ring);
-	if (ts) {
-		DBG("wait: %u", ts);
-		fd_pipe_wait(ctx->screen->pipe, ts);
-	}
-
-	fd_ringbuffer_reset(ring);
-
-	return ring;
-}
-
-static void
-fd_context_next_rb(struct pipe_context *pctx)
-{
-	struct fd_context *ctx = fd_context(pctx);
-	struct fd_ringbuffer *ring;
-
-	fd_ringmarker_del(ctx->draw_start);
-	fd_ringmarker_del(ctx->draw_end);
-
-	ring = next_rb(ctx);
-
-	ctx->draw_start = fd_ringmarker_new(ring);
-	ctx->draw_end = fd_ringmarker_new(ring);
-
-	fd_ringbuffer_set_parent(ring, NULL);
-	ctx->ring = ring;
-
-	fd_ringmarker_del(ctx->binning_start);
-	fd_ringmarker_del(ctx->binning_end);
-
-	ring = next_rb(ctx);
-
-	ctx->binning_start = fd_ringmarker_new(ring);
-	ctx->binning_end = fd_ringmarker_new(ring);
-
-	fd_ringbuffer_set_parent(ring, ctx->ring);
-	ctx->binning_ring = ring;
-}
-
 /* emit accumulated render cmds, needed for example if render target has
  * changed, or for flush()
  */
@@ -101,15 +52,10 @@ fd_context_render(struct pipe_context *pctx)
 	if (!ctx->needs_flush)
 		return;
 
-	fd_gmem_render_tiles(ctx);
+	fd_batch_flush(ctx->batch);
 
-	DBG("%p/%p/%p", ctx->ring->start, ctx->ring->cur, ctx->ring->end);
-
-	/* if size in dwords is more than half the buffer size, then wait and
-	 * wrap around:
-	 */
-	if ((ctx->ring->cur - ctx->ring->start) > ctx->ring->size/8)
-		fd_context_next_rb(pctx);
+	fd_batch_reference(&ctx->batch, NULL);
+	ctx->batch = fd_batch_create(ctx);
 
 	ctx->needs_flush = false;
 	ctx->cleared = ctx->partial_cleared = ctx->restore = ctx->resolve = 0;
@@ -131,14 +77,18 @@ static void
 fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence,
 		unsigned flags)
 {
-	struct fd_ringbuffer *ring = fd_context(pctx)->ring;
+	struct fd_batch *batch = NULL;
+
+	fd_batch_reference(&batch, fd_context(pctx)->batch);
 
 	fd_context_render(pctx);
 
 	if (fence) {
 		fd_screen_fence_ref(pctx->screen, fence, NULL);
-		*fence = fd_fence_create(pctx, fd_ringbuffer_timestamp(ring));
+		*fence = fd_fence_create(pctx, fd_ringbuffer_timestamp(batch->gmem));
 	}
+
+	fd_batch_reference(&batch, NULL);
 }
 
 /**
@@ -149,7 +99,7 @@ static void
 fd_emit_string_marker(struct pipe_context *pctx, const char *string, int len)
 {
 	struct fd_context *ctx = fd_context(pctx);
-	struct fd_ringbuffer *ring = ctx->ring;
+	struct fd_ringbuffer *ring = ctx->batch->draw;
 	const uint32_t *buf = (const void *)string;
 
 	/* max packet size is 0x3fff dwords: */
@@ -191,13 +141,7 @@ fd_context_destroy(struct pipe_context *pctx)
 
 	util_slab_destroy(&ctx->transfer_pool);
 
-	fd_ringmarker_del(ctx->draw_start);
-	fd_ringmarker_del(ctx->draw_end);
-	fd_ringmarker_del(ctx->binning_start);
-	fd_ringmarker_del(ctx->binning_end);
-
-	for (i = 0; i < ARRAY_SIZE(ctx->rings); i++)
-		fd_ringbuffer_del(ctx->rings[i]);
+	fd_batch_reference(&ctx->batch, NULL);  /* unref current batch */
 
 	for (i = 0; i < ARRAY_SIZE(ctx->pipe); i++) {
 		struct fd_vsc_pipe *pipe = &ctx->pipe[i];
@@ -251,13 +195,8 @@ fd_context_init(struct fd_context *ctx, struct pipe_screen *pscreen,
 	pctx->emit_string_marker = fd_emit_string_marker;
 	pctx->set_debug_callback = fd_set_debug_callback;
 
-	for (i = 0; i < ARRAY_SIZE(ctx->rings); i++) {
-		ctx->rings[i] = fd_ringbuffer_new(screen->pipe, 0x100000);
-		if (!ctx->rings[i])
-			goto fail;
-	}
+	ctx->batch = fd_batch_create(ctx);
 
-	fd_context_next_rb(pctx);
 	fd_reset_wfi(ctx);
 
 	util_dynarray_init(&ctx->draw_patches);
diff --git a/src/gallium/drivers/freedreno/freedreno_context.h b/src/gallium/drivers/freedreno/freedreno_context.h
index fe2a94c..ebf6888 100644
--- a/src/gallium/drivers/freedreno/freedreno_context.h
+++ b/src/gallium/drivers/freedreno/freedreno_context.h
@@ -36,6 +36,7 @@
 #include "util/u_slab.h"
 #include "util/u_string.h"
 
+#include "freedreno_batch.h"
 #include "freedreno_screen.h"
 #include "freedreno_gmem.h"
 #include "freedreno_util.h"
@@ -245,33 +246,14 @@ struct fd_context {
 		uint64_t batch_total, batch_sysmem, batch_gmem, batch_restore;
 	} stats;
 
-	/* we can't really sanely deal with wraparound point in ringbuffer
-	 * and because of the way tiling works we can't really flush at
-	 * arbitrary points (without a big performance hit).  When we get
-	 * too close to the end of the current ringbuffer, cycle to the next
-	 * one (and wait for pending rendering from next rb to complete).
-	 * We want the # of ringbuffers to be high enough that we don't
-	 * normally have to wait before resetting to the start of the next
-	 * rb.
+	/* TODO get rid of this.. only used in gmem/tiling code paths (and
+	 * NULL the rest of the time).  Just leaving for now to reduce some
+	 * churn..
 	 */
-	struct fd_ringbuffer *rings[8];
-	unsigned rings_idx;
-
-	/* NOTE: currently using a single ringbuffer for both draw and
-	 * tiling commands, we need to make sure we need to leave enough
-	 * room at the end to append the tiling commands when we flush.
-	 * 0x7000 dwords should be a couple times more than we ever need
-	 * so should be a nice conservative threshold.
-	 */
-#define FD_TILING_COMMANDS_DWORDS 0x7000
-
-	/* normal draw/clear cmds: */
 	struct fd_ringbuffer *ring;
-	struct fd_ringmarker *draw_start, *draw_end;
 
-	/* binning pass draw/clear cmds: */
-	struct fd_ringbuffer *binning_ring;
-	struct fd_ringmarker *binning_start, *binning_end;
+	/* Current batch: */
+	struct fd_batch *batch;
 
 	/* Keep track if WAIT_FOR_IDLE is needed for registers we need
 	 * to update via RMW:
@@ -399,8 +381,7 @@ struct fd_context {
 			uint32_t regid, uint32_t num, struct pipe_resource **prscs, uint32_t *offsets);
 
 	/* indirect-branch emit: */
-	void (*emit_ib)(struct fd_ringbuffer *ring, struct fd_ringmarker *start,
-			struct fd_ringmarker *end);
+	void (*emit_ib)(struct fd_ringbuffer *ring, struct fd_ringbuffer *target);
 };
 
 static inline struct fd_context *
diff --git a/src/gallium/drivers/freedreno/freedreno_draw.c b/src/gallium/drivers/freedreno/freedreno_draw.c
index 34b1ff6..26164f2 100644
--- a/src/gallium/drivers/freedreno/freedreno_draw.c
+++ b/src/gallium/drivers/freedreno/freedreno_draw.c
@@ -192,7 +192,7 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 		util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
 		util_format_short_name(pipe_surface_format(pfb->zsbuf)));
 
-	fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_DRAW);
+	fd_hw_query_set_stage(ctx, ctx->batch->draw, FD_STAGE_DRAW);
 	if (ctx->draw_vbo(ctx, info))
 		ctx->needs_flush = true;
 
@@ -202,18 +202,7 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 	if (fd_mesa_debug & FD_DBG_DDRAW)
 		ctx->dirty = 0xffffffff;
 
-	/* if an app (or, well, piglit test) does many thousands of draws
-	 * without flush (or anything which implicitly flushes, like
-	 * changing render targets), we can exceed the ringbuffer size.
-	 * Since we don't currently have a sane way to wrapparound, and
-	 * we use the same buffer for both draw and tiling commands, for
-	 * now we need to do this hack and trigger flush if we are running
-	 * low on remaining space for cmds:
-	 */
-	if (((ctx->ring->cur - ctx->ring->start) >
-				(ctx->ring->size/4 - FD_TILING_COMMANDS_DWORDS)) ||
-			(fd_mesa_debug & FD_DBG_FLUSH))
-		fd_context_render(pctx);
+	fd_batch_check_size(ctx->batch);
 }
 
 /* TODO figure out how to make better use of existing state mechanism
@@ -274,7 +263,7 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
 		util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
 		util_format_short_name(pipe_surface_format(pfb->zsbuf)));
 
-	fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_CLEAR);
+	fd_hw_query_set_stage(ctx, ctx->batch->draw, FD_STAGE_CLEAR);
 
 	ctx->clear(ctx, buffers, color, depth, stencil);
 
diff --git a/src/gallium/drivers/freedreno/freedreno_gmem.c b/src/gallium/drivers/freedreno/freedreno_gmem.c
index 0d73349..54a3247 100644
--- a/src/gallium/drivers/freedreno/freedreno_gmem.c
+++ b/src/gallium/drivers/freedreno/freedreno_gmem.c
@@ -331,7 +331,7 @@ render_tiles(struct fd_context *ctx)
 		fd_hw_query_prepare_tile(ctx, i, ctx->ring);
 
 		/* emit IB to drawcmds: */
-		ctx->emit_ib(ctx->ring, ctx->draw_start, ctx->draw_end);
+		ctx->emit_ib(ctx->ring, ctx->batch->draw);
 		fd_reset_wfi(ctx);
 
 		/* emit gmem2mem to transfer tile back to system memory: */
@@ -349,7 +349,7 @@ render_sysmem(struct fd_context *ctx)
 	fd_hw_query_prepare_tile(ctx, 0, ctx->ring);
 
 	/* emit IB to drawcmds: */
-	ctx->emit_ib(ctx->ring, ctx->draw_start, ctx->draw_end);
+	ctx->emit_ib(ctx->ring, ctx->batch->draw);
 	fd_reset_wfi(ctx);
 }
 
@@ -357,6 +357,7 @@ void
 fd_gmem_render_tiles(struct fd_context *ctx)
 {
 	struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
+	struct fd_batch *batch = ctx->batch;
 	bool sysmem = false;
 
 	if (ctx->emit_sysmem_prep) {
@@ -371,16 +372,14 @@ fd_gmem_render_tiles(struct fd_context *ctx)
 	/* close out the draw cmds by making sure any active queries are
 	 * paused:
 	 */
-	fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_NULL);
-
-	/* mark the end of the clear/draw cmds before emitting per-tile cmds: */
-	fd_ringmarker_mark(ctx->draw_end);
-	fd_ringmarker_mark(ctx->binning_end);
+	fd_hw_query_set_stage(ctx, batch->draw, FD_STAGE_NULL);
 
 	fd_reset_wfi(ctx);
 
 	ctx->stats.batch_total++;
 
+	ctx->ring = batch->gmem;
+
 	if (sysmem) {
 		DBG("rendering sysmem (%s/%s)",
 			util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
@@ -399,12 +398,9 @@ fd_gmem_render_tiles(struct fd_context *ctx)
 		ctx->stats.batch_gmem++;
 	}
 
-	/* GPU executes starting from tile cmds, which IB back to draw cmds: */
-	fd_ringmarker_flush(ctx->draw_end);
+	fd_ringbuffer_flush(batch->gmem);
 
-	/* mark start for next draw/binning cmds: */
-	fd_ringmarker_mark(ctx->draw_start);
-	fd_ringmarker_mark(ctx->binning_start);
+	ctx->ring = NULL;
 
 	fd_reset_wfi(ctx);
 
diff --git a/src/gallium/drivers/freedreno/freedreno_query_hw.c b/src/gallium/drivers/freedreno/freedreno_query_hw.c
index 95fff3f..dc188b0 100644
--- a/src/gallium/drivers/freedreno/freedreno_query_hw.c
+++ b/src/gallium/drivers/freedreno/freedreno_query_hw.c
@@ -152,7 +152,7 @@ fd_hw_begin_query(struct fd_context *ctx, struct fd_query *q)
 	destroy_periods(ctx, &hq->periods);
 
 	if (is_active(hq, ctx->stage))
-		resume_query(ctx, hq, ctx->ring);
+		resume_query(ctx, hq, ctx->batch->draw);
 
 	q->active = true;
 
@@ -175,7 +175,7 @@ fd_hw_end_query(struct fd_context *ctx, struct fd_query *q)
 	if (!q->active)
 		return;
 	if (is_active(hq, ctx->stage))
-		pause_query(ctx, hq, ctx->ring);
+		pause_query(ctx, hq, ctx->batch->draw);
 	q->active = false;
 	/* move to current list: */
 	list_del(&hq->list);
diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c
index ded8147..bd50988 100644
--- a/src/gallium/drivers/freedreno/freedreno_resource.c
+++ b/src/gallium/drivers/freedreno/freedreno_resource.c
@@ -831,13 +831,13 @@ fd_blitter_pipe_begin(struct fd_context *ctx, bool render_cond)
 		util_blitter_save_render_condition(ctx->blitter,
 			ctx->cond_query, ctx->cond_cond, ctx->cond_mode);
 
-	fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_BLIT);
+	fd_hw_query_set_stage(ctx, ctx->batch->draw, FD_STAGE_BLIT);
 }
 
 static void
 fd_blitter_pipe_end(struct fd_context *ctx)
 {
-	fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_NULL);
+	fd_hw_query_set_stage(ctx, ctx->batch->draw, FD_STAGE_NULL);
 }
 
 static void
diff --git a/src/gallium/drivers/freedreno/freedreno_util.h b/src/gallium/drivers/freedreno/freedreno_util.h
index 330cff9..b6b91f9 100644
--- a/src/gallium/drivers/freedreno/freedreno_util.h
+++ b/src/gallium/drivers/freedreno/freedreno_util.h
@@ -182,7 +182,7 @@ OUT_RING(struct fd_ringbuffer *ring, uint32_t data)
 		DBG("ring[%p]: OUT_RING   %04x:  %08x", ring,
 				(uint32_t)(ring->cur - ring->last_start), data);
 	}
-	*(ring->cur++) = data;
+	fd_ringbuffer_emit(ring, data);
 }
 
 /* like OUT_RING() but appends a cmdstream patch point to 'buf' */
@@ -269,10 +269,9 @@ OUT_WFI(struct fd_ringbuffer *ring)
 }
 
 static inline void
-__OUT_IB(struct fd_ringbuffer *ring, bool prefetch,
-		struct fd_ringmarker *start, struct fd_ringmarker *end)
+__OUT_IB(struct fd_ringbuffer *ring, bool prefetch, struct fd_ringbuffer *target)
 {
-	uint32_t dwords = fd_ringmarker_dwords(start, end);
+	uint32_t dwords = target->cur - target->start;
 
 	assert(dwords > 0);
 
@@ -285,7 +284,7 @@ __OUT_IB(struct fd_ringbuffer *ring, bool prefetch,
 	emit_marker(ring, 6);
 
 	OUT_PKT3(ring, prefetch ? CP_INDIRECT_BUFFER_PFE : CP_INDIRECT_BUFFER_PFD, 2);
-	fd_ringbuffer_emit_reloc_ring(ring, start, end);
+	fd_ringbuffer_emit_reloc_ring_full(ring, target, 0);
 	OUT_RING(ring, dwords);
 
 	emit_marker(ring, 6);
-- 
2.7.4



More information about the mesa-dev mailing list