diff --git a/src/virglrenderer.c b/src/virglrenderer.c index bbf6416..29d6d34 100644 --- a/src/virglrenderer.c +++ b/src/virglrenderer.c @@ -763,3 +763,9 @@ virgl_renderer_resource_export_blob(uint32_t res_id, uint32_t *fd_type, int *fd) return 0; } + +int +virgl_renderer_export_fence(uint32_t client_fence_id, uint32_t *fd) +{ + return vrend_renderer_export_fence(client_fence_id, fd); +} diff --git a/src/virglrenderer.h b/src/virglrenderer.h index db4bb5c..b06eea1 100644 --- a/src/virglrenderer.h +++ b/src/virglrenderer.h @@ -297,6 +297,9 @@ VIRGL_EXPORT int virgl_renderer_resource_get_map_info(uint32_t res_handle, uint3 VIRGL_EXPORT int virgl_renderer_resource_export_blob(uint32_t res_id, uint32_t *fd_type, int *fd); +VIRGL_EXPORT int +virgl_renderer_export_fence(uint32_t client_fence_id, uint32_t *fd); + #endif /* VIRGL_RENDERER_UNSTABLE_APIS */ #endif diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index e9c3c77..49333f0 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -10645,3 +10645,55 @@ int vrend_renderer_resource_unmap(struct pipe_resource *pres) glBindBufferARB(res->target, 0); return 0; } + +int vrend_renderer_export_fence(uint32_t fence_id, int* out_fd) { +#ifdef HAVE_EPOXY_EGL_H + if (!vrend_state.use_egl_fence) { + return -EINVAL; + } + + if (vrend_state.sync_thread) + pipe_mutex_lock(vrend_state.fence_mutex); + + struct vrend_fence *fence = NULL; + struct vrend_fence *iter; + uint32_t min_fence_id = UINT_MAX; + + if (!LIST_IS_EMPTY(&vrend_state.fence_list)) { + min_fence_id = LIST_ENTRY(struct vrend_fence, vrend_state.fence_list.next, fences)->fence_id; + } else if (!LIST_IS_EMPTY(&vrend_state.fence_wait_list)) { + min_fence_id = + LIST_ENTRY(struct vrend_fence, vrend_state.fence_wait_list.next, fences)->fence_id; + } + + 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_id == fence_id) { + fence = iter; + break; + } + } + + if (!fence) { + LIST_FOR_EACH_ENTRY(iter, &vrend_state.fence_wait_list, fences) { + if (iter->fence_id == fence_id) { + fence = iter; + break; + } + } + } + + 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; + } +#endif + return -EINVAL; +} diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index cf2e593..afb900b 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -347,6 +347,8 @@ int vrend_renderer_create_fence(int client_fence_id, uint32_t ctx_id); void vrend_renderer_check_fences(void); +int vrend_renderer_export_fence(uint32_t fence_id, int* out_fd); + bool vrend_hw_switch_context(struct vrend_context *ctx, bool now); uint32_t vrend_renderer_object_insert(struct vrend_context *ctx, void *data, uint32_t handle, enum virgl_object_type type); diff --git a/src/vrend_winsys_egl.c b/src/vrend_winsys_egl.c index 4994a34..0fc41ed 100644 --- a/src/vrend_winsys_egl.c +++ b/src/vrend_winsys_egl.c @@ -74,6 +74,7 @@ struct virgl_egl { EGLConfig egl_conf; EGLContext egl_ctx; uint32_t extension_bits; + EGLSyncKHR signaled_fence; }; static bool virgl_egl_has_extension_in_string(const char *haystack, const char *needle) @@ -236,6 +237,16 @@ struct virgl_egl *virgl_egl_init(struct virgl_gbm *gbm, bool surfaceless, bool g eglMakeCurrent(egl->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl->egl_ctx); + + if (virgl_egl_supports_fences(egl)) { + egl->signaled_fence = eglCreateSyncKHR(egl->egl_display, + EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); + if (!egl->signaled_fence) { + vrend_printf("Failed to create signaled fence"); + goto fail; + } + } + return egl; fail: @@ -245,6 +256,9 @@ struct virgl_egl *virgl_egl_init(struct virgl_gbm *gbm, bool surfaceless, bool g void virgl_egl_destroy(struct virgl_egl *egl) { + if (egl->signaled_fence) { + eglDestroySyncKHR(egl->egl_display, egl->signaled_fence); + } eglMakeCurrent(egl->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(egl->egl_display, egl->egl_ctx); @@ -533,3 +547,12 @@ bool virgl_egl_client_wait_fence(struct virgl_egl *egl, EGLSyncKHR fence, uint64 } return ret != EGL_TIMEOUT_EXPIRED_KHR; } + +bool virgl_egl_export_signaled_fence(struct virgl_egl *egl, int *out_fd) { + return virgl_egl_export_fence(egl, egl->signaled_fence, out_fd); +} + +bool virgl_egl_export_fence(struct virgl_egl *egl, EGLSyncKHR fence, int *out_fd) { + *out_fd = eglDupNativeFenceFDANDROID(egl->egl_display, fence); + return *out_fd != EGL_NO_NATIVE_FENCE_FD_ANDROID; +} diff --git a/src/vrend_winsys_egl.h b/src/vrend_winsys_egl.h index 7f0a2eb..1fb0ccb 100644 --- a/src/vrend_winsys_egl.h +++ b/src/vrend_winsys_egl.h @@ -64,4 +64,6 @@ bool virgl_egl_supports_fences(struct virgl_egl *egl); EGLSyncKHR virgl_egl_fence_create(struct virgl_egl *egl); void virgl_egl_fence_destroy(struct virgl_egl *egl, EGLSyncKHR fence); bool virgl_egl_client_wait_fence(struct virgl_egl *egl, EGLSyncKHR fence, uint64_t timeout); +bool virgl_egl_export_signaled_fence(struct virgl_egl *egl, int *out_fd); +bool virgl_egl_export_fence(struct virgl_egl *egl, EGLSyncKHR fence, int *out_fd); #endif