broadcom/vc4: Native fence fd support
authorStefan Schake <stschake@gmail.com>
Tue, 24 Apr 2018 22:01:00 +0000 (00:01 +0200)
committerEric Anholt <eric@anholt.net>
Thu, 17 May 2018 15:04:30 +0000 (16:04 +0100)
With the syncobj support in place, lets use it to implement the
EGL_ANDROID_native_fence_sync extension. This mostly follows previous
implementations in freedreno and etnaviv.

v2: Drop the flags (Eric)
    Handle in_fence_fd already in job_submit (Eric)
    Drop extra vc4_fence_context_init (Eric)
    Dup fds with CLOEXEC (Eric)
    Mention exact extension name (Eric)

Signed-off-by: Stefan Schake <stschake@gmail.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
src/gallium/drivers/vc4/vc4_context.c
src/gallium/drivers/vc4/vc4_context.h
src/gallium/drivers/vc4/vc4_fence.c
src/gallium/drivers/vc4/vc4_job.c
src/gallium/drivers/vc4/vc4_screen.c
src/gallium/drivers/vc4/vc4_screen.h

index 0deb3ef85ee4659419774dc5c3f96d1f4edfca5c..9ff39c2655f8259f4c050d4c7ba2e193043f837a 100644 (file)
@@ -59,8 +59,17 @@ vc4_pipe_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence,
 
         if (fence) {
                 struct pipe_screen *screen = pctx->screen;
+                int fd = -1;
+
+                if (flags & PIPE_FLUSH_FENCE_FD) {
+                        /* The vc4_fence takes ownership of the returned fd. */
+                        drmSyncobjExportSyncFile(vc4->fd, vc4->job_syncobj,
+                                                 &fd);
+                }
+
                 struct vc4_fence *f = vc4_fence_create(vc4->screen,
-                                                       vc4->last_emit_seqno);
+                                                       vc4->last_emit_seqno,
+                                                       fd);
                 screen->fence_reference(screen, fence, NULL);
                 *fence = (struct pipe_fence_handle *)f;
         }
@@ -124,8 +133,12 @@ vc4_context_destroy(struct pipe_context *pctx)
 
         vc4_program_fini(pctx);
 
-        if (vc4->screen->has_syncobj)
+        if (vc4->screen->has_syncobj) {
                 drmSyncobjDestroy(vc4->fd, vc4->job_syncobj);
+                drmSyncobjDestroy(vc4->fd, vc4->in_syncobj);
+        }
+        if (vc4->in_fence_fd >= 0)
+                close(vc4->in_fence_fd);
 
         ralloc_free(vc4);
 }
@@ -167,6 +180,10 @@ vc4_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
         if (err)
                 goto fail;
 
+        err = vc4_fence_context_init(vc4);
+        if (err)
+                goto fail;
+
         slab_create_child(&vc4->transfer_pool, &screen->transfer_pool);
 
        vc4->uploader = u_upload_create_default(&vc4->base);
index d094957bb577d8558e998b1de0dbc3181fa93df9..ce8bcffac04a657c7c0ce7868b690b1c4816bc3f 100644 (file)
@@ -411,6 +411,10 @@ struct vc4_context {
 
         /** Handle of syncobj containing the last submitted job fence. */
         uint32_t job_syncobj;
+
+        int in_fence_fd;
+        /** Handle of the syncobj that holds in_fence_fd for submission. */
+        uint32_t in_syncobj;
 };
 
 struct vc4_rasterizer_state {
@@ -506,6 +510,7 @@ void vc4_write_uniforms(struct vc4_context *vc4,
 
 void vc4_flush(struct pipe_context *pctx);
 int vc4_job_init(struct vc4_context *vc4);
+int vc4_fence_context_init(struct vc4_context *vc4);
 struct vc4_job *vc4_get_job(struct vc4_context *vc4,
                             struct pipe_surface *cbuf,
                             struct pipe_surface *zsbuf);
index f61e7c6a5e845884825c144aeeecd6d3bd85c514..7071425595c4fc004d76534abd6041c76e8fe928 100644 (file)
  * fired off as our fence marker.
  */
 
+#include <libsync.h>
+#include <fcntl.h>
+
 #include "util/u_inlines.h"
 
 #include "vc4_screen.h"
+#include "vc4_context.h"
 #include "vc4_bufmgr.h"
 
 struct vc4_fence {
         struct pipe_reference reference;
         uint64_t seqno;
+        int fd;
 };
 
+static inline struct vc4_fence *
+vc4_fence(struct pipe_fence_handle *pfence)
+{
+        return (struct vc4_fence *)pfence;
+}
+
 static void
 vc4_fence_reference(struct pipe_screen *pscreen,
                     struct pipe_fence_handle **pp,
                     struct pipe_fence_handle *pf)
 {
         struct vc4_fence **p = (struct vc4_fence **)pp;
-        struct vc4_fence *f = (struct vc4_fence *)pf;
+        struct vc4_fence *f = vc4_fence(pf);
         struct vc4_fence *old = *p;
 
         if (pipe_reference(&(*p)->reference, &f->reference)) {
+                if (old->fd >= 0)
+                        close(old->fd);
                 free(old);
         }
         *p = f;
@@ -66,13 +79,16 @@ vc4_fence_finish(struct pipe_screen *pscreen,
                  uint64_t timeout_ns)
 {
         struct vc4_screen *screen = vc4_screen(pscreen);
-        struct vc4_fence *f = (struct vc4_fence *)pf;
+        struct vc4_fence *f = vc4_fence(pf);
+
+        if (f->fd >= 0)
+                return sync_wait(f->fd, timeout_ns / 1000000) == 0;
 
         return vc4_wait_seqno(screen, f->seqno, timeout_ns, "fence wait");
 }
 
 struct vc4_fence *
-vc4_fence_create(struct vc4_screen *screen, uint64_t seqno)
+vc4_fence_create(struct vc4_screen *screen, uint64_t seqno, int fd)
 {
         struct vc4_fence *f = calloc(1, sizeof(*f));
 
@@ -81,13 +97,59 @@ vc4_fence_create(struct vc4_screen *screen, uint64_t seqno)
 
         pipe_reference_init(&f->reference, 1);
         f->seqno = seqno;
+        f->fd = fd;
 
         return f;
 }
 
+static void
+vc4_fence_create_fd(struct pipe_context *pctx, struct pipe_fence_handle **pf,
+                    int fd, enum pipe_fd_type type)
+{
+        struct vc4_context *vc4 = vc4_context(pctx);
+        struct vc4_fence **fence = (struct vc4_fence **)pf;
+
+        assert(type == PIPE_FD_TYPE_NATIVE_SYNC);
+        *fence = vc4_fence_create(vc4->screen, vc4->last_emit_seqno,
+                                  fcntl(fd, F_DUPFD_CLOEXEC, 3));
+}
+
+static void
+vc4_fence_server_sync(struct pipe_context *pctx,
+                      struct pipe_fence_handle *pfence)
+{
+        struct vc4_context *vc4 = vc4_context(pctx);
+        struct vc4_fence *fence = vc4_fence(pfence);
+
+        sync_accumulate("vc4", &vc4->in_fence_fd, fence->fd);
+}
+
+static int
+vc4_fence_get_fd(struct pipe_screen *screen, struct pipe_fence_handle *pfence)
+{
+        struct vc4_fence *fence = vc4_fence(pfence);
+
+        return fcntl(fence->fd, F_DUPFD_CLOEXEC, 3);
+}
+
+int
+vc4_fence_context_init(struct vc4_context *vc4)
+{
+        vc4->base.create_fence_fd = vc4_fence_create_fd;
+        vc4->base.fence_server_sync = vc4_fence_server_sync;
+        vc4->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(vc4->fd, DRM_SYNCOBJ_CREATE_SIGNALED,
+                                &vc4->in_syncobj);
+}
+
 void
-vc4_fence_init(struct vc4_screen *screen)
+vc4_fence_screen_init(struct vc4_screen *screen)
 {
         screen->base.fence_reference = vc4_fence_reference;
         screen->base.fence_finish = vc4_fence_finish;
+        screen->base.fence_get_fd = vc4_fence_get_fd;
 }
index 3b0ba8b69cfa38fa8c717cd26276e7478575b8d0..725697658475f2009d059f508d54b75796f9f54f 100644 (file)
@@ -477,9 +477,19 @@ vc4_job_submit(struct vc4_context *vc4, struct vc4_job *job)
         }
         submit.flags |= job->flags;
 
-        if (vc4->screen->has_syncobj)
+        if (vc4->screen->has_syncobj) {
                 submit.out_sync = vc4->job_syncobj;
 
+                if (vc4->in_fence_fd >= 0) {
+                        /* This replaces the fence in the syncobj. */
+                        drmSyncobjImportSyncFile(vc4->fd, vc4->in_syncobj,
+                                                 vc4->in_fence_fd);
+                        submit.in_sync = vc4->in_syncobj;
+                        close(vc4->in_fence_fd);
+                        vc4->in_fence_fd = -1;
+                }
+        }
+
         if (!(vc4_debug & VC4_DEBUG_NORAST)) {
                 int ret;
 
index 5476b8cf10c1c54e95b3ed6ad99c9cacd68e6576..d497cd2e8694cafd1f601f2f16c424de31a0859a 100644 (file)
@@ -148,6 +148,9 @@ vc4_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
         case PIPE_CAP_TEXTURE_BARRIER:
                 return 1;
 
+        case PIPE_CAP_NATIVE_FENCE_FD:
+                return screen->has_syncobj;
+
         case PIPE_CAP_TILE_RASTER_ORDER:
                 return vc4_has_feature(screen,
                                        DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER);
@@ -263,7 +266,6 @@ vc4_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
         case PIPE_CAP_VIEWPORT_SUBPIXEL_BITS:
         case PIPE_CAP_TGSI_ARRAY_COMPONENTS:
         case PIPE_CAP_TGSI_CAN_READ_OUTPUTS:
-        case PIPE_CAP_NATIVE_FENCE_FD:
         case PIPE_CAP_TGSI_FS_FBFETCH:
         case PIPE_CAP_TGSI_MUL_ZERO_WINS:
         case PIPE_CAP_DOUBLES:
@@ -708,7 +710,7 @@ vc4_screen_create(int fd, struct renderonly *ro)
 
         slab_create_parent(&screen->transfer_pool, sizeof(struct vc4_transfer), 16);
 
-        vc4_fence_init(screen);
+        vc4_fence_screen_init(screen);
 
         vc4_debug = debug_get_option_vc4_debug();
         if (vc4_debug & VC4_DEBUG_SHADERDB)
index 438e90a1a2ca93333cd8419f75f4899591ebd7d7..f4550d1c28602f7819aee9e0f3863656f5699d6d 100644 (file)
@@ -119,9 +119,9 @@ vc4_screen_get_compiler_options(struct pipe_screen *pscreen,
 extern uint32_t vc4_debug;
 
 void
-vc4_fence_init(struct vc4_screen *screen);
+vc4_fence_screen_init(struct vc4_screen *screen);
 
 struct vc4_fence *
-vc4_fence_create(struct vc4_screen *screen, uint64_t seqno);
+vc4_fence_create(struct vc4_screen *screen, uint64_t seqno, int fd);
 
 #endif /* VC4_SCREEN_H */