[Mesa-dev] [PATCH] gallium/radeon: unify and simplify checking for an empty gfx IB

Marek Olšák maraeo at gmail.com
Thu Aug 25 19:20:52 UTC 2016


FYI, I've already committed this because our other team needs this bug fix.

Marek

On Thu, Aug 25, 2016 at 10:56 AM, Marek Olšák <maraeo at gmail.com> wrote:
> From: Marek Olšák <marek.olsak at amd.com>
>
> We can take advantage of the fact that multi_fence does the obvious thing
> with NULL fences.
>
> This fixes unflushed fences that can get stuck due to empty IBs.
> ---
>  src/gallium/drivers/r600/r600_hw_context.c    |  8 +-------
>  src/gallium/drivers/radeon/r600_pipe_common.c | 29 ++++++++++++++++++---------
>  src/gallium/drivers/radeonsi/si_hw_context.c  | 13 +++---------
>  3 files changed, 23 insertions(+), 27 deletions(-)
>
> diff --git a/src/gallium/drivers/r600/r600_hw_context.c b/src/gallium/drivers/r600/r600_hw_context.c
> index 4447393..58ba09d 100644
> --- a/src/gallium/drivers/r600/r600_hw_context.c
> +++ b/src/gallium/drivers/r600/r600_hw_context.c
> @@ -248,28 +248,22 @@ void r600_flush_emit(struct r600_context *rctx)
>         rctx->b.flags = 0;
>  }
>
>  void r600_context_gfx_flush(void *context, unsigned flags,
>                             struct pipe_fence_handle **fence)
>  {
>         struct r600_context *ctx = context;
>         struct radeon_winsys_cs *cs = ctx->b.gfx.cs;
>         struct radeon_winsys *ws = ctx->b.ws;
>
> -       if (!radeon_emitted(cs, ctx->b.initial_gfx_cs_size) &&
> -           (!fence || ctx->b.last_gfx_fence)) {
> -               if (fence)
> -                       ws->fence_reference(fence, ctx->b.last_gfx_fence);
> -               if (!(flags & RADEON_FLUSH_ASYNC))
> -                       ws->cs_sync_flush(cs);
> +       if (!radeon_emitted(cs, ctx->b.initial_gfx_cs_size))
>                 return;
> -       }
>
>         r600_preflush_suspend_features(&ctx->b);
>
>         /* flush the framebuffer cache */
>         ctx->b.flags |= R600_CONTEXT_FLUSH_AND_INV |
>                       R600_CONTEXT_FLUSH_AND_INV_CB |
>                       R600_CONTEXT_FLUSH_AND_INV_DB |
>                       R600_CONTEXT_FLUSH_AND_INV_CB_META |
>                       R600_CONTEXT_FLUSH_AND_INV_DB_META |
>                       R600_CONTEXT_WAIT_3D_IDLE |
> diff --git a/src/gallium/drivers/radeon/r600_pipe_common.c b/src/gallium/drivers/radeon/r600_pipe_common.c
> index ab620eb..b1da22f 100644
> --- a/src/gallium/drivers/radeon/r600_pipe_common.c
> +++ b/src/gallium/drivers/radeon/r600_pipe_common.c
> @@ -258,54 +258,63 @@ void r600_postflush_resume_features(struct r600_common_context *ctx)
>         if (!LIST_IS_EMPTY(&ctx->active_queries))
>                 r600_resume_queries(ctx);
>  }
>
>  static void r600_flush_from_st(struct pipe_context *ctx,
>                                struct pipe_fence_handle **fence,
>                                unsigned flags)
>  {
>         struct pipe_screen *screen = ctx->screen;
>         struct r600_common_context *rctx = (struct r600_common_context *)ctx;
> +       struct radeon_winsys *ws = rctx->ws;
>         unsigned rflags = 0;
>         struct pipe_fence_handle *gfx_fence = NULL;
>         struct pipe_fence_handle *sdma_fence = NULL;
>         bool deferred_fence = false;
>
>         if (flags & PIPE_FLUSH_END_OF_FRAME)
>                 rflags |= RADEON_FLUSH_END_OF_FRAME;
>         if (flags & PIPE_FLUSH_DEFERRED)
>                 rflags |= RADEON_FLUSH_ASYNC;
>
>         if (rctx->dma.cs) {
>                 rctx->dma.flush(rctx, rflags, fence ? &sdma_fence : NULL);
>         }
>
> -       /* Instead of flushing, create a deferred fence. Constraints:
> -        * - The state tracker must allow a deferred flush.
> -        * - The state tracker must request a fence.
> -        * Thread safety in fence_finish must be ensured by the state tracker.
> -        */
> -       if (flags & PIPE_FLUSH_DEFERRED && fence) {
> -               gfx_fence = rctx->ws->cs_get_next_fence(rctx->gfx.cs);
> -               deferred_fence = true;
> +       if (!radeon_emitted(rctx->gfx.cs, rctx->initial_gfx_cs_size)) {
> +               if (fence)
> +                       ws->fence_reference(&gfx_fence, rctx->last_gfx_fence);
> +               if (!(rflags & RADEON_FLUSH_ASYNC))
> +                       ws->cs_sync_flush(rctx->gfx.cs);
>         } else {
> -               rctx->gfx.flush(rctx, rflags, fence ? &gfx_fence : NULL);
> +               /* Instead of flushing, create a deferred fence. Constraints:
> +                * - The state tracker must allow a deferred flush.
> +                * - The state tracker must request a fence.
> +                * Thread safety in fence_finish must be ensured by the state tracker.
> +                */
> +               if (flags & PIPE_FLUSH_DEFERRED && fence) {
> +                       gfx_fence = rctx->ws->cs_get_next_fence(rctx->gfx.cs);
> +                       deferred_fence = true;
> +               } else {
> +                       rctx->gfx.flush(rctx, rflags, fence ? &gfx_fence : NULL);
> +               }
>         }
>
>         /* Both engines can signal out of order, so we need to keep both fences. */
> -       if (gfx_fence || sdma_fence) {
> +       if (fence) {
>                 struct r600_multi_fence *multi_fence =
>                         CALLOC_STRUCT(r600_multi_fence);
>                 if (!multi_fence)
>                         return;
>
>                 multi_fence->reference.count = 1;
> +               /* If both fences are NULL, fence_finish will always return true. */
>                 multi_fence->gfx = gfx_fence;
>                 multi_fence->sdma = sdma_fence;
>
>                 if (deferred_fence) {
>                         multi_fence->gfx_unflushed.ctx = rctx;
>                         multi_fence->gfx_unflushed.ib_index = rctx->num_gfx_cs_flushes;
>                 }
>
>                 screen->fence_reference(screen, fence, NULL);
>                 *fence = (struct pipe_fence_handle*)multi_fence;
> diff --git a/src/gallium/drivers/radeonsi/si_hw_context.c b/src/gallium/drivers/radeonsi/si_hw_context.c
> index 49d1a35..aeccb2d 100644
> --- a/src/gallium/drivers/radeonsi/si_hw_context.c
> +++ b/src/gallium/drivers/radeonsi/si_hw_context.c
> @@ -93,31 +93,24 @@ void si_need_cs_space(struct si_context *ctx)
>  void si_context_gfx_flush(void *context, unsigned flags,
>                           struct pipe_fence_handle **fence)
>  {
>         struct si_context *ctx = context;
>         struct radeon_winsys_cs *cs = ctx->b.gfx.cs;
>         struct radeon_winsys *ws = ctx->b.ws;
>
>         if (ctx->gfx_flush_in_progress)
>                 return;
>
> -       ctx->gfx_flush_in_progress = true;
> -
> -       if (!radeon_emitted(cs, ctx->b.initial_gfx_cs_size) &&
> -           (!fence || ctx->b.last_gfx_fence)) {
> -               if (fence)
> -                       ws->fence_reference(fence, ctx->b.last_gfx_fence);
> -               if (!(flags & RADEON_FLUSH_ASYNC))
> -                       ws->cs_sync_flush(cs);
> -               ctx->gfx_flush_in_progress = false;
> +       if (!radeon_emitted(cs, ctx->b.initial_gfx_cs_size))
>                 return;
> -       }
> +
> +       ctx->gfx_flush_in_progress = true;
>
>         r600_preflush_suspend_features(&ctx->b);
>
>         ctx->b.flags |= SI_CONTEXT_CS_PARTIAL_FLUSH |
>                         SI_CONTEXT_PS_PARTIAL_FLUSH;
>
>         /* DRM 3.1.0 doesn't flush TC for VI correctly. */
>         if (ctx->b.chip_class == VI && ctx->b.screen->info.drm_minor <= 1)
>                 ctx->b.flags |= SI_CONTEXT_INV_GLOBAL_L2 |
>                                 SI_CONTEXT_INV_VMEM_L1;
> --
> 2.7.4
>


More information about the mesa-dev mailing list