From 9bbd239a4039522d7c1023ecb21764679447bb2d Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 20 May 2016 15:36:10 -0400 Subject: [PATCH] freedreno: introduce fd_batch 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 --- .../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 +- .../drivers/freedreno/freedreno_batch.c | 93 +++++++++++++++++++ .../drivers/freedreno/freedreno_batch.h | 72 ++++++++++++++ .../drivers/freedreno/freedreno_context.c | 85 +++-------------- .../drivers/freedreno/freedreno_context.h | 38 +++----- .../drivers/freedreno/freedreno_draw.c | 17 +--- .../drivers/freedreno/freedreno_gmem.c | 20 ++-- .../drivers/freedreno/freedreno_query_hw.c | 4 +- .../drivers/freedreno/freedreno_resource.c | 4 +- .../drivers/freedreno/freedreno_util.h | 9 +- 20 files changed, 252 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 edba36999e2..4ba8c9dd19a 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 14620acbc85..030e6f69b71 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 f8d03ca5eb0..032780364df 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 67239414393..0593b253f1a 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 03b9328b605..45185edb505 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 17e1fef882f..110f30e89be 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 7b96d5eaee2..2449a84c721 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 b9bae8adc54..e0513860a71 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 c8658f0fe9c..5bb712c755c 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 a39697dafb4..89dc51ad1ee 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 e2115454d86..524c35a18bd 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 00000000000..c202ff0e942 --- /dev/null +++ b/src/gallium/drivers/freedreno/freedreno_batch.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 Rob Clark + * + * 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 + */ + +#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 00000000000..2134624f833 --- /dev/null +++ b/src/gallium/drivers/freedreno/freedreno_batch.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 Rob Clark + * + * 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 + */ + +#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 65c38913c22..d3a631e3a00 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]; @@ -253,13 +197,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 53b4e1dbaa7..cdf40146881 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" @@ -246,33 +247,19 @@ 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.. the rule here is that you can deref ctx->batch + * in codepaths from pipe_context entrypoints. But not in code- + * paths from fd_batch_flush() (basically, the stuff that gets + * called from GMEM code), since in those code-paths the batch + * you care about is not necessarily the same as ctx->batch. + */ + struct fd_batch *batch; /* Keep track if WAIT_FOR_IDLE is needed for registers we need * to update via RMW: @@ -400,8 +387,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 34b1ff6010c..26164f2109e 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 0d73349057c..54a3247b933 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 7b528f5ccae..817f129a404 100644 --- a/src/gallium/drivers/freedreno/freedreno_query_hw.c +++ b/src/gallium/drivers/freedreno/freedreno_query_hw.c @@ -158,7 +158,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; @@ -181,7 +181,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 96d1d88eeed..41f46a69c3e 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.c +++ b/src/gallium/drivers/freedreno/freedreno_resource.c @@ -830,13 +830,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 330cff9c0fb..b6b91f92c7c 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.30.2