diff --git a/src/virglrenderer.c b/src/virglrenderer.c index 36efd59..80f7f5b 100644 --- a/src/virglrenderer.c +++ b/src/virglrenderer.c @@ -165,6 +165,12 @@ void virgl_renderer_fill_caps(uint32_t set, uint32_t version, } } +static void per_context_fence_retire(UNUSED struct virgl_context *ctx, + UNUSED uint64_t queue_id, + UNUSED void *fence_cookie) +{ +} + int virgl_renderer_context_create_with_flags(uint32_t ctx_id, uint32_t ctx_flags, uint32_t nlen, @@ -204,7 +210,7 @@ int virgl_renderer_context_create_with_flags(uint32_t ctx_id, ctx->ctx_id = ctx_id; ctx->capset_id = capset_id; - ctx->fence_retire = NULL; + ctx->fence_retire = per_context_fence_retire; ret = virgl_context_add(ctx); if (ret) { @@ -436,8 +442,10 @@ void virgl_renderer_get_rect(int resource_id, struct iovec *iov, unsigned int nu } -static void virgl_write_fence(uint32_t fence_id) +static void ctx0_fence_retire(void *fence_cookie, + UNUSED void *retire_data) { + const uint32_t fence_id = (uint32_t)(uintptr_t)fence_cookie; state.cbs->write_fence(state.cookie, fence_id); } @@ -474,7 +482,7 @@ static int make_current(virgl_renderer_gl_context ctx) } static const struct vrend_if_cbs vrend_cbs = { - virgl_write_fence, + ctx0_fence_retire, create_gl_context, destroy_gl_context, make_current, diff --git a/src/vrend_decode.c b/src/vrend_decode.c index 557ad02..bf162bd 100644 --- a/src/vrend_decode.c +++ b/src/vrend_decode.c @@ -1462,6 +1462,13 @@ static int vrend_decode_pipe_resource_set_type(struct vrend_context *ctx, const static void vrend_decode_ctx_init_base(struct vrend_decode_ctx *dctx, uint32_t ctx_id); +static void vrend_decode_ctx_fence_retire(void *fence_cookie, + void *retire_data) +{ + struct vrend_decode_ctx *dctx = retire_data; + dctx->base.fence_retire(&dctx->base, 0, fence_cookie); +} + struct virgl_context *vrend_renderer_context_create(uint32_t handle, uint32_t nlen, const char *debug_name) @@ -1480,6 +1487,10 @@ struct virgl_context *vrend_renderer_context_create(uint32_t handle, return NULL; } + vrend_renderer_set_fence_retire(dctx->grctx, + vrend_decode_ctx_fence_retire, + dctx); + return &dctx->base; } @@ -1667,6 +1678,29 @@ static int vrend_decode_ctx_submit_cmd(struct virgl_context *ctx, return 0; } +static int vrend_decode_ctx_get_fencing_fd(UNUSED struct virgl_context *ctx) +{ + return vrend_renderer_get_poll_fd(); +} + +static void vrend_decode_ctx_retire_fences(UNUSED struct virgl_context *ctx) +{ + vrend_renderer_check_fences(); +} + +static int vrend_decode_ctx_submit_fence(struct virgl_context *ctx, + uint32_t flags, + uint64_t queue_id, + void *fence_cookie) +{ + struct vrend_decode_ctx *dctx = (struct vrend_decode_ctx *)ctx; + + if (queue_id) + return -EINVAL; + + return vrend_renderer_create_fence(dctx->grctx, flags, fence_cookie); +} + static void vrend_decode_ctx_init_base(struct vrend_decode_ctx *dctx, uint32_t ctx_id) { @@ -1684,7 +1718,7 @@ static void vrend_decode_ctx_init_base(struct vrend_decode_ctx *dctx, ctx->get_blob_done = NULL; ctx->submit_cmd = vrend_decode_ctx_submit_cmd; - ctx->get_fencing_fd = NULL; - ctx->retire_fences = NULL; - ctx->submit_fence = NULL; + ctx->get_fencing_fd = vrend_decode_ctx_get_fencing_fd; + ctx->retire_fences = vrend_decode_ctx_retire_fences; + ctx->submit_fence = vrend_decode_ctx_submit_fence; } diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index 066324d..02bf3f6 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -86,6 +86,7 @@ struct vrend_fence { * valid. */ struct vrend_context *ctx; + uint32_t flags; void *fence_cookie; union { @@ -739,6 +740,9 @@ struct vrend_context { struct vrend_shader_cfg shader_cfg; unsigned debug_flags; + + vrend_context_fence_retire fence_retire; + void *fence_retire_data; }; static struct vrend_resource *vrend_renderer_ctx_res_lookup(struct vrend_context *ctx, int res_handle); @@ -6420,6 +6424,9 @@ struct vrend_context *vrend_create_context(int id, uint32_t nlen, const char *de vrender_get_glsl_version(&grctx->shader_cfg.glsl_version); + if (!grctx->ctx_id) + grctx->fence_retire = vrend_clicbs->ctx0_fence_retire; + return grctx; } @@ -9158,7 +9165,18 @@ void vrend_renderer_blit(struct vrend_context *ctx, vrend_pause_render_condition(ctx, false); } -int vrend_renderer_create_fence(struct vrend_context *ctx, void *fence_cookie) +void vrend_renderer_set_fence_retire(struct vrend_context *ctx, + vrend_context_fence_retire retire, + void *retire_data) +{ + assert(ctx->ctx_id); + ctx->fence_retire = retire; + ctx->fence_retire_data = retire_data; +} + +int vrend_renderer_create_fence(struct vrend_context *ctx, + uint32_t flags, + void *fence_cookie) { struct vrend_fence *fence; @@ -9170,6 +9188,7 @@ int vrend_renderer_create_fence(struct vrend_context *ctx, void *fence_cookie) return ENOMEM; fence->ctx = ctx; + fence->flags = flags; fence->fence_cookie = fence_cookie; #ifdef HAVE_EPOXY_EGL_H @@ -9202,19 +9221,47 @@ int vrend_renderer_create_fence(struct vrend_context *ctx, void *fence_cookie) static void vrend_renderer_check_queries(void); +static bool need_fence_retire_signal_locked(struct vrend_fence *fence) +{ + struct vrend_fence *next; + + /* last fence */ + if (fence->fences.next == &vrend_state.fence_list) + return true; + + /* next fence belongs to a different context */ + next = LIST_ENTRY(struct vrend_fence, fence->fences.next, fences); + if (next->ctx != fence->ctx) + return true; + + return false; +} + void vrend_renderer_check_fences(void) { + struct list_head retired_fences; struct vrend_fence *fence, *stor; - bool fence_cookie_valid = false; - void *fence_cookie; + + list_inithead(&retired_fences); if (vrend_state.sync_thread) { flush_eventfd(vrend_state.eventfd); pipe_mutex_lock(vrend_state.fence_mutex); LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_list, fences) { - fence_cookie_valid = true; - fence_cookie = fence->fence_cookie; - free_fence_locked(fence); + /* vrend_free_fences_for_context might have marked the fence invalid + * by setting fence->ctx to NULL + */ + if (!fence->ctx) { + free_fence_locked(fence); + continue; + } + + if (need_fence_retire_signal_locked(fence)) { + list_del(&fence->fences); + list_addtail(&fence->fences, &retired_fences); + } else { + free_fence_locked(fence); + } } pipe_mutex_unlock(vrend_state.fence_mutex); } else { @@ -9222,9 +9269,12 @@ void vrend_renderer_check_fences(void) LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_list, fences) { if (do_wait(fence, /* can_block */ false)) { - fence_cookie_valid = true; - fence_cookie = fence->fence_cookie; - free_fence_locked(fence); + if (need_fence_retire_signal_locked(fence)) { + list_del(&fence->fences); + list_addtail(&fence->fences, &retired_fences); + } else { + free_fence_locked(fence); + } } else { /* don't bother checking any subsequent ones */ break; @@ -9232,12 +9282,17 @@ void vrend_renderer_check_fences(void) } } - if (!fence_cookie_valid) + if (LIST_IS_EMPTY(&retired_fences)) return; vrend_renderer_check_queries(); - vrend_clicbs->write_fence((uint32_t)(uintptr_t)fence_cookie); + LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &retired_fences, fences) { + struct vrend_context *ctx = fence->ctx; + ctx->fence_retire(fence->fence_cookie, ctx->fence_retire_data); + + free_fence_locked(fence); + } } static bool vrend_get_one_query_result(GLuint query_id, bool use_64, uint64_t *result) @@ -10963,7 +11018,34 @@ int vrend_renderer_resource_unmap(struct pipe_resource *pres) int vrend_renderer_create_ctx0_fence(uint32_t fence_id) { void *fence_cookie = (void *)(uintptr_t)fence_id; - return vrend_renderer_create_fence(vrend_state.ctx0, fence_cookie); + return vrend_renderer_create_fence(vrend_state.ctx0, 0, fence_cookie); +} + +static bool find_ctx0_fence_locked(struct list_head *fence_list, + void *fence_cookie, + bool *seen_first, + struct vrend_fence **fence) +{ + struct vrend_fence *iter; + + LIST_FOR_EACH_ENTRY(iter, fence_list, fences) { + /* only consider ctx0 fences */ + if (iter->ctx != vrend_state.ctx0) + continue; + + if (iter->fence_cookie == fence_cookie) { + *fence = iter; + return true; + } + + if (!*seen_first) { + if (fence_cookie < iter->fence_cookie) + return true; + *seen_first = true; + } + } + + return false; } int vrend_renderer_export_ctx0_fence(uint32_t fence_id, int* out_fd) { @@ -10976,45 +11058,30 @@ int vrend_renderer_export_ctx0_fence(uint32_t fence_id, int* out_fd) { pipe_mutex_lock(vrend_state.fence_mutex); void *fence_cookie = (void *)(uintptr_t)fence_id; + bool seen_first = false; struct vrend_fence *fence = NULL; - struct vrend_fence *iter; - uint32_t min_fence_id = UINT_MAX; - - if (!LIST_IS_EMPTY(&vrend_state.fence_list)) { - iter = LIST_ENTRY(struct vrend_fence, vrend_state.fence_list.next, fences); - min_fence_id = (uint32_t)(uintptr_t)iter->fence_cookie; - } else if (!LIST_IS_EMPTY(&vrend_state.fence_wait_list)) { - iter = LIST_ENTRY(struct vrend_fence, vrend_state.fence_wait_list.next, fences); - min_fence_id = (uint32_t)(uintptr_t)iter->fence_cookie; - } - - if (fence_id < min_fence_id) { - if (vrend_state.sync_thread) - pipe_mutex_unlock(vrend_state.fence_mutex); - return virgl_egl_export_signaled_fence(egl, out_fd) ? 0 : -EINVAL; - } - - LIST_FOR_EACH_ENTRY(iter, &vrend_state.fence_list, fences) { - if (iter->fence_cookie == fence_cookie) { - fence = iter; - break; - } - } - - if (!fence) { - LIST_FOR_EACH_ENTRY(iter, &vrend_state.fence_wait_list, fences) { - if (iter->fence_cookie == fence_cookie) { - fence = iter; - break; - } - } + bool found = find_ctx0_fence_locked(&vrend_state.fence_list, + fence_cookie, + &seen_first, + &fence); + if (!found) { + found = find_ctx0_fence_locked(&vrend_state.fence_wait_list, + fence_cookie, + &seen_first, + &fence); + /* consider signaled when no active ctx0 fence at all */ + if (!found && !seen_first) + found = true; } if (vrend_state.sync_thread) pipe_mutex_unlock(vrend_state.fence_mutex); - if (fence && virgl_egl_export_fence(egl, fence->eglsyncobj, out_fd)) { - return 0; + if (found) { + if (fence) + return virgl_egl_export_fence(egl, fence->eglsyncobj, out_fd) ? 0 : -EINVAL; + else + return virgl_egl_export_signaled_fence(egl, out_fd) ? 0 : -EINVAL; } #endif return -EINVAL; diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index 79e1ed9..297fc5c 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -107,8 +107,11 @@ struct vrend_format_table { uint32_t flags; }; +typedef void (*vrend_context_fence_retire)(void *fence_cookie, + void *retire_data); + struct vrend_if_cbs { - void (*write_fence)(unsigned fence_id); + vrend_context_fence_retire ctx0_fence_retire; virgl_gl_context (*create_gl_context)(int scanout, struct virgl_gl_ctx_param *params); void (*destroy_gl_context)(virgl_gl_context ctx); @@ -352,7 +355,13 @@ void vrend_set_tess_state(struct vrend_context *ctx, const float tess_factors[6] void vrend_renderer_fini(void); -int vrend_renderer_create_fence(struct vrend_context *ctx, void *fence_cookie); +void vrend_renderer_set_fence_retire(struct vrend_context *ctx, + vrend_context_fence_retire retire, + void *retire_data); + +int vrend_renderer_create_fence(struct vrend_context *ctx, + uint32_t flags, + void *fence_cookie); void vrend_renderer_check_fences(void);