[Mesa-dev] [PATCH 6/7] radeonsi: implement pipe_context::server_fence_sync

Marek Olšák maraeo at gmail.com
Wed Sep 6 09:34:29 UTC 2017


From: Marek Olšák <marek.olsak at amd.com>

This will be more useful once we have sync_file support.
---
 src/gallium/drivers/radeon/r600_pipe_common.c | 44 +++++++++++++++++++++++++++
 src/gallium/drivers/radeon/radeon_winsys.h    |  7 +++++
 src/gallium/winsys/amdgpu/drm/amdgpu_cs.c     | 16 ++++++++++
 3 files changed, 67 insertions(+)

diff --git a/src/gallium/drivers/radeon/r600_pipe_common.c b/src/gallium/drivers/radeon/r600_pipe_common.c
index 5e05b60..46a5aa1 100644
--- a/src/gallium/drivers/radeon/r600_pipe_common.c
+++ b/src/gallium/drivers/radeon/r600_pipe_common.c
@@ -387,20 +387,63 @@ void r600_postflush_resume_features(struct r600_common_context *ctx)
 	if (ctx->streamout.suspended) {
 		ctx->streamout.append_bitmask = ctx->streamout.enabled_mask;
 		r600_streamout_buffers_dirty(ctx);
 	}
 
 	/* resume queries */
 	if (!LIST_IS_EMPTY(&ctx->active_queries))
 		r600_resume_queries(ctx);
 }
 
+static void r600_add_fence_dependency(struct r600_common_context *rctx,
+				      struct pipe_fence_handle *fence)
+{
+	struct radeon_winsys *ws = rctx->ws;
+
+	if (rctx->dma.cs)
+		ws->cs_add_fence_dependency(rctx->dma.cs, fence);
+	ws->cs_add_fence_dependency(rctx->gfx.cs, fence);
+}
+
+static void r600_fence_server_sync(struct pipe_context *ctx,
+				   struct pipe_fence_handle *fence)
+{
+	struct r600_common_context *rctx = (struct r600_common_context *)ctx;
+	struct r600_multi_fence *rfence = (struct r600_multi_fence *)fence;
+
+	/* Only amdgpu needs to handle fence dependencies.
+	 * radeon synchronizes all rings by default.
+	 */
+	if (rctx->screen->info.drm_major == 2)
+		return;
+
+	/* Only imported fences need to be handled by fence_server_sync,
+	 * because the winsys handles synchronizations automatically for BOs
+	 * within the process.
+	 *
+	 * Simply skip unflushed fences here, and the winsys will drop no-op
+	 * dependencies (i.e. dependencies within the same ring).
+	 */
+	if (rfence->gfx_unflushed.ctx)
+		return;
+
+	/* All unflushed commands will not start execution before
+	 * this fence dependency is signalled.
+	 *
+	 * Should we flush the context to allow more GPU parallelism?
+	 */
+	if (rfence->sdma)
+		r600_add_fence_dependency(rctx, rfence->sdma);
+	if (rfence->gfx)
+		r600_add_fence_dependency(rctx, rfence->gfx);
+}
+
 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;
 	struct pipe_fence_handle *gfx_fence = NULL;
 	struct pipe_fence_handle *sdma_fence = NULL;
 	bool deferred_fence = false;
@@ -660,20 +703,21 @@ bool r600_common_context_init(struct r600_common_context *rctx,
 
 	rctx->b.invalidate_resource = r600_invalidate_resource;
 	rctx->b.resource_commit = r600_resource_commit;
 	rctx->b.transfer_map = u_transfer_map_vtbl;
 	rctx->b.transfer_flush_region = u_transfer_flush_region_vtbl;
 	rctx->b.transfer_unmap = u_transfer_unmap_vtbl;
 	rctx->b.texture_subdata = u_default_texture_subdata;
 	rctx->b.memory_barrier = r600_memory_barrier;
 	rctx->b.flush = r600_flush_from_st;
 	rctx->b.set_debug_callback = r600_set_debug_callback;
+	rctx->b.fence_server_sync = r600_fence_server_sync;
 	rctx->dma_clear_buffer = r600_dma_clear_buffer_fallback;
 
 	/* evergreen_compute.c has a special codepath for global buffers.
 	 * Everything else can use the direct path.
 	 */
 	if ((rscreen->chip_class == EVERGREEN || rscreen->chip_class == CAYMAN) &&
 	    (context_flags & PIPE_CONTEXT_COMPUTE_ONLY))
 		rctx->b.buffer_subdata = u_default_buffer_subdata;
 	else
 		rctx->b.buffer_subdata = r600_buffer_subdata;
diff --git a/src/gallium/drivers/radeon/radeon_winsys.h b/src/gallium/drivers/radeon/radeon_winsys.h
index f0a0a92..99e22e0 100644
--- a/src/gallium/drivers/radeon/radeon_winsys.h
+++ b/src/gallium/drivers/radeon/radeon_winsys.h
@@ -567,20 +567,27 @@ struct radeon_winsys {
                                enum radeon_feature_id fid,
                                bool enable);
      /**
       * Make sure all asynchronous flush of the cs have completed
       *
       * \param cs        A command stream.
       */
     void (*cs_sync_flush)(struct radeon_winsys_cs *cs);
 
     /**
+     * Add a fence dependency to the CS, so that the CS will wait for
+     * the fence before execution.
+     */
+    void (*cs_add_fence_dependency)(struct radeon_winsys_cs *cs,
+                                    struct pipe_fence_handle *fence);
+
+    /**
      * Wait for the fence and return true if the fence has been signalled.
      * The timeout of 0 will only return the status.
      * The timeout of PIPE_TIMEOUT_INFINITE will always wait until the fence
      * is signalled.
      */
     bool (*fence_wait)(struct radeon_winsys *ws,
                        struct pipe_fence_handle *fence,
                        uint64_t timeout);
 
     /**
diff --git a/src/gallium/winsys/amdgpu/drm/amdgpu_cs.c b/src/gallium/winsys/amdgpu/drm/amdgpu_cs.c
index ca6021c..1d7ea34 100644
--- a/src/gallium/winsys/amdgpu/drm/amdgpu_cs.c
+++ b/src/gallium/winsys/amdgpu/drm/amdgpu_cs.c
@@ -929,20 +929,35 @@ static bool is_noop_fence_dependency(struct amdgpu_cs *acs,
 
    if (fence->ctx == acs->ctx &&
        fence->fence.ip_type == cs->request.ip_type &&
        fence->fence.ip_instance == cs->request.ip_instance &&
        fence->fence.ring == cs->request.ring)
       return true;
 
    return amdgpu_fence_wait((void *)fence, 0, false);
 }
 
+static void amdgpu_cs_add_fence_dependency(struct radeon_winsys_cs *rws,
+                                           struct pipe_fence_handle *pfence)
+{
+   struct amdgpu_cs *acs = amdgpu_cs(rws);
+   struct amdgpu_cs_context *cs = acs->csc;
+   struct amdgpu_fence *fence = (struct amdgpu_fence*)pfence;
+
+   if (is_noop_fence_dependency(acs, fence))
+      return;
+
+   unsigned idx = add_fence_dependency_entry(cs);
+   amdgpu_fence_reference(&cs->fence_dependencies[idx],
+                          (struct pipe_fence_handle*)fence);
+}
+
 static void amdgpu_add_bo_fence_dependencies(struct amdgpu_cs *acs,
                                              struct amdgpu_cs_buffer *buffer)
 {
    struct amdgpu_cs_context *cs = acs->csc;
    struct amdgpu_winsys_bo *bo = buffer->bo;
    unsigned new_num_fences = 0;
 
    for (unsigned j = 0; j < bo->num_fences; ++j) {
       struct amdgpu_fence *bo_fence = (void *)bo->fences[j];
 
@@ -1390,13 +1405,14 @@ void amdgpu_cs_init_functions(struct amdgpu_winsys *ws)
    ws->base.cs_create = amdgpu_cs_create;
    ws->base.cs_destroy = amdgpu_cs_destroy;
    ws->base.cs_add_buffer = amdgpu_cs_add_buffer;
    ws->base.cs_validate = amdgpu_cs_validate;
    ws->base.cs_check_space = amdgpu_cs_check_space;
    ws->base.cs_get_buffer_list = amdgpu_cs_get_buffer_list;
    ws->base.cs_flush = amdgpu_cs_flush;
    ws->base.cs_get_next_fence = amdgpu_cs_get_next_fence;
    ws->base.cs_is_buffer_referenced = amdgpu_bo_is_referenced;
    ws->base.cs_sync_flush = amdgpu_cs_sync_flush;
+   ws->base.cs_add_fence_dependency = amdgpu_cs_add_fence_dependency;
    ws->base.fence_wait = amdgpu_fence_wait_rel_timeout;
    ws->base.fence_reference = amdgpu_fence_reference;
 }
-- 
2.7.4



More information about the mesa-dev mailing list