From 4380b73ca661280966feb81289ff62207bfa20a0 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 5 Jan 2020 19:14:47 +0100 Subject: [PATCH] Add HAVE_DYNAMIC_EGL option --- Makefile.common | 10 +- gfx/common/angle_common.c | 6 +- gfx/common/egl_common.c | 192 ++++++++++++++++++++++++++++++++------ gfx/common/egl_common.h | 2 + qb/config.params.sh | 1 + 5 files changed, 181 insertions(+), 30 deletions(-) diff --git a/Makefile.common b/Makefile.common index dbeb65b5d7..b90b350cfa 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1284,8 +1284,14 @@ endif ifeq ($(HAVE_EGL), 1) DEFINES += -DHAVE_EGL DEF_FLAGS += $(EGL_CFLAGS) - LIBS += $(EGL_LIBS) OBJ += gfx/common/egl_common.o + +ifeq ($(HAVE_DYNAMIC_EGL), 1) + DEFINES += -DHAVE_DYNAMIC_EGL +else + LIBS += $(EGL_LIBS) +endif + endif ifeq ($(HAVE_SDL2), 1) @@ -1965,8 +1971,6 @@ endif ifeq ($(HAVE_ANGLE), 1) OBJ += gfx/common/angle_common.o DEFINES += -DHAVE_ANGLE - # TODO/FIXME - should perhaps set these libraries as separate CFLAG variables in qb system - LIBS += -lEGL endif # Record diff --git a/gfx/common/angle_common.c b/gfx/common/angle_common.c index 8dca63ebd5..1c78d94a97 100644 --- a/gfx/common/angle_common.c +++ b/gfx/common/angle_common.c @@ -88,7 +88,11 @@ static bool angle_try_initialize(egl_ctx_data_t* egl, void* display_data, const EGLint* display_attr, EGLint* major, EGLint* minor) { - EGLDisplay dpy = EGL_NO_DISPLAY; + EGLDisplay dpy = EGL_NO_DISPLAY; +#if defined(HAVE_DYNAMIC) && defined(HAVE_DYNAMIC_EGL) + if (!egl_init_dll()) + return false; +#endif PFNEGLGETPLATFORMDISPLAYEXTPROC ptr_eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)egl_get_proc_address("eglGetPlatformDisplayEXT"); diff --git a/gfx/common/egl_common.c b/gfx/common/egl_common.c index 4224d1e570..59a92e27dc 100644 --- a/gfx/common/egl_common.c +++ b/gfx/common/egl_common.c @@ -38,9 +38,149 @@ bool g_egl_inited = false; unsigned g_egl_major = 0; unsigned g_egl_minor = 0; +#if defined(HAVE_DYNAMIC) && defined(HAVE_DYNAMIC_EGL) +#include + +typedef EGLBoolean(* PFN_EGL_QUERY_SURFACE)( + EGLDisplay dpy, + EGLSurface surface, + EGLint attribute, + EGLint *value); +typedef void *(* PFN_EGL_GET_PROC_ADDRESS)(const char *procname); +typedef EGLSurface(*PFN_EGL_CREATE_WINDOW_SURFACE) (EGLDisplay dpy, + EGLConfig config, + EGLNativeWindowType win, + const EGLint * attrib_list); +typedef EGLContext(*PFN_EGL_CREATE_CONTEXT)(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint * attrib_list); +typedef EGLBoolean(*PFN_EGL_GET_CONFIGS) (EGLDisplay dpy, EGLConfig * configs, + EGLint config_size, EGLint * num_config); +typedef EGLint(*PFN_EGL_GET_ERROR) (void); +typedef EGLDisplay(*PFN_EGL_GET_DISPLAY) (EGLNativeDisplayType display_id); +typedef EGLBoolean(*PFN_EGL_CHOOSE_CONFIG) (EGLDisplay dpy, + const EGLint * attrib_list, + EGLConfig * configs, + EGLint config_size, EGLint * num_config); +typedef EGLBoolean(*PFN_EGL_TERMINATE)(EGLDisplay dpy); +typedef EGLBoolean(*PFN_EGL_INITIALIZE)(EGLDisplay dpy, EGLint * major, + EGLint * minor); +typedef EGLBoolean(*PFN_EGL_BIND_API) (EGLenum api); +typedef EGLBoolean(*PFN_EGL_MAKE_CURRENT) (EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx); +typedef EGLBoolean(*PFN_EGL_DESTROY_SURFACE) (EGLDisplay dpy, EGLSurface surface); +typedef EGLBoolean(*PFN_EGL_DESTROY_CONTEXT) (EGLDisplay dpy, EGLContext ctx); +typedef EGLContext(*PFN_EGL_GET_CURRENT_CONTEXT) (void); +typedef const char *(*PFN_EGL_QUERY_STRING) (EGLDisplay dpy, EGLint name); +typedef EGLBoolean(*PFN_EGL_GET_CONFIG_ATTRIB) (EGLDisplay dpy, + EGLConfig config, + EGLint attribute, EGLint * value); +typedef EGLBoolean(*PFN_EGL_SWAP_BUFFERS) (EGLDisplay dpy, EGLSurface surface); +typedef EGLBoolean(*PFN_EGL_SWAP_INTERVAL) (EGLDisplay dpy, EGLint interval); + +static PFN_EGL_QUERY_SURFACE _egl_query_surface; +static PFN_EGL_GET_PROC_ADDRESS _egl_get_proc_address; +static PFN_EGL_CREATE_WINDOW_SURFACE _egl_create_window_surface; +static PFN_EGL_CREATE_CONTEXT _egl_create_context; +static PFN_EGL_GET_CONFIGS _egl_get_configs; +static PFN_EGL_GET_ERROR _egl_get_error; +static PFN_EGL_GET_DISPLAY _egl_get_display; +static PFN_EGL_CHOOSE_CONFIG _egl_choose_config; +static PFN_EGL_TERMINATE _egl_terminate; +static PFN_EGL_INITIALIZE _egl_initialize; +static PFN_EGL_BIND_API _egl_bind_api; +static PFN_EGL_MAKE_CURRENT _egl_make_current; +static PFN_EGL_DESTROY_SURFACE _egl_destroy_surface; +static PFN_EGL_DESTROY_CONTEXT _egl_destroy_context; +static PFN_EGL_GET_CURRENT_CONTEXT _egl_get_current_context; +static PFN_EGL_QUERY_STRING _egl_query_string; +static PFN_EGL_GET_CONFIG_ATTRIB _egl_get_config_attrib; +static PFN_EGL_SWAP_BUFFERS _egl_swap_buffers; +static PFN_EGL_SWAP_INTERVAL _egl_swap_interval; + +#else +#define _egl_query_surface(a, b, c, d) eglQuerySurface(a, b, c, d) +#define _egl_get_proc_address(a) eglGetProcAddress(a) +#define _egl_create_window_surface(a, b, c, d) eglCreateWindowSurface(a, b, c, d) +#define _egl_create_context(a, b, c, d) eglCreateContext(a, b, c, d) +#define _egl_get_configs(a, b, c, d) eglGetConfigs(a, b, c, d) +#define _egl_get_display(a) eglGetDisplay(a) +#define _egl_choose_config(a, b, c, d, e) eglChooseConfig(a, b, c, d, e) +#define _egl_make_current(a, b, c, d) eglMakeCurrent(a, b, c, d) +#define _egl_initialize(a, b, c) eglInitialize(a, b, c) +#define _egl_destroy_surface(a, b) eglDestroySurface(a, b) +#define _egl_destroy_context(a, b) eglDestroyContext(a, b) +#define _egl_get_current_context() eglGetCurrentContext() +#define _egl_get_error() eglGetError() +#define _egl_terminate(dpy) eglTerminate(dpy) +#define _egl_bind_api(a) eglBindAPI(a) +#define _egl_query_string(a, b) eglQueryString(a, b) +#define _egl_get_config_attrib(a, b, c, d) eglGetConfigAttrib(a, b, c, d) +#define _egl_swap_buffers(a, b) eglSwapBuffers(a, b) +#define _egl_swap_interval(a, b) eglSwapInterval(a, b) +#endif + +bool egl_init_dll(void) +{ +#if defined(HAVE_DYNAMIC) && defined(HAVE_DYNAMIC_EGL) + static dylib_t egl_dll; + + if (!egl_dll) + { + egl_dll = dylib_load("libEGL.dll"); + if (egl_dll) + { + /* Setup function callbacks once */ + _egl_query_surface = (PFN_EGL_QUERY_SURFACE)dylib_proc( + egl_dll, "eglQuerySurface"); + _egl_get_proc_address = (PFN_EGL_GET_PROC_ADDRESS)dylib_proc( + egl_dll, "eglGetProcAddress"); + _egl_create_window_surface = (PFN_EGL_CREATE_WINDOW_SURFACE)dylib_proc( + egl_dll, "eglCreateWindowSurface"); + _egl_create_context = (PFN_EGL_CREATE_CONTEXT)dylib_proc( + egl_dll, "eglCreateContext"); + _egl_get_configs = (PFN_EGL_GET_CONFIGS)dylib_proc( + egl_dll, "eglGetConfigs"); + _egl_get_error = (PFN_EGL_GET_ERROR)dylib_proc( + egl_dll, "eglGetError"); + _egl_get_display = (PFN_EGL_GET_DISPLAY)dylib_proc( + egl_dll, "eglGetDisplay"); + _egl_choose_config = (PFN_EGL_CHOOSE_CONFIG)dylib_proc( + egl_dll, "eglChooseConfig"); + _egl_terminate = (PFN_EGL_TERMINATE)dylib_proc( + egl_dll, "eglTerminate"); + _egl_initialize = (PFN_EGL_INITIALIZE)dylib_proc( + egl_dll, "eglInitialize"); + _egl_bind_api = (PFN_EGL_BIND_API)dylib_proc( + egl_dll, "eglBindAPI"); + _egl_make_current = (PFN_EGL_MAKE_CURRENT)dylib_proc( + egl_dll, "eglMakeCurrent"); + _egl_destroy_surface = (PFN_EGL_DESTROY_SURFACE)dylib_proc( + egl_dll, "eglDestroySurface"); + _egl_destroy_context = (PFN_EGL_DESTROY_CONTEXT)dylib_proc( + egl_dll, "eglDestroyContext"); + _egl_get_current_context = (PFN_EGL_GET_CURRENT_CONTEXT)dylib_proc( + egl_dll, "eglGetCurrentContext"); + _egl_query_string = (PFN_EGL_QUERY_STRING)dylib_proc( + egl_dll, "eglQueryString"); + _egl_get_config_attrib = (PFN_EGL_GET_CONFIG_ATTRIB)dylib_proc( + egl_dll, "eglGetConfigAttrib"); + _egl_swap_buffers = (PFN_EGL_SWAP_BUFFERS)dylib_proc( + egl_dll, "eglSwapBuffers"); + _egl_swap_interval = (PFN_EGL_SWAP_INTERVAL)dylib_proc( + egl_dll, "eglSwapInterval"); + } + } + + if (egl_dll) + return true; +#endif + return false; +} + void egl_report_error(void) { - EGLint error = eglGetError(); + EGLint error = _egl_get_error(); const char *str = NULL; switch (error) { @@ -106,28 +246,28 @@ void egl_report_error(void) gfx_ctx_proc_t egl_get_proc_address(const char *symbol) { - return eglGetProcAddress(symbol); + return _egl_get_proc_address(symbol); } void egl_terminate(EGLDisplay dpy) { - eglTerminate(dpy); + _egl_terminate(dpy); } static bool egl_get_config_attrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { - return eglGetConfigAttrib(dpy, config, attribute, value); + return _egl_get_config_attrib(dpy, config, attribute, value); } bool egl_initialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { - return eglInitialize(dpy, major, minor); + return _egl_initialize(dpy, major, minor); } bool egl_bind_api(EGLenum egl_api) { - return eglBindAPI(egl_api); + return _egl_bind_api(egl_api); } void egl_destroy(egl_ctx_data_t *egl) @@ -144,16 +284,16 @@ void egl_destroy(egl_ctx_data_t *egl) #endif #endif - eglMakeCurrent(egl->dpy, + _egl_make_current(egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (egl->ctx != EGL_NO_CONTEXT) - eglDestroyContext(egl->dpy, egl->ctx); + _egl_destroy_context(egl->dpy, egl->ctx); if (egl->hw_ctx != EGL_NO_CONTEXT) - eglDestroyContext(egl->dpy, egl->hw_ctx); + _egl_destroy_context(egl->dpy, egl->hw_ctx); if (egl->surf != EGL_NO_SURFACE) - eglDestroySurface(egl->dpy, egl->surf); + _egl_destroy_surface(egl->dpy, egl->surf); egl_terminate(egl->dpy); } @@ -180,7 +320,7 @@ void egl_bind_hw_render(egl_ctx_data_t *egl, bool enable) if (egl->surf == EGL_NO_SURFACE) return; - eglMakeCurrent(egl->dpy, egl->surf, + _egl_make_current(egl->dpy, egl->surf, egl->surf, enable ? egl->hw_ctx : egl->ctx); } @@ -192,7 +332,7 @@ void egl_swap_buffers(void *data) egl->dpy != EGL_NO_DISPLAY && egl->surf != EGL_NO_SURFACE ) - eglSwapBuffers(egl->dpy, egl->surf); + _egl_swap_buffers(egl->dpy, egl->surf); } void egl_set_swap_interval(egl_ctx_data_t *egl, int interval) @@ -205,11 +345,11 @@ void egl_set_swap_interval(egl_ctx_data_t *egl, int interval) if (egl->dpy == EGL_NO_DISPLAY) return; - if (!(eglGetCurrentContext())) + if (!_egl_get_current_context()) return; RARCH_LOG("[EGL]: eglSwapInterval(%u)\n", interval); - if (!eglSwapInterval(egl->dpy, interval)) + if (!_egl_swap_interval(egl->dpy, interval)) { RARCH_ERR("[EGL]: eglSwapInterval() failed.\n"); egl_report_error(); @@ -225,8 +365,8 @@ void egl_get_video_size(egl_ctx_data_t *egl, unsigned *width, unsigned *height) { EGLint gl_width, gl_height; - eglQuerySurface(egl->dpy, egl->surf, EGL_WIDTH, &gl_width); - eglQuerySurface(egl->dpy, egl->surf, EGL_HEIGHT, &gl_height); + _egl_query_surface(egl->dpy, egl->surf, EGL_WIDTH, &gl_width); + _egl_query_surface(egl->dpy, egl->surf, EGL_HEIGHT, &gl_height); *width = gl_width; *height = gl_height; } @@ -236,7 +376,7 @@ bool check_egl_version(int minMajorVersion, int minMinorVersion) { int count; int major, minor; - const char *str = eglQueryString(EGL_NO_DISPLAY, EGL_VERSION); + const char *str = _egl_query_string(EGL_NO_DISPLAY, EGL_VERSION); if (!str) return false; @@ -260,7 +400,7 @@ bool check_egl_version(int minMajorVersion, int minMinorVersion) bool check_egl_client_extension(const char *name) { size_t nameLen; - const char *str = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + const char *str = _egl_query_string(EGL_NO_DISPLAY, EGL_EXTENSIONS); /* The EGL implementation doesn't support client extensions at all. */ if (!str) @@ -332,7 +472,7 @@ static EGLDisplay get_egl_display(EGLenum platform, void *native) * implementation doesn't support eglGetPlatformDisplay. In this case, try * eglGetDisplay and hope for the best. */ RARCH_LOG("[EGL] Falling back to eglGetDisplay\n"); - return eglGetDisplay((EGLNativeDisplayType) native); + return _egl_get_display((EGLNativeDisplayType) native); } bool egl_get_native_visual_id(egl_ctx_data_t *egl, EGLint *value) @@ -376,7 +516,7 @@ bool egl_init_context_common( if (!egl) return false; - if (!eglGetConfigs(egl->dpy, NULL, 0, count) || *count < 1) + if (!_egl_get_configs(egl->dpy, NULL, 0, count) || *count < 1) { RARCH_ERR("[EGL]: No configs to choose from.\n"); return false; @@ -386,7 +526,7 @@ bool egl_init_context_common( if (!configs) return false; - if (!eglChooseConfig(egl->dpy, attrib_ptr, + if (!_egl_choose_config(egl->dpy, attrib_ptr, configs, *count, &matched) || !matched) { RARCH_ERR("[EGL]: No EGL configs with appropriate attributes.\n"); @@ -446,7 +586,7 @@ bool egl_init_context(egl_ctx_data_t *egl, bool egl_create_context(egl_ctx_data_t *egl, const EGLint *egl_attribs) { - EGLContext ctx = eglCreateContext(egl->dpy, egl->config, EGL_NO_CONTEXT, + EGLContext ctx = _egl_create_context(egl->dpy, egl->config, EGL_NO_CONTEXT, egl_attribs); if (ctx == EGL_NO_CONTEXT) @@ -457,7 +597,7 @@ bool egl_create_context(egl_ctx_data_t *egl, const EGLint *egl_attribs) if (egl->use_hw_ctx) { - egl->hw_ctx = eglCreateContext(egl->dpy, egl->config, egl->ctx, + egl->hw_ctx = _egl_create_context(egl->dpy, egl->config, egl->ctx, egl_attribs); RARCH_LOG("[EGL]: Created shared context: %p.\n", (void*)egl->hw_ctx); @@ -475,16 +615,16 @@ bool egl_create_surface(egl_ctx_data_t *egl, void *native_window) EGL_NONE, }; - egl->surf = eglCreateWindowSurface(egl->dpy, egl->config, (NativeWindowType)native_window, window_attribs); + egl->surf = _egl_create_window_surface(egl->dpy, egl->config, (NativeWindowType)native_window, window_attribs); if (egl->surf == EGL_NO_SURFACE) return false; /* Connect the context to the surface. */ - if (!eglMakeCurrent(egl->dpy, egl->surf, egl->surf, egl->ctx)) + if (!_egl_make_current(egl->dpy, egl->surf, egl->surf, egl->ctx)) return false; - RARCH_LOG("[EGL]: Current context: %p.\n", (void*)eglGetCurrentContext()); + RARCH_LOG("[EGL]: Current context: %p.\n", (void*)_egl_get_current_context()); return true; } diff --git a/gfx/common/egl_common.h b/gfx/common/egl_common.h index 20fcccac9f..478db7325d 100644 --- a/gfx/common/egl_common.h +++ b/gfx/common/egl_common.h @@ -95,6 +95,8 @@ bool egl_default_accept_config_cb(void *display_data, EGLDisplay dpy, EGLConfig bool egl_initialize(EGLDisplay dpy, EGLint *major, EGLint *minor); +bool egl_init_dll(void); + bool egl_init_context_common( egl_ctx_data_t *egl, EGLint *count, const EGLint *attrib_ptr, diff --git a/qb/config.params.sh b/qb/config.params.sh index 4a9894cbc0..9adbce566d 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -84,6 +84,7 @@ HAVE_SUNXI=no # Sunxi video support HAVE_WAYLAND=auto # Wayland support C89_WAYLAND=no CXX_WAYLAND=no +HAVE_DYNAMIC_EGL=no # Dynamic library EGL support HAVE_EGL=auto # EGL context support HAVE_VG=auto # OpenVG support HAVE_CG=auto # Cg shader support