From 290f827928b3845bb50e4bd2f27b878e136af36f Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 28 Oct 2020 09:51:15 -0700 Subject: [PATCH] freedreno: Make fd_context_batch() return a reference This protects better against another context triggering a batch flush and unref while the first context is doing resource tracking. Signed-off-by: Rob Clark Part-of: --- .../drivers/freedreno/a4xx/fd4_query.c | 1 + .../drivers/freedreno/freedreno_batch_cache.c | 2 ++ .../drivers/freedreno/freedreno_context.c | 36 +++++++++++++------ .../drivers/freedreno/freedreno_draw.c | 12 +++---- .../drivers/freedreno/freedreno_query_acc.c | 7 ++-- .../drivers/freedreno/freedreno_query_hw.c | 4 +++ 6 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_query.c b/src/gallium/drivers/freedreno/a4xx/fd4_query.c index 465e4b3c03c..73a5af1268c 100644 --- a/src/gallium/drivers/freedreno/a4xx/fd4_query.c +++ b/src/gallium/drivers/freedreno/a4xx/fd4_query.c @@ -119,6 +119,7 @@ time_elapsed_enable(struct fd_context *ctx, struct fd_ringbuffer *ring) fd_wfi(batch, ring); OUT_PKT0(ring, REG_A4XX_CP_PERFCTR_CP_SEL_0, 1); OUT_RING(ring, CP_ALWAYS_COUNT); + fd_batch_reference(&batch, NULL); } static struct fd_hw_sample * diff --git a/src/gallium/drivers/freedreno/freedreno_batch_cache.c b/src/gallium/drivers/freedreno/freedreno_batch_cache.c index 0d0064c6ce7..4f918932e27 100644 --- a/src/gallium/drivers/freedreno/freedreno_batch_cache.c +++ b/src/gallium/drivers/freedreno/freedreno_batch_cache.c @@ -159,6 +159,8 @@ bc_flush(struct fd_batch_cache *cache, struct fd_context *ctx, bool deferred) } } + fd_batch_reference_locked(¤t_batch, NULL); + fd_screen_unlock(ctx->screen); } else { fd_screen_unlock(ctx->screen); diff --git a/src/gallium/drivers/freedreno/freedreno_context.c b/src/gallium/drivers/freedreno/freedreno_context.c index 0d3c5e6c15e..9393965e22a 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.c +++ b/src/gallium/drivers/freedreno/freedreno_context.c @@ -51,10 +51,14 @@ fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep, { struct fd_context *ctx = fd_context(pctx); struct pipe_fence_handle *fence = NULL; - // TODO we want to lookup batch if it exists, but not create one if not. - struct fd_batch *batch = fd_context_batch(ctx); + struct fd_batch *batch = NULL; - DBG("%p: flush: flags=%x", ctx->batch, flags); + /* We want to lookup current batch if it exists, but not create a new + * one if not (unless we need a fence) + */ + fd_batch_reference(&batch, ctx->batch); + + DBG("%p: flush: flags=%x", batch, flags); /* In some sequence of events, we can end up with a last_fence that is * not an "fd" fence, which results in eglDupNativeFenceFDANDROID() @@ -73,7 +77,9 @@ fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fencep, goto out; } - if (!batch) { + if (fencep && !batch) { + batch = fd_context_batch(ctx); + } else if (!batch) { fd_bc_dump(ctx->screen, "%p: NULL batch, remaining:\n", ctx); return; } @@ -105,6 +111,8 @@ out: fd_fence_ref(&fence, NULL); + fd_batch_reference(&batch, NULL); + if (flags & PIPE_FLUSH_END_OF_FRAME) fd_log_eof(ctx); } @@ -232,18 +240,26 @@ fd_context_switch_to(struct fd_context *ctx, struct fd_batch *batch) } } +/** + * Return a reference to the current batch, caller must unref. + */ struct fd_batch * fd_context_batch(struct fd_context *ctx) { - if (unlikely(!ctx->batch)) { - struct fd_batch *batch = - fd_batch_from_fb(&ctx->screen->batch_cache, ctx, &ctx->framebuffer); + struct fd_batch *batch = NULL; + + fd_batch_reference(&batch, ctx->batch); + + if (unlikely(!batch)) { + batch = fd_batch_from_fb(&ctx->screen->batch_cache, ctx, &ctx->framebuffer); util_copy_framebuffer_state(&batch->framebuffer, &ctx->framebuffer); - ctx->batch = batch; + fd_batch_reference(&ctx->batch, batch); fd_context_all_dirty(ctx); } - fd_context_switch_to(ctx, ctx->batch); - return ctx->batch; + + fd_context_switch_to(ctx, batch); + + return batch; } void diff --git a/src/gallium/drivers/freedreno/freedreno_draw.c b/src/gallium/drivers/freedreno/freedreno_draw.c index 6e492e7461f..5db8391b55f 100644 --- a/src/gallium/drivers/freedreno/freedreno_draw.c +++ b/src/gallium/drivers/freedreno/freedreno_draw.c @@ -259,8 +259,7 @@ 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)); + struct fd_batch *batch = fd_context_batch(ctx); if (ctx->in_discard_blit) { fd_batch_reset(batch); @@ -274,7 +273,8 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) * 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)); + fd_batch_reference(&batch, NULL); + batch = fd_context_batch(ctx); batch_draw_tracking(batch, info); assert(ctx->batch == batch); } @@ -397,8 +397,7 @@ fd_clear(struct pipe_context *pctx, unsigned buffers, if (!fd_render_condition_check(pctx)) return; - struct fd_batch *batch = NULL; - fd_batch_reference(&batch, fd_context_batch(ctx)); + struct fd_batch *batch = fd_context_batch(ctx); if (ctx->in_discard_blit) { fd_batch_reset(batch); @@ -412,7 +411,8 @@ fd_clear(struct pipe_context *pctx, unsigned buffers, * 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)); + fd_batch_reference(&batch, NULL); + batch = fd_context_batch(ctx); batch_clear_tracking(batch, buffers); assert(ctx->batch == batch); } diff --git a/src/gallium/drivers/freedreno/freedreno_query_acc.c b/src/gallium/drivers/freedreno/freedreno_query_acc.c index 888f7763d85..f02e22c4f43 100644 --- a/src/gallium/drivers/freedreno/freedreno_query_acc.c +++ b/src/gallium/drivers/freedreno/freedreno_query_acc.c @@ -112,8 +112,11 @@ fd_acc_begin_query(struct fd_context *ctx, struct fd_query *q) /* TIMESTAMP/GPU_FINISHED and don't do normal bracketing at draw time, we * need to just emit the capture at this moment. */ - if (skip_begin_query(q->type)) - fd_acc_query_resume(aq, fd_context_batch(ctx)); + if (skip_begin_query(q->type)) { + struct fd_batch *batch = fd_context_batch(ctx); + fd_acc_query_resume(aq, batch); + fd_batch_reference(&batch, NULL); + } } static void diff --git a/src/gallium/drivers/freedreno/freedreno_query_hw.c b/src/gallium/drivers/freedreno/freedreno_query_hw.c index 5be59613ff5..28d270adb2d 100644 --- a/src/gallium/drivers/freedreno/freedreno_query_hw.c +++ b/src/gallium/drivers/freedreno/freedreno_query_hw.c @@ -149,6 +149,8 @@ fd_hw_begin_query(struct fd_context *ctx, struct fd_query *q) /* add to active list: */ assert(list_is_empty(&hq->list)); list_addtail(&hq->list, &ctx->hw_active_queries); + + fd_batch_reference(&batch, NULL); } static void @@ -164,6 +166,8 @@ fd_hw_end_query(struct fd_context *ctx, struct fd_query *q) /* remove from active list: */ list_delinit(&hq->list); + + fd_batch_reference(&batch, NULL); } /* helper to get ptr to specified sample: */