From ddb7fadaf8b1aa3004e72d6b0e28e465f8f45fba Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 4 Oct 2018 08:05:49 -0400 Subject: [PATCH] freedreno: avoid no-op flushes by re-using last-fence Noticed that with webgl (in chromium, at least) we end up generating a lot of no-op submits just to get a fence. Tracking the last fence and returning that if there is no rendering since last flush avoids this. Signed-off-by: Rob Clark --- .../drivers/freedreno/a6xx/fd6_blitter.c | 3 +++ .../drivers/freedreno/freedreno_context.c | 19 +++++++++++++++++-- .../drivers/freedreno/freedreno_context.h | 6 ++++++ .../drivers/freedreno/freedreno_draw.c | 5 +++++ .../drivers/freedreno/freedreno_resource.c | 3 +++ 5 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_blitter.c b/src/gallium/drivers/freedreno/a6xx/fd6_blitter.c index c962fe79970..30840955b61 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_blitter.c +++ b/src/gallium/drivers/freedreno/a6xx/fd6_blitter.c @@ -28,6 +28,7 @@ #include "util/u_dump.h" #include "freedreno_blitter.h" +#include "freedreno_fence.h" #include "freedreno_resource.h" #include "fd6_blitter.h" @@ -486,6 +487,8 @@ fd6_blit(struct pipe_context *pctx, const struct pipe_blit_info *info) return; } + fd_fence_ref(pctx->screen, &ctx->last_fence, NULL); + batch = fd_bc_alloc_batch(&ctx->screen->batch_cache, ctx, true); fd6_emit_restore(batch, batch->draw); diff --git a/src/gallium/drivers/freedreno/freedreno_context.c b/src/gallium/drivers/freedreno/freedreno_context.c index 5c56be29b13..a08acea7a48 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.c +++ b/src/gallium/drivers/freedreno/freedreno_context.c @@ -49,14 +49,24 @@ fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep, DBG("%p: flush: flags=%x\n", ctx->batch, flags); + /* if no rendering since last flush, ie. app just decided it needed + * a fence, re-use the last one: + */ + if (ctx->last_fence) { + fd_fence_ref(pctx->screen, &fence, ctx->last_fence); + goto out; + } + if (!batch) return; /* Take a ref to the batch's fence (batch can be unref'd when flushed: */ fd_fence_ref(pctx->screen, &fence, batch->fence); - if (flags & PIPE_FLUSH_FENCE_FD) - batch->needs_out_fence_fd = true; + /* TODO is it worth trying to figure out if app is using fence-fd's, to + * avoid requesting one every batch? + */ + batch->needs_out_fence_fd = true; if (!ctx->screen->reorder) { fd_batch_flush(batch, true, false); @@ -66,9 +76,12 @@ fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep, fd_bc_flush(&ctx->screen->batch_cache, ctx); } +out: if (fencep) fd_fence_ref(pctx->screen, fencep, fence); + fd_fence_ref(pctx->screen, &ctx->last_fence, fence); + fd_fence_ref(pctx->screen, &fence, NULL); } @@ -137,6 +150,8 @@ fd_context_destroy(struct pipe_context *pctx) DBG(""); + fd_fence_ref(pctx->screen, &ctx->last_fence, NULL); + if (ctx->screen->reorder && util_queue_is_initialized(&ctx->flush_queue)) util_queue_destroy(&ctx->flush_queue); diff --git a/src/gallium/drivers/freedreno/freedreno_context.h b/src/gallium/drivers/freedreno/freedreno_context.h index 2ebfaca2e5f..01038d30919 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.h +++ b/src/gallium/drivers/freedreno/freedreno_context.h @@ -230,6 +230,12 @@ struct fd_context { */ struct fd_batch *batch; + /* NULL if there has been rendering since last flush. Otherwise + * keeps a reference to the last fence so we can re-use it rather + * than having to flush no-op batch. + */ + struct pipe_fence_handle *last_fence; + /* Are we in process of shadowing a resource? Used to detect recursion * in transfer_map, and skip unneeded synchronization. */ diff --git a/src/gallium/drivers/freedreno/freedreno_draw.c b/src/gallium/drivers/freedreno/freedreno_draw.c index 5f9706c0b6e..02ea41e2c4e 100644 --- a/src/gallium/drivers/freedreno/freedreno_draw.c +++ b/src/gallium/drivers/freedreno/freedreno_draw.c @@ -34,6 +34,7 @@ #include "freedreno_draw.h" #include "freedreno_context.h" +#include "freedreno_fence.h" #include "freedreno_state.h" #include "freedreno_resource.h" #include "freedreno_query_acc.h" @@ -98,6 +99,8 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) return; } + fd_fence_ref(pctx->screen, &ctx->last_fence, NULL); + /* Upload a user index buffer. */ struct pipe_resource *indexbuf = NULL; unsigned index_offset = 0; @@ -382,6 +385,8 @@ fd_clear(struct pipe_context *pctx, unsigned buffers, if (!fd_render_condition_check(pctx)) return; + fd_fence_ref(pctx->screen, &ctx->last_fence, NULL); + if (ctx->in_blit) { fd_batch_reset(batch); fd_context_all_dirty(ctx); diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c index 759ae7d28ae..54d73858962 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.c +++ b/src/gallium/drivers/freedreno/freedreno_resource.c @@ -35,6 +35,7 @@ #include "freedreno_resource.h" #include "freedreno_batch_cache.h" +#include "freedreno_fence.h" #include "freedreno_screen.h" #include "freedreno_surface.h" #include "freedreno_context.h" @@ -1070,6 +1071,8 @@ void fd_blitter_pipe_begin(struct fd_context *ctx, bool render_cond, bool discard, enum fd_render_stage stage) { + fd_fence_ref(ctx->base.screen, &ctx->last_fence, NULL); + util_blitter_save_fragment_constant_buffer_slot(ctx->blitter, ctx->constbuf[PIPE_SHADER_FRAGMENT].cb); util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vtx.vertexbuf.vb); -- 2.30.2