v3d: Fix incorrect handling of two fences created back-to-back.
authorEric Anholt <eric@anholt.net>
Mon, 9 Jul 2018 19:41:46 +0000 (12:41 -0700)
committerEric Anholt <eric@anholt.net>
Fri, 20 Jul 2018 18:11:29 +0000 (11:11 -0700)
Recreating our context's syncobj with ALREADY_SIGNALED meant that if you
created two fences in a row, then waiting on the second would succeed
immediately.  Instead, export a sync file in the gallium fence (since we
don't have a syncobj clone ioctl), and just create a new syncobj to wait
on whenever we need to.

Noticed while debugging
dEQP-GLES3.functional.fence_sync.client_wait_sync_finish

src/gallium/drivers/v3d/v3d_fence.c

index f07ea17b0d3e1cb99a42609affd0764ac931d4d4..0edcb66d911217285ff082d05973907a410703e7 100644 (file)
@@ -42,7 +42,7 @@
 
 struct v3d_fence {
         struct pipe_reference reference;
-        uint32_t sync;
+        int fd;
 };
 
 static void
@@ -50,13 +50,12 @@ v3d_fence_reference(struct pipe_screen *pscreen,
                     struct pipe_fence_handle **pp,
                     struct pipe_fence_handle *pf)
 {
-        struct v3d_screen *screen = v3d_screen(pscreen);
         struct v3d_fence **p = (struct v3d_fence **)pp;
         struct v3d_fence *f = (struct v3d_fence *)pf;
         struct v3d_fence *old = *p;
 
         if (pipe_reference(&(*p)->reference, &f->reference)) {
-                drmSyncobjDestroy(screen->fd, old->sync);
+                close(old->fd);
                 free(old);
         }
         *p = f;
@@ -70,12 +69,31 @@ v3d_fence_finish(struct pipe_screen *pscreen,
 {
         struct v3d_screen *screen = v3d_screen(pscreen);
         struct v3d_fence *f = (struct v3d_fence *)pf;
+        int ret;
+
+        unsigned syncobj;
+        ret = drmSyncobjCreate(screen->fd, 0, &syncobj);
+        if (ret) {
+                fprintf(stderr, "Failed to create syncobj to wait on: %d\n",
+                        ret);
+                return false;
+        }
+
+        drmSyncobjImportSyncFile(screen->fd, syncobj, f->fd);
+        if (ret) {
+                fprintf(stderr, "Failed to import fence to syncobj: %d\n", ret);
+                return false;
+        }
 
         uint64_t abs_timeout = os_time_get_absolute_timeout(timeout_ns);
         if (abs_timeout == OS_TIMEOUT_INFINITE)
                 abs_timeout = INT64_MAX;
-        return drmSyncobjWait(screen->fd, &f->sync, 1, abs_timeout,
-                              0, NULL) >= 0;
+
+        ret = drmSyncobjWait(screen->fd, &syncobj, 1, abs_timeout, 0, NULL);
+
+        drmSyncobjDestroy(screen->fd, syncobj);
+
+        return ret >= 0;
 }
 
 struct v3d_fence *
@@ -85,18 +103,19 @@ v3d_fence_create(struct v3d_context *v3d)
         if (!f)
                 return NULL;
 
-        uint32_t new_sync;
-        /* Make a new sync object for the context. */
-        int ret = drmSyncobjCreate(v3d->fd, DRM_SYNCOBJ_CREATE_SIGNALED,
-                                   &new_sync);
-        if (ret) {
+        /* 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;
         }
 
         pipe_reference_init(&f->reference, 1);
-        f->sync = v3d->out_sync;
-        v3d->out_sync = new_sync;
 
         return f;
 }