From 06240496bf281caac21baefadd05075238535d97 Mon Sep 17 00:00:00 2001 From: Andrii Pauk Date: Thu, 13 Jan 2022 09:53:53 +0200 Subject: [PATCH] vrend: Add get_egl_display callback This is required for support of untyped resources on virtio devices which create their own egl context. Currently untyped resources support is reported to mesa only in case virglrenderer creates it's own egl context from scratch. The problem that this context is not "sharable" with device context and if it's created vrend uses it instead of context callbacks implemented by device. Thus such approach is not suitable for devices with it's own egl context. The only thing that is required for untyped resources support is initialized eglDisplay handle that is requried for eglCreateImageKHR, thus add callback for device to share it. Untyped resources feature support is required for sharing vkr resources with vrend. Signed-off-by: Oleksandr.Gabrylchuk Signed-off-by: Andrii Pauk Reviewed-by: Chia-I Wu --- src/virglrenderer.c | 24 +++++++++++++++++++++++- src/virglrenderer.h | 25 ++++++++++++++++++++++--- src/vrend_winsys.c | 24 +++++++++++++++++++++++- src/vrend_winsys.h | 2 ++ src/vrend_winsys_egl.c | 28 ++++++++++++++++++++++++++++ src/vrend_winsys_egl.h | 2 ++ 6 files changed, 100 insertions(+), 5 deletions(-) diff --git a/src/virglrenderer.c b/src/virglrenderer.c index 959e5a8..29674b3 100644 --- a/src/virglrenderer.c +++ b/src/virglrenderer.c @@ -60,6 +60,7 @@ struct global_state { bool vrend_initialized; bool vkr_initialized; bool proxy_initialized; + bool external_winsys_initialized; }; static struct global_state state; @@ -610,7 +611,7 @@ void virgl_renderer_cleanup(UNUSED void *cookie) if (state.vrend_initialized) vrend_renderer_fini(); - if (state.winsys_initialized) + if (state.winsys_initialized || state.external_winsys_initialized) vrend_winsys_cleanup(); memset(&state, 0, sizeof(state)); @@ -679,6 +680,27 @@ int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks state.winsys_initialized = true; } + if (!state.winsys_initialized && !state.external_winsys_initialized && + state.cbs && state.cbs->version >= 4 && state.cbs->get_egl_display) { + void *egl_display = NULL; + + if (!cbs->create_gl_context || !cbs->destroy_gl_context || + !cbs->make_current) + goto fail; + + egl_display = state.cbs->get_egl_display(cookie); + + if (!egl_display) + goto fail; + + ret = vrend_winsys_init_external(egl_display); + + if (ret) + goto fail; + + state.external_winsys_initialized = true; + } + if (!state.vrend_initialized && !(flags & VIRGL_RENDERER_NO_VIRGL)) { uint32_t renderer_flags = 0; diff --git a/src/virglrenderer.h b/src/virglrenderer.h index c6988af..cd3523a 100644 --- a/src/virglrenderer.h +++ b/src/virglrenderer.h @@ -46,7 +46,7 @@ struct virgl_renderer_gl_ctx_param { }; #ifdef VIRGL_RENDERER_UNSTABLE_APIS -#define VIRGL_RENDERER_CALLBACKS_VERSION 3 +#define VIRGL_RENDERER_CALLBACKS_VERSION 4 #else #define VIRGL_RENDERER_CALLBACKS_VERSION 2 #endif @@ -55,18 +55,37 @@ struct virgl_renderer_callbacks { int version; void (*write_fence)(void *cookie, uint32_t fence); - /* interact with GL implementation */ + /* + * The following 3 callbacks allows virglrenderer to + * use winsys from caller, instead of initializing it's own + * winsys (flag VIRGL_RENDERER_USE_EGL or VIRGL_RENDERER_USE_GLX). + */ + + /* create a GL/GLES context */ virgl_renderer_gl_context (*create_gl_context)(void *cookie, int scanout_idx, struct virgl_renderer_gl_ctx_param *param); + /* destroy a GL/GLES context */ void (*destroy_gl_context)(void *cookie, virgl_renderer_gl_context ctx); + /* make a context current */ int (*make_current)(void *cookie, int scanout_idx, virgl_renderer_gl_context ctx); - int (*get_drm_fd)(void *cookie); /* v2, used with flags & VIRGL_RENDERER_USE_EGL */ + /* + * v2, used with flags & VIRGL_RENDERER_USE_EGL + * Chose the drm fd, that will be used by virglrenderer + * for winsys initialization. + */ + int (*get_drm_fd)(void *cookie); #ifdef VIRGL_RENDERER_UNSTABLE_APIS void (*write_context_fence)(void *cookie, uint32_t ctx_id, uint64_t queue_id, void *fence_cookie); /* version 0: a connected socket of type SOCK_SEQPACKET */ int (*get_server_fd)(void *cookie, uint32_t version); + + /* + * Get the EGLDisplay from caller. It requires create_gl_context, + * destroy_gl_context, make_current to be implemented by caller. + */ + void *(*get_egl_display)(void *cookie); #endif }; diff --git a/src/vrend_winsys.c b/src/vrend_winsys.c index 669af81..9371e81 100644 --- a/src/vrend_winsys.c +++ b/src/vrend_winsys.c @@ -33,7 +33,8 @@ enum { CONTEXT_NONE, CONTEXT_EGL, - CONTEXT_GLX + CONTEXT_GLX, + CONTEXT_EGL_EXTERNAL }; static int use_context = CONTEXT_NONE; @@ -102,6 +103,10 @@ void vrend_winsys_cleanup(void) virgl_gbm_fini(gbm); gbm = NULL; } + } else if (use_context == CONTEXT_EGL_EXTERNAL) { + free(egl); + egl = NULL; + use_context = CONTEXT_NONE; } #endif #ifdef HAVE_EPOXY_GLX_H @@ -113,6 +118,23 @@ void vrend_winsys_cleanup(void) #endif } +int vrend_winsys_init_external(void *egl_display) +{ +#ifdef HAVE_EPOXY_EGL_H + egl = virgl_egl_init_external(egl_display); + if (!egl) + return -1; + + use_context = CONTEXT_EGL_EXTERNAL; +#else + (void)egl_display; + vrend_printf( "EGL is not supported on this platform\n"); + return -1; +#endif + + return 0; +} + virgl_renderer_gl_context vrend_winsys_create_context(struct virgl_gl_ctx_param *param) { #ifdef HAVE_EPOXY_EGL_H diff --git a/src/vrend_winsys.h b/src/vrend_winsys.h index 17507ff..5e60540 100644 --- a/src/vrend_winsys.h +++ b/src/vrend_winsys.h @@ -48,6 +48,8 @@ extern struct virgl_gbm *gbm; int vrend_winsys_init(uint32_t flags, int preferred_fd); void vrend_winsys_cleanup(void); +int vrend_winsys_init_external(void *egl_display); + virgl_renderer_gl_context vrend_winsys_create_context(struct virgl_gl_ctx_param *param); void vrend_winsys_destroy_context(virgl_renderer_gl_context ctx); int vrend_winsys_make_context_current(virgl_renderer_gl_context ctx); diff --git a/src/vrend_winsys_egl.c b/src/vrend_winsys_egl.c index 4dcc668..cda67e9 100644 --- a/src/vrend_winsys_egl.c +++ b/src/vrend_winsys_egl.c @@ -419,6 +419,34 @@ void virgl_egl_destroy(struct virgl_egl *egl) free(egl); } +struct virgl_egl *virgl_egl_init_external(EGLDisplay egl_display) +{ + const char *extensions; + struct virgl_egl *egl; + + egl = calloc(1, sizeof(struct virgl_egl)); + if (!egl) + return NULL; + + egl->egl_display = egl_display; + + extensions = eglQueryString(egl->egl_display, EGL_EXTENSIONS); +#ifdef VIRGL_EGL_DEBUG + vrend_printf( "EGL version: %s\n", + eglQueryString(egl->egl_display, EGL_VERSION)); + vrend_printf( "EGL vendor: %s\n", + eglQueryString(egl->egl_display, EGL_VENDOR)); + vrend_printf( "EGL extensions: %s\n", extensions); +#endif + + if (virgl_egl_init_extensions(egl, extensions)) { + free(egl); + return NULL; + } + + return egl; +} + virgl_renderer_gl_context virgl_egl_create_context(struct virgl_egl *egl, struct virgl_gl_ctx_param *vparams) { EGLContext egl_ctx; diff --git a/src/vrend_winsys_egl.h b/src/vrend_winsys_egl.h index e8dcf85..0ef3e4e 100644 --- a/src/vrend_winsys_egl.h +++ b/src/vrend_winsys_egl.h @@ -37,6 +37,8 @@ struct virgl_egl *virgl_egl_init(struct virgl_gbm *gbm, bool surfaceless, bool g void virgl_egl_destroy(struct virgl_egl *egl); +struct virgl_egl *virgl_egl_init_external(EGLDisplay egl_display); + virgl_renderer_gl_context virgl_egl_create_context(struct virgl_egl *egl, struct virgl_gl_ctx_param *vparams);