From 1e3a8fd41dcca13a376a3fc835250c5d2843056d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis-Francis=20Ratt=C3=A9-Boulianne?= Date: Fri, 9 Jul 2021 01:06:38 -0400 Subject: [PATCH 1/3] vrend: Prepare for async fence callback support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Once we retire fences directly in the sync thread, we will also need to check queries in the same loop as virgl_renderer_poll() will no longer be called. In order to do that safely, we need to lock around operations on the query waiting list. We also need to keep track of the current context for the sync thread given we need to update it before checking query status. Signed-off-by: Louis-Francis Ratté-Boulianne Reviewed-by: Chia-I Wu Reviewed-by: Ryan Neph --- src/vrend_renderer.c | 66 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index 26a9f872e..66266e1fe 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -311,10 +311,14 @@ struct global_renderer_state { struct vrend_context *current_ctx; struct vrend_context *current_hw_ctx; + /* fence_mutex should be locked before using the query list + * if async fence callback are enabled + */ struct list_head waiting_query_list; struct list_head fence_list; struct list_head fence_wait_list; struct vrend_fence *fence_waiting; + struct vrend_context *current_sync_thread_ctx; int gl_major_ver; int gl_minor_ver; @@ -347,6 +351,8 @@ struct global_renderer_state { uint32_t use_explicit_locations : 1; /* threaded sync */ uint32_t stop_sync_thread : 1; + /* async fence callback */ + bool use_async_fence_cb : 1; /* Needed on GLES to inject a TCS */ uint32_t bgra_srgb_emulation_loaded : 1; @@ -5897,6 +5903,18 @@ static GLenum tgsitargettogltarget(const enum pipe_texture_target target, int nr return PIPE_BUFFER; } +static inline void lock_sync(void) +{ + if (vrend_state.sync_thread && vrend_state.use_async_fence_cb) + pipe_mutex_lock(vrend_state.fence_mutex); +} + +static inline void unlock_sync(void) +{ + if (vrend_state.sync_thread && vrend_state.use_async_fence_cb) + pipe_mutex_unlock(vrend_state.fence_mutex); +} + static void vrend_free_sync_thread(void) { if (!vrend_state.sync_thread) @@ -5993,11 +6011,15 @@ static bool do_wait(struct vrend_fence *fence, bool can_block) return done; } +static void vrend_renderer_check_queries_locked(void); + static void wait_sync(struct vrend_fence *fence) { do_wait(fence, /* can_block */ true); pipe_mutex_lock(vrend_state.fence_mutex); + if (vrend_state.use_async_fence_cb) + vrend_renderer_check_queries_locked(); list_addtail(&fence->fences, &vrend_state.fence_list); vrend_state.fence_waiting = NULL; pipe_mutex_unlock(vrend_state.fence_mutex); @@ -6385,7 +6407,12 @@ static void vrend_destroy_sub_context(struct vrend_sub_context *sub) vrend_set_num_vbo_sub(sub, 0); vrend_resource_reference((struct vrend_resource **)&sub->ib.buffer, NULL); + /* need to lock mutex before destroying queries, we could + * be checking these in the sync thread */ + lock_sync(); vrend_object_fini_ctx_table(sub->object_hash); + unlock_sync(); + vrend_clicbs->destroy_gl_context(sub->gl_context); list_del(&sub->head); @@ -9349,8 +9376,6 @@ int vrend_renderer_create_fence(struct vrend_context *ctx, return ENOMEM; } -static void vrend_renderer_check_queries(void); - static bool need_fence_retire_signal_locked(struct vrend_fence *fence, const struct list_head *signaled_list) { @@ -9421,7 +9446,8 @@ void vrend_renderer_check_fences(void) if (LIST_IS_EMPTY(&retired_fences)) return; - vrend_renderer_check_queries(); + /* no need to lock when not using a sync thread */ + vrend_renderer_check_queries_locked(); LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &retired_fences, fences) { struct vrend_context *ctx = fence->ctx; @@ -9465,7 +9491,7 @@ vrend_update_oq_samples_multiplier(struct vrend_context *ctx) } -static bool vrend_check_query(struct vrend_query *query) +static bool vrend_check_query_locked(struct vrend_query *query) { struct virgl_host_query_state state; bool ret; @@ -9496,13 +9522,33 @@ static bool vrend_check_query(struct vrend_query *query) return true; } -static void vrend_renderer_check_queries(void) +static bool vrend_hw_switch_query_context(struct vrend_context *ctx) +{ + if (vrend_state.use_async_fence_cb) { + if (!ctx) + return false; + + if (ctx == vrend_state.current_sync_thread_ctx) + return true; + + if (ctx->ctx_id != 0 && ctx->in_error) + return false; + + vrend_clicbs->make_current(ctx->sub->gl_context); + vrend_state.current_sync_thread_ctx = ctx; + return true; + } else { + return vrend_hw_switch_context(ctx, true); + } +} + +static void vrend_renderer_check_queries_locked(void) { struct vrend_query *query, *stor; LIST_FOR_EACH_ENTRY_SAFE(query, stor, &vrend_state.waiting_query_list, waiting_queries) { - if (!vrend_hw_switch_context(query->ctx, true) || - vrend_check_query(query)) + if (!vrend_hw_switch_query_context(query->ctx) || + vrend_check_query_locked(query)) list_delinit(&query->waiting_queries); } } @@ -9673,7 +9719,9 @@ int vrend_begin_query(struct vrend_context *ctx, uint32_t handle) if (q->index > 0 && !has_feature(feat_transform_feedback3)) return EINVAL; + lock_sync(); list_delinit(&q->waiting_queries); + unlock_sync(); if (q->gltype == GL_TIMESTAMP) return 0; @@ -9724,12 +9772,14 @@ void vrend_get_query_result(struct vrend_context *ctx, uint32_t handle, if (!q) return; - ret = vrend_check_query(q); + lock_sync(); + ret = vrend_check_query_locked(q); if (ret) { list_delinit(&q->waiting_queries); } else if (LIST_IS_EMPTY(&q->waiting_queries)) { list_addtail(&q->waiting_queries, &vrend_state.waiting_query_list); } + unlock_sync(); } #define COPY_QUERY_RESULT_TO_BUFFER(resid, offset, pvalue, size, multiplier) \ -- GitLab From 23c4ef5aa35c754330ea0c73ac902b27d4dc5e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis-Francis=20Ratt=C3=A9-Boulianne?= Date: Fri, 9 Jul 2021 01:15:04 -0400 Subject: [PATCH 2/3] vrend: Add VREND_USE_ASYNC_FENCE_CB flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It indicates that fences should be retired directly from the sync thread when enabled. Signed-off-by: Louis-Francis Ratté-Boulianne Reviewed-by: Chia-I Wu Reviewed-by: Ryan Neph --- src/vrend_renderer.c | 42 +++++++++++++++++++++++++++++++++--------- src/vrend_renderer.h | 5 +++-- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index 66266e1fe..f941b8f6e 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -6015,15 +6015,27 @@ static void vrend_renderer_check_queries_locked(void); static void wait_sync(struct vrend_fence *fence) { + struct vrend_context *ctx = fence->ctx; + do_wait(fence, /* can_block */ true); pipe_mutex_lock(vrend_state.fence_mutex); - if (vrend_state.use_async_fence_cb) + if (vrend_state.use_async_fence_cb) { vrend_renderer_check_queries_locked(); - list_addtail(&fence->fences, &vrend_state.fence_list); + /* to be able to call free_fence_locked without locking */ + list_inithead(&fence->fences); + } else { + list_addtail(&fence->fences, &vrend_state.fence_list); + } vrend_state.fence_waiting = NULL; pipe_mutex_unlock(vrend_state.fence_mutex); + if (vrend_state.use_async_fence_cb) { + ctx->fence_retire(fence->fence_cookie, ctx->fence_retire_data); + free_fence_locked(fence); + return; + } + if (write_eventfd(vrend_state.eventfd, 1)) { perror("failed to write to eventfd\n"); } @@ -6079,11 +6091,13 @@ static void vrend_renderer_use_threaded_sync(void) return; } - vrend_state.eventfd = create_eventfd(0); - if (vrend_state.eventfd == -1) { - vrend_printf( "Failed to create eventfd\n"); - vrend_clicbs->destroy_gl_context(vrend_state.sync_context); - return; + if (!vrend_state.use_async_fence_cb) { + vrend_state.eventfd = create_eventfd(0); + if (vrend_state.eventfd == -1) { + vrend_printf( "Failed to create eventfd\n"); + vrend_clicbs->destroy_gl_context(vrend_state.sync_context); + return; + } } pipe_condvar_init(vrend_state.fence_cond); @@ -6091,8 +6105,10 @@ static void vrend_renderer_use_threaded_sync(void) vrend_state.sync_thread = pipe_thread_create(thread_sync, NULL); if (!vrend_state.sync_thread) { - close(vrend_state.eventfd); - vrend_state.eventfd = -1; + if (vrend_state.eventfd != -1) { + close(vrend_state.eventfd); + vrend_state.eventfd = -1; + } vrend_clicbs->destroy_gl_context(vrend_state.sync_context); pipe_condvar_destroy(vrend_state.fence_cond); pipe_mutex_destroy(vrend_state.fence_mutex); @@ -6308,6 +6324,8 @@ int vrend_renderer_init(const struct vrend_if_cbs *cbs, uint32_t flags) vrend_state.eventfd = -1; if (flags & VREND_USE_THREAD_SYNC) { + if (flags & VREND_USE_ASYNC_FENCE_CB) + vrend_state.use_async_fence_cb = true; vrend_renderer_use_threaded_sync(); } if (flags & VREND_USE_EXTERNAL_BLOB) @@ -9402,6 +9420,12 @@ void vrend_renderer_check_fences(void) struct list_head retired_fences; struct vrend_fence *fence, *stor; + /* No need to check the fence list, fences are retired directly in + * the polling thread in that case. + */ + if (vrend_state.use_async_fence_cb) + return; + list_inithead(&retired_fences); if (vrend_state.sync_thread) { diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index b1ef8a40b..ac4031bc5 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -122,8 +122,9 @@ struct vrend_if_cbs { int (*make_current)(virgl_gl_context ctx); }; -#define VREND_USE_THREAD_SYNC 1 -#define VREND_USE_EXTERNAL_BLOB 2 +#define VREND_USE_THREAD_SYNC (1 << 0) +#define VREND_USE_EXTERNAL_BLOB (1 << 1) +#define VREND_USE_ASYNC_FENCE_CB (1 << 2) const struct virgl_resource_pipe_callbacks * vrend_renderer_get_pipe_callbacks(void); -- GitLab From 0ee70e92a51c910cd90be3db36c4858b5c7deaed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis-Francis=20Ratt=C3=A9-Boulianne?= Date: Fri, 9 Jul 2021 01:17:22 -0400 Subject: [PATCH 3/3] virgl: Add VIRGL_RENDERER_ASYNC_FENCE_CB flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flag allows fence callback to be executed directly from the fence polling thread. It requires the `write_fence` callback provided by the user to be thread-safe. The `virgl_renderer_poll()` method no longer needs to be called by the user if that flag is used. v2: set VKR_RENDERER_ASYNC_FENCE_CB as well (by olv) Signed-off-by: Louis-Francis Ratté-Boulianne Reviewed-by: Chia-I Wu Reviewed-by: Ryan Neph (v1) --- src/virglrenderer.c | 4 ++++ src/virglrenderer.h | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/virglrenderer.c b/src/virglrenderer.c index f05eb3002..7250c1d57 100644 --- a/src/virglrenderer.c +++ b/src/virglrenderer.c @@ -667,6 +667,8 @@ int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks if (flags & VIRGL_RENDERER_THREAD_SYNC) renderer_flags |= VREND_USE_THREAD_SYNC; + if (flags & VIRGL_RENDERER_ASYNC_FENCE_CB) + renderer_flags |= VREND_USE_ASYNC_FENCE_CB; if (flags & VIRGL_RENDERER_USE_EXTERNAL_BLOB) renderer_flags |= VREND_USE_EXTERNAL_BLOB; @@ -680,6 +682,8 @@ int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks uint32_t vkr_flags = 0; if (flags & VIRGL_RENDERER_THREAD_SYNC) vkr_flags |= VKR_RENDERER_THREAD_SYNC; + if (flags & VIRGL_RENDERER_ASYNC_FENCE_CB) + vkr_flags |= VKR_RENDERER_ASYNC_FENCE_CB; ret = vkr_renderer_init(vkr_flags); if (ret) diff --git a/src/virglrenderer.h b/src/virglrenderer.h index 2fe43aadf..a1c06ffd8 100644 --- a/src/virglrenderer.h +++ b/src/virglrenderer.h @@ -98,6 +98,13 @@ struct virgl_renderer_callbacks { */ #define VIRGL_RENDERER_NO_VIRGL (1 << 7) +/* + * Used in conjonction with VIRGL_RENDERER_THREAD_SYNC; + * write_fence callback is executed directly from the polling thread. When enabled, + * virgl_renderer_get_poll_fd should not be used to watch for retired fences. + */ +#define VIRGL_RENDERER_ASYNC_FENCE_CB (1 << 8) + #endif /* VIRGL_RENDERER_UNSTABLE_APIS */ VIRGL_EXPORT int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks *cb); -- GitLab