From 7c008c293d7b220eec0c98cefb794cab95ee344e Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 24 Jun 2020 11:28:32 -0700 Subject: [PATCH] freedreno: handle batch flush in resource tracking In rare cases, we can get into situations where the tracking of read/ written resources triggers a flush of the current batch. To handle that, (1) take a reference to the current batch, so it doesn't disappear under us, and (2) check after resource tracking whether the current batch was flushed. If it is, we have to re-do the resource tracking, but since we have a fresh batch, it should not get flushed the second time around. Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/3160 Signed-off-by: Rob Clark Part-of: --- .../drivers/freedreno/freedreno_draw.c | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/gallium/drivers/freedreno/freedreno_draw.c b/src/gallium/drivers/freedreno/freedreno_draw.c index da79a81d521..a5dae976607 100644 --- a/src/gallium/drivers/freedreno/freedreno_draw.c +++ b/src/gallium/drivers/freedreno/freedreno_draw.c @@ -213,8 +213,6 @@ static void fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) { struct fd_context *ctx = fd_context(pctx); - struct fd_batch *batch = fd_context_batch(ctx); - struct pipe_framebuffer_state *pfb = &batch->framebuffer; /* for debugging problems with indirect draw, it is convenient * to be able to emulate it, to determine if game is feeding us @@ -260,6 +258,9 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) } } + struct fd_batch *batch = NULL; + fd_batch_reference(&batch, fd_context_batch(ctx)); + if (ctx->in_discard_blit) { fd_batch_reset(batch); fd_context_all_dirty(ctx); @@ -267,6 +268,16 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) batch_draw_tracking(batch, info); + if (unlikely(ctx->batch != batch)) { + /* The current batch was flushed in batch_draw_tracking() + * so start anew. We know this won't happen a second time + * since we are dealing with a fresh batch: + */ + fd_batch_reference(&batch, fd_context_batch(ctx)); + batch_draw_tracking(batch, info); + assert(ctx->batch == batch); + } + batch->blit = ctx->in_discard_blit; batch->back_blit = ctx->in_shadow; batch->num_draws++; @@ -299,6 +310,7 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) */ fd_fence_ref(&ctx->last_fence, NULL); + struct pipe_framebuffer_state *pfb = &batch->framebuffer; DBG("%p: %ux%u num_draws=%u (%s/%s)", batch, pfb->width, pfb->height, batch->num_draws, util_format_short_name(pipe_surface_format(pfb->cbufs[0])), @@ -316,6 +328,7 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) fd_context_all_dirty(ctx); fd_batch_check_size(batch); + fd_batch_reference(&batch, NULL); if (info == &new_info) pipe_resource_reference(&indexbuf, NULL); @@ -377,13 +390,14 @@ fd_clear(struct pipe_context *pctx, unsigned buffers, unsigned stencil) { struct fd_context *ctx = fd_context(pctx); - struct fd_batch *batch = fd_context_batch(ctx); - struct pipe_framebuffer_state *pfb = &batch->framebuffer; /* TODO: push down the region versions into the tiles */ if (!fd_render_condition_check(pctx)) return; + struct fd_batch *batch = NULL; + fd_batch_reference(&batch, fd_context_batch(ctx)); + if (ctx->in_discard_blit) { fd_batch_reset(batch); fd_context_all_dirty(ctx); @@ -391,12 +405,23 @@ fd_clear(struct pipe_context *pctx, unsigned buffers, batch_clear_tracking(batch, buffers); + if (unlikely(ctx->batch != batch)) { + /* The current batch was flushed in batch_clear_tracking() + * so start anew. We know this won't happen a second time + * since we are dealing with a fresh batch: + */ + fd_batch_reference(&batch, fd_context_batch(ctx)); + batch_clear_tracking(batch, buffers); + assert(ctx->batch == batch); + } + /* Clearing last_fence must come after the batch dependency tracking * (resource_read()/resource_written()), as that can trigger a flush, * re-populating last_fence */ fd_fence_ref(&ctx->last_fence, NULL); + struct pipe_framebuffer_state *pfb = &batch->framebuffer; DBG("%p: %x %ux%u depth=%f, stencil=%u (%s/%s)", batch, buffers, pfb->width, pfb->height, depth, stencil, util_format_short_name(pipe_surface_format(pfb->cbufs[0])), @@ -423,6 +448,7 @@ fd_clear(struct pipe_context *pctx, unsigned buffers, } fd_batch_check_size(batch); + fd_batch_reference(&batch, NULL); } static void -- 2.30.2