[Mesa-dev] [PATCH 8/8] gallium/u_threaded: avoid syncing in threaded_context_flush

Nicolai Hähnle nhaehnle at gmail.com
Mon Nov 13 14:03:36 UTC 2017


From: Nicolai Hähnle <nicolai.haehnle at 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



More information about the mesa-dev mailing list