From b0acc3a5628c6c6dd669cbb7cff2d974b175605e Mon Sep 17 00:00:00 2001 From: Stefan Schake Date: Wed, 25 Apr 2018 00:01:00 +0200 Subject: [PATCH] broadcom/vc4: Native fence fd support 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 Reviewed-by: Eric Anholt --- src/gallium/drivers/vc4/vc4_context.c | 21 +++++++- src/gallium/drivers/vc4/vc4_context.h | 5 ++ src/gallium/drivers/vc4/vc4_fence.c | 70 +++++++++++++++++++++++++-- src/gallium/drivers/vc4/vc4_job.c | 12 ++++- src/gallium/drivers/vc4/vc4_screen.c | 6 ++- src/gallium/drivers/vc4/vc4_screen.h | 4 +- 6 files changed, 107 insertions(+), 11 deletions(-) diff --git a/src/gallium/drivers/vc4/vc4_context.c b/src/gallium/drivers/vc4/vc4_context.c index 0deb3ef85ee..9ff39c2655f 100644 --- a/src/gallium/drivers/vc4/vc4_context.c +++ b/src/gallium/drivers/vc4/vc4_context.c @@ -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); diff --git a/src/gallium/drivers/vc4/vc4_context.h b/src/gallium/drivers/vc4/vc4_context.h index d094957bb57..ce8bcffac04 100644 --- a/src/gallium/drivers/vc4/vc4_context.h +++ b/src/gallium/drivers/vc4/vc4_context.h @@ -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); diff --git a/src/gallium/drivers/vc4/vc4_fence.c b/src/gallium/drivers/vc4/vc4_fence.c index f61e7c6a5e8..7071425595c 100644 --- a/src/gallium/drivers/vc4/vc4_fence.c +++ b/src/gallium/drivers/vc4/vc4_fence.c @@ -34,26 +34,39 @@ * fired off as our fence marker. */ +#include +#include + #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; } diff --git a/src/gallium/drivers/vc4/vc4_job.c b/src/gallium/drivers/vc4/vc4_job.c index 3b0ba8b69cf..72569765847 100644 --- a/src/gallium/drivers/vc4/vc4_job.c +++ b/src/gallium/drivers/vc4/vc4_job.c @@ -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; diff --git a/src/gallium/drivers/vc4/vc4_screen.c b/src/gallium/drivers/vc4/vc4_screen.c index 5476b8cf10c..d497cd2e869 100644 --- a/src/gallium/drivers/vc4/vc4_screen.c +++ b/src/gallium/drivers/vc4/vc4_screen.c @@ -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) diff --git a/src/gallium/drivers/vc4/vc4_screen.h b/src/gallium/drivers/vc4/vc4_screen.h index 438e90a1a2c..f4550d1c286 100644 --- a/src/gallium/drivers/vc4/vc4_screen.h +++ b/src/gallium/drivers/vc4/vc4_screen.h @@ -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 */ -- 2.30.2