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 <robdclark@gmail.com>
This commit is contained in:
Rob Clark 2018-10-04 08:05:49 -04:00
parent 01194cd582
commit ddb7fadaf8
5 changed files with 34 additions and 2 deletions

View file

@ -28,6 +28,7 @@
#include "util/u_dump.h" #include "util/u_dump.h"
#include "freedreno_blitter.h" #include "freedreno_blitter.h"
#include "freedreno_fence.h"
#include "freedreno_resource.h" #include "freedreno_resource.h"
#include "fd6_blitter.h" #include "fd6_blitter.h"
@ -486,6 +487,8 @@ fd6_blit(struct pipe_context *pctx, const struct pipe_blit_info *info)
return; return;
} }
fd_fence_ref(pctx->screen, &ctx->last_fence, NULL);
batch = fd_bc_alloc_batch(&ctx->screen->batch_cache, ctx, true); batch = fd_bc_alloc_batch(&ctx->screen->batch_cache, ctx, true);
fd6_emit_restore(batch, batch->draw); fd6_emit_restore(batch, batch->draw);

View file

@ -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); 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) if (!batch)
return; return;
/* Take a ref to the batch's fence (batch can be unref'd when flushed: */ /* Take a ref to the batch's fence (batch can be unref'd when flushed: */
fd_fence_ref(pctx->screen, &fence, batch->fence); fd_fence_ref(pctx->screen, &fence, batch->fence);
if (flags & PIPE_FLUSH_FENCE_FD) /* TODO is it worth trying to figure out if app is using fence-fd's, to
batch->needs_out_fence_fd = true; * avoid requesting one every batch?
*/
batch->needs_out_fence_fd = true;
if (!ctx->screen->reorder) { if (!ctx->screen->reorder) {
fd_batch_flush(batch, true, false); 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); fd_bc_flush(&ctx->screen->batch_cache, ctx);
} }
out:
if (fencep) if (fencep)
fd_fence_ref(pctx->screen, fencep, fence); fd_fence_ref(pctx->screen, fencep, fence);
fd_fence_ref(pctx->screen, &ctx->last_fence, fence);
fd_fence_ref(pctx->screen, &fence, NULL); fd_fence_ref(pctx->screen, &fence, NULL);
} }
@ -137,6 +150,8 @@ fd_context_destroy(struct pipe_context *pctx)
DBG(""); DBG("");
fd_fence_ref(pctx->screen, &ctx->last_fence, NULL);
if (ctx->screen->reorder && util_queue_is_initialized(&ctx->flush_queue)) if (ctx->screen->reorder && util_queue_is_initialized(&ctx->flush_queue))
util_queue_destroy(&ctx->flush_queue); util_queue_destroy(&ctx->flush_queue);

View file

@ -230,6 +230,12 @@ struct fd_context {
*/ */
struct fd_batch *batch; 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 /* Are we in process of shadowing a resource? Used to detect recursion
* in transfer_map, and skip unneeded synchronization. * in transfer_map, and skip unneeded synchronization.
*/ */

View file

@ -34,6 +34,7 @@
#include "freedreno_draw.h" #include "freedreno_draw.h"
#include "freedreno_context.h" #include "freedreno_context.h"
#include "freedreno_fence.h"
#include "freedreno_state.h" #include "freedreno_state.h"
#include "freedreno_resource.h" #include "freedreno_resource.h"
#include "freedreno_query_acc.h" #include "freedreno_query_acc.h"
@ -98,6 +99,8 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
return; return;
} }
fd_fence_ref(pctx->screen, &ctx->last_fence, NULL);
/* Upload a user index buffer. */ /* Upload a user index buffer. */
struct pipe_resource *indexbuf = NULL; struct pipe_resource *indexbuf = NULL;
unsigned index_offset = 0; unsigned index_offset = 0;
@ -382,6 +385,8 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
if (!fd_render_condition_check(pctx)) if (!fd_render_condition_check(pctx))
return; return;
fd_fence_ref(pctx->screen, &ctx->last_fence, NULL);
if (ctx->in_blit) { if (ctx->in_blit) {
fd_batch_reset(batch); fd_batch_reset(batch);
fd_context_all_dirty(ctx); fd_context_all_dirty(ctx);

View file

@ -35,6 +35,7 @@
#include "freedreno_resource.h" #include "freedreno_resource.h"
#include "freedreno_batch_cache.h" #include "freedreno_batch_cache.h"
#include "freedreno_fence.h"
#include "freedreno_screen.h" #include "freedreno_screen.h"
#include "freedreno_surface.h" #include "freedreno_surface.h"
#include "freedreno_context.h" #include "freedreno_context.h"
@ -1070,6 +1071,8 @@ void
fd_blitter_pipe_begin(struct fd_context *ctx, bool render_cond, bool discard, fd_blitter_pipe_begin(struct fd_context *ctx, bool render_cond, bool discard,
enum fd_render_stage stage) enum fd_render_stage stage)
{ {
fd_fence_ref(ctx->base.screen, &ctx->last_fence, NULL);
util_blitter_save_fragment_constant_buffer_slot(ctx->blitter, util_blitter_save_fragment_constant_buffer_slot(ctx->blitter,
ctx->constbuf[PIPE_SHADER_FRAGMENT].cb); ctx->constbuf[PIPE_SHADER_FRAGMENT].cb);
util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vtx.vertexbuf.vb); util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vtx.vertexbuf.vb);