radeonsi: avoid syncing the driver thread in si_fence_finish

It is really only required when we need to flush for deferred fences.

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
This commit is contained in:
Nicolai Hähnle 2017-11-10 10:58:10 +01:00
parent 3db1ce01b1
commit bc65dcab3b
3 changed files with 49 additions and 37 deletions

View file

@ -407,6 +407,14 @@ threaded_transfer(struct pipe_transfer *transfer)
return (struct threaded_transfer*)transfer;
}
static inline struct pipe_context *
threaded_context_unwrap_unsync(struct pipe_context *pipe)
{
if (!pipe || !pipe->priv)
return pipe;
return (struct pipe_context*)pipe->priv;
}
static inline void
tc_unflushed_batch_token_reference(struct tc_unflushed_batch_token **dst,
struct tc_unflushed_batch_token *src)

View file

@ -188,12 +188,8 @@ static boolean si_fence_finish(struct pipe_screen *screen,
{
struct radeon_winsys *rws = ((struct r600_common_screen*)screen)->ws;
struct si_multi_fence *rfence = (struct si_multi_fence *)fence;
struct r600_common_context *rctx;
int64_t abs_timeout = os_time_get_absolute_timeout(timeout);
ctx = threaded_context_unwrap_sync(ctx);
rctx = ctx ? (struct r600_common_context*)ctx : NULL;
if (!util_queue_fence_is_signalled(&rfence->ready)) {
if (!timeout)
return false;
@ -245,41 +241,46 @@ static boolean si_fence_finish(struct pipe_screen *screen,
}
/* Flush the gfx IB if it hasn't been flushed yet. */
if (rctx &&
rfence->gfx_unflushed.ctx == rctx &&
rfence->gfx_unflushed.ib_index == rctx->num_gfx_cs_flushes) {
/* Section 4.1.2 (Signaling) of the OpenGL 4.6 (Core profile)
* spec says:
*
* "If the sync object being blocked upon will not be
* signaled in finite time (for example, by an associated
* fence command issued previously, but not yet flushed to
* the graphics pipeline), then ClientWaitSync may hang
* forever. To help prevent this behavior, if
* ClientWaitSync is called and all of the following are
* true:
*
* * the SYNC_FLUSH_COMMANDS_BIT bit is set in flags,
* * sync is unsignaled when ClientWaitSync is called,
* * and the calls to ClientWaitSync and FenceSync were
* issued from the same context,
*
* then the GL will behave as if the equivalent of Flush
* were inserted immediately after the creation of sync."
*
* This means we need to flush for such fences even when we're
* not going to wait.
*/
rctx->gfx.flush(rctx, timeout ? 0 : RADEON_FLUSH_ASYNC, NULL);
rfence->gfx_unflushed.ctx = NULL;
if (ctx && rfence->gfx_unflushed.ctx) {
struct si_context *sctx;
if (!timeout)
return false;
sctx = (struct si_context *)threaded_context_unwrap_unsync(ctx);
if (rfence->gfx_unflushed.ctx == &sctx->b &&
rfence->gfx_unflushed.ib_index == sctx->b.num_gfx_cs_flushes) {
/* Section 4.1.2 (Signaling) of the OpenGL 4.6 (Core profile)
* spec says:
*
* "If the sync object being blocked upon will not be
* signaled in finite time (for example, by an associated
* fence command issued previously, but not yet flushed to
* the graphics pipeline), then ClientWaitSync may hang
* forever. To help prevent this behavior, if
* ClientWaitSync is called and all of the following are
* true:
*
* * the SYNC_FLUSH_COMMANDS_BIT bit is set in flags,
* * sync is unsignaled when ClientWaitSync is called,
* * and the calls to ClientWaitSync and FenceSync were
* issued from the same context,
*
* then the GL will behave as if the equivalent of Flush
* were inserted immediately after the creation of sync."
*
* This means we need to flush for such fences even when we're
* not going to wait.
*/
threaded_context_unwrap_sync(ctx);
sctx->b.gfx.flush(&sctx->b, timeout ? 0 : RADEON_FLUSH_ASYNC, NULL);
rfence->gfx_unflushed.ctx = NULL;
/* Recompute the timeout after all that. */
if (timeout && timeout != PIPE_TIMEOUT_INFINITE) {
int64_t time = os_time_get_nano();
timeout = abs_timeout > time ? abs_timeout - time : 0;
if (!timeout)
return false;
/* Recompute the timeout after all that. */
if (timeout && timeout != PIPE_TIMEOUT_INFINITE) {
int64_t time = os_time_get_nano();
timeout = abs_timeout > time ? abs_timeout - time : 0;
}
}
}

View file

@ -129,6 +129,9 @@ void si_context_gfx_flush(void *context, unsigned flags,
ws->cs_flush(cs, flags, &ctx->b.last_gfx_fence);
if (fence)
ws->fence_reference(fence, ctx->b.last_gfx_fence);
/* This must be after cs_flush returns, since the context's API
* thread can concurrently read this value in si_fence_finish. */
ctx->b.num_gfx_cs_flushes++;
/* Check VM faults if needed. */