From c44163876a2858aea219a08bd2e048b76953cff9 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 14 Jul 2016 10:32:02 -0400 Subject: [PATCH] freedreno: track batch/blit types Add a bit of extra book-keeping about blits and back-blits (from resource shadowing). If the app uploads all mipmap levels, as opposed to uploading the first level and then glGenerateMipmap(), we can discard the back-blit (as opposed to being naive and shadowing the resource for each mipmap level). Also, after a normal blit, we might as well flush the batch immediately, since there is not likely to be further rendering to the surface. Signed-off-by: Rob Clark --- .../drivers/freedreno/freedreno_batch.h | 4 ++- .../drivers/freedreno/freedreno_context.h | 26 +++++++++---------- .../drivers/freedreno/freedreno_draw.c | 16 +++++++----- .../drivers/freedreno/freedreno_resource.c | 9 ++++++- .../drivers/freedreno/freedreno_state.c | 21 ++++++++++++--- 5 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/gallium/drivers/freedreno/freedreno_batch.h b/src/gallium/drivers/freedreno/freedreno_batch.h index 228a1b72bf6..6be196534ab 100644 --- a/src/gallium/drivers/freedreno/freedreno_batch.h +++ b/src/gallium/drivers/freedreno/freedreno_batch.h @@ -93,7 +93,9 @@ struct fd_batch { FD_BUFFER_ALL = FD_BUFFER_COLOR | FD_BUFFER_DEPTH | FD_BUFFER_STENCIL, } cleared, partial_cleared, restore, resolve; - bool needs_flush; + bool needs_flush : 1; + bool blit : 1; + bool back_blit : 1; /* only blit so far is resource shadowing back-blit */ /* To decide whether to render to system memory, keep track of the * number of draws, and whether any of them require multisample, diff --git a/src/gallium/drivers/freedreno/freedreno_context.h b/src/gallium/drivers/freedreno/freedreno_context.h index 45876259fd8..7e25e57d43b 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.h +++ b/src/gallium/drivers/freedreno/freedreno_context.h @@ -161,16 +161,27 @@ struct fd_context { */ struct fd_batch *batch; + /* Are we in process of shadowing a resource? Used to detect recursion + * in transfer_map, and skip unneeded synchronization. + */ + bool in_shadow : 1; + + /* Ie. in blit situation where we no longer care about previous framebuffer + * contents. Main point is to eliminate blits from fd_try_shadow_resource(). + * For example, in case of texture upload + gen-mipmaps. + */ + bool in_blit : 1; + /* Keep track if WAIT_FOR_IDLE is needed for registers we need * to update via RMW: */ - bool needs_wfi; + bool needs_wfi : 1; /* Do we need to re-emit RB_FRAME_BUFFER_DIMENSION? At least on a3xx * it is not a banked context register, so it needs a WFI to update. * Keep track if it has actually changed, to avoid unneeded WFI. * */ - bool needs_rb_fbd; + bool needs_rb_fbd : 1; struct pipe_scissor_state scissor; @@ -244,17 +255,6 @@ struct fd_context { bool cond_cond; /* inverted rendering condition */ uint cond_mode; - /* Are we in process of shadowing a resource? Used to detect recursion - * in transfer_map, and skip unneeded synchronization. - */ - bool in_shadow; - - /* Ie. in blit situation where we no longer care about previous framebuffer - * contents. Main point is to eliminate blits from fd_try_shadow_resource(). - * For example, in case of texture upload + gen-mipmaps. - */ - bool discard; - struct pipe_debug_callback debug; /* GMEM/tile handling fxns: */ diff --git a/src/gallium/drivers/freedreno/freedreno_draw.c b/src/gallium/drivers/freedreno/freedreno_draw.c index fd3da1f20e5..dd4a720dd0e 100644 --- a/src/gallium/drivers/freedreno/freedreno_draw.c +++ b/src/gallium/drivers/freedreno/freedreno_draw.c @@ -84,15 +84,19 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) return; } - if (ctx->discard) { - fd_batch_reset(ctx->batch); - ctx->discard = false; + if (ctx->in_blit) { + fd_batch_reset(batch); + ctx->dirty = ~0; } + batch->blit = ctx->in_blit; + batch->back_blit = ctx->in_shadow; + /* NOTE: needs to be before resource_written(batch->query_buf), otherwise * query_buf may not be created yet. */ fd_hw_query_set_stage(batch, batch->draw, FD_STAGE_DRAW); + /* * Figure out the buffers/features we need: */ @@ -219,9 +223,9 @@ fd_clear(struct pipe_context *pctx, unsigned buffers, if (!fd_render_condition_check(pctx)) return; - if (ctx->discard) { - fd_batch_reset(ctx->batch); - ctx->discard = false; + if (ctx->in_blit) { + fd_batch_reset(batch); + ctx->dirty = ~0; } /* for bookkeeping about which buffers have been cleared (and thus diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c index b6c9488ec65..0e0305885a7 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.c +++ b/src/gallium/drivers/freedreno/freedreno_resource.c @@ -487,6 +487,12 @@ fd_resource_transfer_map(struct pipe_context *pctx, * to wait. */ } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { + if ((usage & PIPE_TRANSFER_WRITE) && rsc->write_batch && + rsc->write_batch->back_blit) { + /* if only thing pending is a back-blit, we can discard it: */ + fd_batch_reset(rsc->write_batch); + } + /* If the GPU is writing to the resource, or if it is reading from the * resource and we're trying to write to it, flush the renders. */ @@ -1057,7 +1063,7 @@ fd_blitter_pipe_begin(struct fd_context *ctx, bool render_cond, bool discard) if (ctx->batch) fd_hw_query_set_stage(ctx->batch, ctx->batch->draw, FD_STAGE_BLIT); - ctx->discard = discard; + ctx->in_blit = discard; } static void @@ -1065,6 +1071,7 @@ fd_blitter_pipe_end(struct fd_context *ctx) { if (ctx->batch) fd_hw_query_set_stage(ctx->batch, ctx->batch->draw, FD_STAGE_NULL); + ctx->in_blit = false; } static void diff --git a/src/gallium/drivers/freedreno/freedreno_state.c b/src/gallium/drivers/freedreno/freedreno_state.c index 849ea08037d..f83fd219f0a 100644 --- a/src/gallium/drivers/freedreno/freedreno_state.c +++ b/src/gallium/drivers/freedreno/freedreno_state.c @@ -119,13 +119,28 @@ fd_set_framebuffer_state(struct pipe_context *pctx, struct pipe_framebuffer_state *cso; if (ctx->screen->reorder) { - struct fd_batch *batch; - if (likely(ctx->batch)) - fd_hw_query_set_stage(ctx->batch, ctx->batch->draw, FD_STAGE_NULL); + struct fd_batch *batch, *old_batch = NULL; + + fd_batch_reference(&old_batch, ctx->batch); + + if (likely(old_batch)) + fd_hw_query_set_stage(old_batch, old_batch->draw, FD_STAGE_NULL); + batch = fd_batch_from_fb(&ctx->screen->batch_cache, ctx, framebuffer); fd_batch_reference(&ctx->batch, NULL); ctx->batch = batch; ctx->dirty = ~0; + + if (old_batch && old_batch->blit && !old_batch->back_blit) { + /* for blits, there is not really much point in hanging on + * to the uncommitted batch (ie. you probably don't blit + * multiple times to the same surface), so we might as + * well go ahead and flush this one: + */ + fd_batch_flush(old_batch); + } + + fd_batch_reference(&old_batch, NULL); } else { DBG("%d: cbufs[0]=%p, zsbuf=%p", ctx->batch->needs_flush, framebuffer->cbufs[0], framebuffer->zsbuf); -- 2.30.2