From a221f9709efeaf0ac901c7b0568e8aa311aa1b96 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 9 Jul 2018 12:41:46 -0700 Subject: [PATCH] v3d: Fix incorrect handling of two fences created back-to-back. 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 | 43 +++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/gallium/drivers/v3d/v3d_fence.c b/src/gallium/drivers/v3d/v3d_fence.c index f07ea17b0d3..0edcb66d911 100644 --- a/src/gallium/drivers/v3d/v3d_fence.c +++ b/src/gallium/drivers/v3d/v3d_fence.c @@ -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; } -- 2.30.2