Module: Mesa
Branch: main
Commit: d04538653bdfd5317dc8cf45528e017a7362b205
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=d04538653bdfd5317dc8cf45528e017a7362b205

Author: Iago Toral Quiroga <ito...@igalia.com>
Date:   Thu Nov  2 11:12:07 2023 +0100

v3d: implement support for PIPE_CAP_NATIVE_FENCE_FD

Reviewed-by: Alejandro PiƱeiro <apinhe...@igalia.com>
Tested-by: Roman Stratiienko <r.stratiie...@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20602>

---

 src/gallium/drivers/v3d/v3d_context.c        | 21 +++++++-
 src/gallium/drivers/v3d/v3d_context.h        |  9 +++-
 src/gallium/drivers/v3d/v3d_fence.c          | 72 ++++++++++++++++++++++------
 src/gallium/drivers/v3d/v3d_job.c            | 23 +++++++--
 src/gallium/drivers/v3d/v3d_screen.c         |  5 +-
 src/gallium/drivers/v3d/v3d_screen.h         |  2 +-
 src/gallium/drivers/v3d/v3dx_query_perfcnt.c | 13 ++++-
 7 files changed, 120 insertions(+), 25 deletions(-)

diff --git a/src/gallium/drivers/v3d/v3d_context.c 
b/src/gallium/drivers/v3d/v3d_context.c
index 240c99672f9..6c121567d72 100644
--- a/src/gallium/drivers/v3d/v3d_context.c
+++ b/src/gallium/drivers/v3d/v3d_context.c
@@ -61,8 +61,21 @@ v3d_pipe_flush(struct pipe_context *pctx, struct 
pipe_fence_handle **fence,
         v3d_flush(pctx);
 
         if (fence) {
+                int fd = -1;
+                /* Snapshot the last V3D rendering's out fence.  We'd rather
+                 * have another syncobj instead of a sync file, but this is all
+                 * we get. (HandleToFD/FDToHandle just gives you another 
syncobj
+                 * ID for the same syncobj).
+                 */
+                drmSyncobjExportSyncFile(v3d->fd, v3d->out_sync, &fd);
+                if (fd == -1) {
+                        fprintf(stderr, "export failed\n");
+                        *fence = NULL;
+                        return;
+                }
+
                 struct pipe_screen *screen = pctx->screen;
-                struct v3d_fence *f = v3d_fence_create(v3d);
+                struct v3d_fence *f = v3d_fence_create(v3d, fd);
                 screen->fence_reference(screen, fence, NULL);
                 *fence = (struct pipe_fence_handle *)f;
         }
@@ -292,6 +305,8 @@ v3d_context_destroy(struct pipe_context *pctx)
 
         v3d_program_fini(pctx);
 
+        v3d_fence_context_finish(v3d);
+
         ralloc_free(v3d);
 }
 
@@ -385,6 +400,10 @@ v3d_context_create(struct pipe_screen *pscreen, void 
*priv, unsigned flags)
                                               PIPE_BIND_CONSTANT_BUFFER,
                                               PIPE_USAGE_STREAM, 0);
 
+        ret = v3d_fence_context_init(v3d);
+        if (ret)
+                goto fail;
+
         v3d->blitter = util_blitter_create(pctx);
         if (!v3d->blitter)
                 goto fail;
diff --git a/src/gallium/drivers/v3d/v3d_context.h 
b/src/gallium/drivers/v3d/v3d_context.h
index 2f27693fef6..ea86df23913 100644
--- a/src/gallium/drivers/v3d/v3d_context.h
+++ b/src/gallium/drivers/v3d/v3d_context.h
@@ -626,6 +626,10 @@ struct v3d_context {
         struct pipe_query *cond_query;
         bool cond_cond;
         enum pipe_render_cond_flag cond_mode;
+
+        int in_fence_fd;
+        /** Handle of the syncobj that holds in_fence_fd for submission. */
+        uint32_t in_syncobj;
         /** @} */
 };
 
@@ -781,12 +785,15 @@ bool v3d_generate_mipmap(struct pipe_context *pctx,
 void
 v3d_fence_unreference(struct v3d_fence **fence);
 
-struct v3d_fence *v3d_fence_create(struct v3d_context *v3d);
+struct v3d_fence *v3d_fence_create(struct v3d_context *v3d, int fd);
 
 bool v3d_fence_wait(struct v3d_screen *screen,
                     struct v3d_fence *fence,
                     uint64_t timeout_ns);
 
+int v3d_fence_context_init(struct v3d_context *v3d);
+void v3d_fence_context_finish(struct v3d_context *v3d);
+
 void v3d_update_primitive_counters(struct v3d_context *v3d);
 
 bool v3d_line_smoothing_enabled(struct v3d_context *v3d);
diff --git a/src/gallium/drivers/v3d/v3d_fence.c 
b/src/gallium/drivers/v3d/v3d_fence.c
index 3abfcd7c750..082548c4970 100644
--- a/src/gallium/drivers/v3d/v3d_fence.c
+++ b/src/gallium/drivers/v3d/v3d_fence.c
@@ -33,6 +33,8 @@
  * the same BOs), so we can just use the seqno of the last rendering we'd
  * fired off as our fence marker.
  */
+#include <fcntl.h>
+#include <libsync.h>
 
 #include "util/u_inlines.h"
 #include "util/os_time.h"
@@ -117,32 +119,74 @@ v3d_fence_finish(struct pipe_screen *pscreen,
 }
 
 struct v3d_fence *
-v3d_fence_create(struct v3d_context *v3d)
+v3d_fence_create(struct v3d_context *v3d, int fd)
 {
         struct v3d_fence *f = calloc(1, sizeof(*f));
         if (!f)
                 return NULL;
 
-        /* Snapshot the last V3D rendering's out fence.  We'd rather have
-         * another syncobj instead of a sync file, but this is all we get.
-         * (HandleToFD/FDToHandle just gives you another syncobj ID for the
-         * same syncobj).
-         */
-        drmSyncobjExportSyncFile(v3d->fd, v3d->out_sync, &f->fd);
-        if (f->fd == -1) {
-                fprintf(stderr, "export failed\n");
-                free(f);
-                return NULL;
-        }
-
+        f->fd = fd;
         pipe_reference_init(&f->reference, 1);
 
         return f;
 }
 
+static void
+v3d_fence_create_fd(struct pipe_context *pctx, struct pipe_fence_handle **pf,
+                    int fd, enum pipe_fd_type type)
+{
+        struct v3d_context *v3d = (struct v3d_context *)pctx;
+        struct v3d_fence **fence = (struct v3d_fence **)pf;
+
+        assert(type == PIPE_FD_TYPE_NATIVE_SYNC);
+        *fence = v3d_fence_create(v3d, fcntl(fd, F_DUPFD_CLOEXEC, 3));
+}
+
+static void
+v3d_fence_server_sync(struct pipe_context *pctx,
+                      struct pipe_fence_handle *pfence)
+{
+        struct v3d_context *v3d = (struct v3d_context*)pctx;
+        struct v3d_fence *fence = (struct v3d_fence *)pfence;
+
+        sync_accumulate("v3d", &v3d->in_fence_fd, fence->fd);
+}
+
+static int
+v3d_fence_get_fd(struct pipe_screen *screen, struct pipe_fence_handle *pfence)
+{
+        struct v3d_fence *fence = (struct v3d_fence *) pfence;
+        return fcntl(fence->fd, F_DUPFD_CLOEXEC, 3);
+}
+
+int
+v3d_fence_context_init(struct v3d_context *v3d)
+{
+        v3d->base.create_fence_fd = v3d_fence_create_fd;
+        v3d->base.fence_server_sync = v3d_fence_server_sync;
+        v3d->in_fence_fd = -1;
+
+        /* Since we initialize the in_fence_fd to -1 (no wait necessary),
+         * we also need to initialize our in_syncobj as signaled.
+         */
+        return drmSyncobjCreate(v3d->fd, DRM_SYNCOBJ_CREATE_SIGNALED,
+                                &v3d->in_syncobj);
+}
+
+void
+v3d_fence_context_finish(struct v3d_context *v3d)
+{
+        drmSyncobjDestroy(v3d->fd, v3d->in_syncobj);
+        if (v3d->in_fence_fd >= 0) {
+                close(v3d->in_fence_fd);
+                v3d->in_fence_fd = -1;
+        }
+}
+
 void
-v3d_fence_init(struct v3d_screen *screen)
+v3d_fence_screen_init(struct v3d_screen *screen)
 {
         screen->base.fence_reference = v3d_fence_reference;
         screen->base.fence_finish = v3d_fence_finish;
+        screen->base.fence_get_fd = v3d_fence_get_fd;
 }
diff --git a/src/gallium/drivers/v3d/v3d_job.c 
b/src/gallium/drivers/v3d/v3d_job.c
index 68b67a5ce10..1a7632a0e44 100644
--- a/src/gallium/drivers/v3d/v3d_job.c
+++ b/src/gallium/drivers/v3d/v3d_job.c
@@ -27,6 +27,7 @@
  */
 
 #include <xf86drm.h>
+#include <libsync.h>
 #include "v3d_context.h"
 /* The OQ/semaphore packets are the same across V3D versions. */
 #define V3D_VERSION 42
@@ -514,11 +515,23 @@ v3d_job_submit(struct v3d_context *v3d, struct v3d_job 
*job)
         if (cl_offset(&job->bcl) > 0)
                 v3d_X(devinfo, bcl_epilogue)(v3d, job);
 
-        /* While the RCL will implicitly depend on the last RCL to have
-         * finished, we also need to block on any previous TFU job we may have
-         * dispatched.
-         */
-        job->submit.in_sync_rcl = v3d->out_sync;
+        if (v3d->in_fence_fd >= 0) {
+                /* PIPE_CAP_NATIVE_FENCE */
+                if (drmSyncobjImportSyncFile(v3d->fd, v3d->in_syncobj,
+                                             v3d->in_fence_fd)) {
+                   fprintf(stderr, "Failed to import native fence.\n");
+                } else {
+                   job->submit.in_sync_bcl = v3d->in_syncobj;
+                }
+                close(v3d->in_fence_fd);
+                v3d->in_fence_fd = -1;
+        } else {
+                /* While the RCL will implicitly depend on the last RCL to have
+                 * finished, we also need to block on any previous TFU job we
+                 * may have dispatched.
+                 */
+                job->submit.in_sync_rcl = v3d->out_sync;
+        }
 
         /* Update the sync object for the last rendering by our context. */
         job->submit.out_sync = v3d->out_sync;
diff --git a/src/gallium/drivers/v3d/v3d_screen.c 
b/src/gallium/drivers/v3d/v3d_screen.c
index 44d5b90c44d..f965b62ec78 100644
--- a/src/gallium/drivers/v3d/v3d_screen.c
+++ b/src/gallium/drivers/v3d/v3d_screen.c
@@ -291,6 +291,9 @@ v3d_screen_get_param(struct pipe_screen *pscreen, enum 
pipe_cap param)
         case PIPE_CAP_IMAGE_STORE_FORMATTED:
                 return false;
 
+        case PIPE_CAP_NATIVE_FENCE_FD:
+                return true;
+
         default:
                 return u_pipe_screen_get_param_defaults(pscreen, param);
         }
@@ -926,7 +929,7 @@ v3d_screen_create(int fd, const struct pipe_screen_config 
*config,
                 v3d_has_feature(screen, DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH);
         screen->has_perfmon = v3d_has_feature(screen, 
DRM_V3D_PARAM_SUPPORTS_PERFMON);
 
-        v3d_fence_init(screen);
+        v3d_fence_screen_init(screen);
 
         v3d_process_debug_variable();
 
diff --git a/src/gallium/drivers/v3d/v3d_screen.h 
b/src/gallium/drivers/v3d/v3d_screen.h
index 1da9b83c965..6954e473bb9 100644
--- a/src/gallium/drivers/v3d/v3d_screen.h
+++ b/src/gallium/drivers/v3d/v3d_screen.h
@@ -102,7 +102,7 @@ struct pipe_screen *v3d_screen_create(int fd,
                                       struct renderonly *ro);
 
 void
-v3d_fence_init(struct v3d_screen *screen);
+v3d_fence_screen_init(struct v3d_screen *screen);
 
 #ifdef ENABLE_SHADER_CACHE
 void
diff --git a/src/gallium/drivers/v3d/v3dx_query_perfcnt.c 
b/src/gallium/drivers/v3d/v3dx_query_perfcnt.c
index 431aad14b4f..7bc708074e7 100644
--- a/src/gallium/drivers/v3d/v3dx_query_perfcnt.c
+++ b/src/gallium/drivers/v3d/v3dx_query_perfcnt.c
@@ -175,8 +175,17 @@ v3d_end_query_perfcnt(struct v3d_context *v3d, struct 
v3d_query *query)
         /* Get a copy of latest submitted job's fence to wait for its
          * completion
          */
-        if (v3d->active_perfmon->job_submitted)
-                v3d->active_perfmon->last_job_fence = v3d_fence_create(v3d);
+        if (v3d->active_perfmon->job_submitted) {
+                int fd = -1;
+                drmSyncobjExportSyncFile(v3d->fd, v3d->out_sync, &fd);
+                if (fd == -1) {
+                        fprintf(stderr, "export failed\n");
+                        v3d->active_perfmon->last_job_fence = NULL;
+                } else {
+                        v3d->active_perfmon->last_job_fence =
+                                v3d_fence_create(v3d, fd);
+                }
+        }
 
         v3d->active_perfmon = NULL;
 

Reply via email to