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;