diff --git a/src/virglrenderer.c b/src/virglrenderer.c index f05eb3002366c66d3597d3af4f7c65f40198bf5f..7250c1d57e81eec3175022e94999d917c4dffb5e 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 2fe43aadf2d48c3c3a8053d86ccd386f6ac3b081..a1c06ffd8ac47f46cf8a9882eebbc76f00775c70 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); diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index 26a9f872e402cfd1dd0628d0e1f985f2df4ada30..f941b8f6ee69e2a33d7cfddd057cfe9d9cc5c3a5 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,15 +6011,31 @@ 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) { + struct vrend_context *ctx = fence->ctx; + do_wait(fence, /* can_block */ true); pipe_mutex_lock(vrend_state.fence_mutex); - list_addtail(&fence->fences, &vrend_state.fence_list); + if (vrend_state.use_async_fence_cb) { + vrend_renderer_check_queries_locked(); + /* 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"); } @@ -6057,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); @@ -6069,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); @@ -6286,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) @@ -6385,7 +6425,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 +9394,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) { @@ -9377,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) { @@ -9421,7 +9470,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 +9515,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 +9546,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 +9743,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 +9796,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) \ diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index b1ef8a40bcc536cc8b81b0265d7f3e5f0a61e6e3..ac4031bc53b5481e31dd246bef6e4de083862362 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);