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);