From: Nicolai Hähnle <nicolai.haeh...@amd.com> We could always do the flush asynchronously, but if we're going to wait for a fence anyway and the driver thread is currently idle, the additional communication overhead isn't worth it. --- src/gallium/auxiliary/util/u_threaded_context.c | 16 +++++++++++++--- src/gallium/auxiliary/util/u_threaded_context.h | 3 ++- src/gallium/drivers/radeonsi/si_fence.c | 3 ++- 3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/src/gallium/auxiliary/util/u_threaded_context.c b/src/gallium/auxiliary/util/u_threaded_context.c index ecd42724548..eb8f7011682 100644 --- a/src/gallium/auxiliary/util/u_threaded_context.c +++ b/src/gallium/auxiliary/util/u_threaded_context.c @@ -223,27 +223,37 @@ _tc_sync(struct threaded_context *tc, const char *info, const char *func) /** * Call this from fence_finish for same-context fence waits of deferred fences * that haven't been flushed yet. * * The passed pipe_context must be the one passed to pipe_screen::fence_finish, * i.e., the wrapped one. */ void threaded_context_flush(struct pipe_context *_pipe, - struct tc_unflushed_batch_token *token) + struct tc_unflushed_batch_token *token, + bool prefer_async) { struct threaded_context *tc = threaded_context(_pipe); /* This is called from the state-tracker / application thread. */ - if (token->tc && token->tc == tc) - tc_sync(token->tc); + if (token->tc && token->tc == tc) { + struct tc_batch *last = &tc->batch_slots[tc->last]; + + /* Prefer to do the flush in the driver thread if it is already + * running. That should be better for cache locality. + */ + if (prefer_async || !util_queue_fence_is_signalled(&last->fence)) + tc_batch_flush(tc); + else + tc_sync(token->tc); + } } static void tc_set_resource_reference(struct pipe_resource **dst, struct pipe_resource *src) { *dst = NULL; pipe_resource_reference(dst, src); } void diff --git a/src/gallium/auxiliary/util/u_threaded_context.h b/src/gallium/auxiliary/util/u_threaded_context.h index e1ba73607db..ed653b7600d 100644 --- a/src/gallium/auxiliary/util/u_threaded_context.h +++ b/src/gallium/auxiliary/util/u_threaded_context.h @@ -373,21 +373,22 @@ struct pipe_context *threaded_context_unwrap_sync(struct pipe_context *pipe); struct pipe_context * threaded_context_create(struct pipe_context *pipe, struct slab_parent_pool *parent_transfer_pool, tc_replace_buffer_storage_func replace_buffer, tc_create_fence_func create_fence, struct threaded_context **out); void threaded_context_flush(struct pipe_context *_pipe, - struct tc_unflushed_batch_token *token); + struct tc_unflushed_batch_token *token, + bool prefer_async); static inline struct threaded_context * threaded_context(struct pipe_context *pipe) { return (struct threaded_context*)pipe; } static inline struct threaded_resource * threaded_resource(struct pipe_resource *res) { diff --git a/src/gallium/drivers/radeonsi/si_fence.c b/src/gallium/drivers/radeonsi/si_fence.c index 5163d652c83..9d6bcfe1027 100644 --- a/src/gallium/drivers/radeonsi/si_fence.c +++ b/src/gallium/drivers/radeonsi/si_fence.c @@ -196,21 +196,22 @@ static boolean si_fence_finish(struct pipe_screen *screen, if (rfence->tc_token) { /* Ensure that si_flush_from_st will be called for * this fence, but only if we're in the API thread * where the context is current. * * Note that the batch containing the flush may already * be in flight in the driver thread, so the fence * may not be ready yet when this call returns. */ - threaded_context_flush(ctx, rfence->tc_token); + threaded_context_flush(ctx, rfence->tc_token, + timeout == 0); } if (timeout == PIPE_TIMEOUT_INFINITE) { util_queue_fence_wait(&rfence->ready); } else { if (!util_queue_fence_wait_timeout(&rfence->ready, abs_timeout)) return false; } if (timeout && timeout != PIPE_TIMEOUT_INFINITE) { -- 2.11.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev