diff --git a/CMakeLists.txt b/CMakeLists.txt index e990b85b..8f0d6650 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,6 +402,11 @@ if (_GLFW_EGL) list(APPEND glfw_PKG_DEPS "glesv2") endif() + if (CMAKE_DL_LIBS) + list(APPEND glfw_LIBRARIES "${CMAKE_DL_LIBS}") + list(APPEND glfw_PKG_LIBS "-l${CMAKE_DL_LIBS}") + endif() + endif() #-------------------------------------------------------------------- diff --git a/README.md b/README.md index ef428147..19764a9c 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,7 @@ GLFW bundles a number of dependencies in the `deps/` directory. - [GLX] Made all GLX functions dynamically loaded - [GLX] Removed `_GLFW_HAS_GLXGETPROCADDRESS*` and `_GLFW_HAS_DLOPEN` compile-time options + - [EGL] Made all EGL functions dynamically loaded ## Contact diff --git a/src/egl_context.c b/src/egl_context.c index c2c541f0..7a14d734 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -78,7 +78,7 @@ static const char* getErrorString(EGLint error) static int getConfigAttrib(EGLConfig config, int attrib) { int value; - eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value); + _glfw_eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value); return value; } @@ -93,7 +93,7 @@ static GLboolean chooseFBConfigs(const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* closest; int i, nativeCount, usableCount; - eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); + _glfw_eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); if (!nativeCount) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned"); @@ -101,7 +101,8 @@ static GLboolean chooseFBConfigs(const _GLFWctxconfig* ctxconfig, } nativeConfigs = calloc(nativeCount, sizeof(EGLConfig)); - eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount); + _glfw_eglGetConfigs(_glfw.egl.display, nativeConfigs, + nativeCount, &nativeCount); usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; @@ -178,23 +179,86 @@ static GLboolean chooseFBConfigs(const _GLFWctxconfig* ctxconfig, // int _glfwInitContextAPI(void) { + int i; + const char* sonames[] = + { +#if defined(_GLFW_WIN32) + "libEGL.dll", + "EGL.dll", +#elif defined(_GLFW_COCOA) + "libEGL.dylib", +#else + "libEGL.so.1", +#endif + NULL + }; + if (!_glfwCreateContextTLS()) return GL_FALSE; - _glfw.egl.display = eglGetDisplay((EGLNativeDisplayType)_GLFW_EGL_NATIVE_DISPLAY); + for (i = 0; sonames[i]; i++) + { + _glfw.egl.handle = _glfw_dlopen(sonames[i]); + if (_glfw.egl.handle) + break; + } + + if (!_glfw.egl.handle) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to load EGL"); + return GL_FALSE; + } + + _glfw.egl.GetConfigAttrib = + _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib"); + _glfw.egl.GetConfigs = + _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs"); + _glfw.egl.GetDisplay = + _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay"); + _glfw.egl.GetError = + _glfw_dlsym(_glfw.egl.handle, "eglGetError"); + _glfw.egl.Initialize = + _glfw_dlsym(_glfw.egl.handle, "eglInitialize"); + _glfw.egl.Terminate = + _glfw_dlsym(_glfw.egl.handle, "eglTerminate"); + _glfw.egl.BindAPI = + _glfw_dlsym(_glfw.egl.handle, "eglBindAPI"); + _glfw.egl.CreateContext = + _glfw_dlsym(_glfw.egl.handle, "eglCreateContext"); + _glfw.egl.DestroySurface = + _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface"); + _glfw.egl.DestroyContext = + _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext"); + _glfw.egl.CreateWindowSurface = + _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface"); + _glfw.egl.MakeCurrent = + _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent"); + _glfw.egl.SwapBuffers = + _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers"); + _glfw.egl.SwapInterval = + _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval"); + _glfw.egl.QueryString = + _glfw_dlsym(_glfw.egl.handle, "eglQueryString"); + _glfw.egl.GetProcAddress = + _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress"); + + _glfw.egl.display = + _glfw_eglGetDisplay((EGLNativeDisplayType)_GLFW_EGL_NATIVE_DISPLAY); if (_glfw.egl.display == EGL_NO_DISPLAY) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to get EGL display: %s", - getErrorString(eglGetError())); + getErrorString(_glfw_eglGetError())); return GL_FALSE; } - if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor)) + if (!_glfw_eglInitialize(_glfw.egl.display, + &_glfw.egl.major, + &_glfw.egl.minor)) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to initialize EGL: %s", - getErrorString(eglGetError())); + getErrorString(_glfw_eglGetError())); return GL_FALSE; } @@ -208,7 +272,14 @@ int _glfwInitContextAPI(void) // void _glfwTerminateContextAPI(void) { - eglTerminate(_glfw.egl.display); + if (_glfw_eglTerminate) + _glfw_eglTerminate(_glfw.egl.display); + + if (_glfw.egl.handle) + { + _glfw_dlclose(_glfw.egl.handle); + _glfw.egl.handle = NULL; + } _glfwDestroyContextTLS(); } @@ -248,8 +319,8 @@ int _glfwCreateContext(_GLFWwindow* window, EGLint redBits, greenBits, blueBits, alphaBits, visualID = 0; XVisualInfo info; - eglGetConfigAttrib(_glfw.egl.display, config, - EGL_NATIVE_VISUAL_ID, &visualID); + _glfw_eglGetConfigAttrib(_glfw.egl.display, config, + EGL_NATIVE_VISUAL_ID, &visualID); info.screen = _glfw.x11.screen; mask = VisualScreenMask; @@ -265,14 +336,14 @@ int _glfwCreateContext(_GLFWwindow* window, // Some EGL drivers do not implement the EGL_NATIVE_VISUAL_ID // attribute, so attempt to find the closest match - eglGetConfigAttrib(_glfw.egl.display, config, - EGL_RED_SIZE, &redBits); - eglGetConfigAttrib(_glfw.egl.display, config, - EGL_GREEN_SIZE, &greenBits); - eglGetConfigAttrib(_glfw.egl.display, config, - EGL_BLUE_SIZE, &blueBits); - eglGetConfigAttrib(_glfw.egl.display, config, - EGL_ALPHA_SIZE, &alphaBits); + _glfw_eglGetConfigAttrib(_glfw.egl.display, config, + EGL_RED_SIZE, &redBits); + _glfw_eglGetConfigAttrib(_glfw.egl.display, config, + EGL_GREEN_SIZE, &greenBits); + _glfw_eglGetConfigAttrib(_glfw.egl.display, config, + EGL_BLUE_SIZE, &blueBits); + _glfw_eglGetConfigAttrib(_glfw.egl.display, config, + EGL_ALPHA_SIZE, &alphaBits); info.depth = redBits + greenBits + blueBits + alphaBits; mask |= VisualDepthMask; @@ -291,21 +362,21 @@ int _glfwCreateContext(_GLFWwindow* window, if (ctxconfig->api == GLFW_OPENGL_ES_API) { - if (!eglBindAPI(EGL_OPENGL_ES_API)) + if (!_glfw_eglBindAPI(EGL_OPENGL_ES_API)) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to bind OpenGL ES: %s", - getErrorString(eglGetError())); + getErrorString(_glfw_eglGetError())); return GL_FALSE; } } else { - if (!eglBindAPI(EGL_OPENGL_API)) + if (!_glfw_eglBindAPI(EGL_OPENGL_API)) { _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to bind OpenGL: %s", - getErrorString(eglGetError())); + getErrorString(_glfw_eglGetError())); return GL_FALSE; } } @@ -371,14 +442,14 @@ int _glfwCreateContext(_GLFWwindow* window, // Context release behaviors (GL_KHR_context_flush_control) are not yet // supported on EGL but are not a hard constraint, so ignore and continue - window->egl.context = eglCreateContext(_glfw.egl.display, - config, share, attribs); + window->egl.context = _glfw_eglCreateContext(_glfw.egl.display, + config, share, attribs); if (window->egl.context == EGL_NO_CONTEXT) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "EGL: Failed to create context: %s", - getErrorString(eglGetError())); + getErrorString(_glfw_eglGetError())); return GL_FALSE; } @@ -403,13 +474,13 @@ void _glfwDestroyContext(_GLFWwindow* window) if (window->egl.surface) { - eglDestroySurface(_glfw.egl.display, window->egl.surface); + _glfw_eglDestroySurface(_glfw.egl.display, window->egl.surface); window->egl.surface = EGL_NO_SURFACE; } if (window->egl.context) { - eglDestroyContext(_glfw.egl.display, window->egl.context); + _glfw_eglDestroyContext(_glfw.egl.display, window->egl.context); window->egl.context = EGL_NO_CONTEXT; } } @@ -438,27 +509,30 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) { if (window->egl.surface == EGL_NO_SURFACE) { - window->egl.surface = eglCreateWindowSurface(_glfw.egl.display, - window->egl.config, - (EGLNativeWindowType)_GLFW_EGL_NATIVE_WINDOW, - NULL); + window->egl.surface = + _glfw_eglCreateWindowSurface(_glfw.egl.display, + window->egl.config, + (EGLNativeWindowType)_GLFW_EGL_NATIVE_WINDOW, + NULL); if (window->egl.surface == EGL_NO_SURFACE) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: Failed to create window surface: %s", - getErrorString(eglGetError())); + getErrorString(_glfw_eglGetError())); } } - eglMakeCurrent(_glfw.egl.display, - window->egl.surface, - window->egl.surface, - window->egl.context); + _glfw_eglMakeCurrent(_glfw.egl.display, + window->egl.surface, + window->egl.surface, + window->egl.context); } else { - eglMakeCurrent(_glfw.egl.display, - EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + _glfw_eglMakeCurrent(_glfw.egl.display, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + EGL_NO_CONTEXT); } _glfwSetContextTLS(window); @@ -466,17 +540,18 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) void _glfwPlatformSwapBuffers(_GLFWwindow* window) { - eglSwapBuffers(_glfw.egl.display, window->egl.surface); + _glfw_eglSwapBuffers(_glfw.egl.display, window->egl.surface); } void _glfwPlatformSwapInterval(int interval) { - eglSwapInterval(_glfw.egl.display, interval); + _glfw_eglSwapInterval(_glfw.egl.display, interval); } int _glfwPlatformExtensionSupported(const char* extension) { - const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); + const char* extensions = _glfw_eglQueryString(_glfw.egl.display, + EGL_EXTENSIONS); if (extensions) { if (_glfwStringInExtensionString(extension, extensions)) @@ -488,7 +563,7 @@ int _glfwPlatformExtensionSupported(const char* extension) GLFWglproc _glfwPlatformGetProcAddress(const char* procname) { - return eglGetProcAddress(procname); + return _glfw_eglGetProcAddress(procname); } diff --git a/src/egl_context.h b/src/egl_context.h index c828690e..4a1f343f 100644 --- a/src/egl_context.h +++ b/src/egl_context.h @@ -28,6 +28,17 @@ #ifndef _glfw3_egl_context_h_ #define _glfw3_egl_context_h_ +#if defined(_GLFW_WIN32) + #define _glfw_dlopen(name) LoadLibraryA(name) + #define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle) + #define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name) +#else + #include + #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) + #define _glfw_dlclose(handle) dlclose(handle) + #define _glfw_dlsym(handle, name) dlsym(handle, name) +#endif + #include // This path may need to be changed if you build GLFW using your own setup @@ -35,6 +46,40 @@ // extensions and not all operating systems come with an up-to-date version #include "../deps/EGL/eglext.h" +// EGL function pointer typedefs +typedef EGLBoolean (EGLAPIENTRY * PFNEGLGETCONFIGATTRIBPROC)(EGLDisplay,EGLConfig,EGLint,EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLGETCONFIGSPROC)(EGLDisplay,EGLConfig*,EGLint,EGLint*); +typedef EGLDisplay (EGLAPIENTRY * PFNEGLGETDISPLAYPROC)(EGLNativeDisplayType); +typedef EGLint (EGLAPIENTRY * PFNEGLGETERRORPROC)(void); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLINITIALIZEPROC)(EGLDisplay,EGLint*,EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLTERMINATEPROC)(EGLDisplay); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLBINDAPIPROC)(EGLenum); +typedef EGLContext (EGLAPIENTRY * PFNEGLCREATECONTEXTPROC)(EGLDisplay,EGLConfig,EGLContext,const EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLDESTROYSURFACEPROC)(EGLDisplay,EGLSurface); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLDESTROYCONTEXTPROC)(EGLDisplay,EGLContext); +typedef EGLSurface (EGLAPIENTRY * PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLMAKECURRENTPROC)(EGLDisplay,EGLSurface,EGLSurface,EGLContext); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLSWAPBUFFERSPROC)(EGLDisplay,EGLSurface); +typedef EGLBoolean (EGLAPIENTRY * PFNEGLSWAPINTERVALPROC)(EGLDisplay,EGLint); +typedef const char* (EGLAPIENTRY * PFNEGLQUERYSTRINGPROC)(EGLDisplay,EGLint); +typedef GLFWglproc (EGLAPIENTRY * PFNEGLGETPROCADDRESSPROC)(const char*); +#define _glfw_eglGetConfigAttrib _glfw.egl.GetConfigAttrib +#define _glfw_eglGetConfigs _glfw.egl.GetConfigs +#define _glfw_eglGetDisplay _glfw.egl.GetDisplay +#define _glfw_eglGetError _glfw.egl.GetError +#define _glfw_eglInitialize _glfw.egl.Initialize +#define _glfw_eglTerminate _glfw.egl.Terminate +#define _glfw_eglBindAPI _glfw.egl.BindAPI +#define _glfw_eglCreateContext _glfw.egl.CreateContext +#define _glfw_eglDestroySurface _glfw.egl.DestroySurface +#define _glfw_eglDestroyContext _glfw.egl.DestroyContext +#define _glfw_eglCreateWindowSurface _glfw.egl.CreateWindowSurface +#define _glfw_eglMakeCurrent _glfw.egl.MakeCurrent +#define _glfw_eglSwapBuffers _glfw.egl.SwapBuffers +#define _glfw_eglSwapInterval _glfw.egl.SwapInterval +#define _glfw_eglQueryString _glfw.egl.QueryString +#define _glfw_eglGetProcAddress _glfw.egl.GetProcAddress + #define _GLFW_PLATFORM_FBCONFIG EGLConfig egl #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextEGL egl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl @@ -64,6 +109,25 @@ typedef struct _GLFWlibraryEGL GLboolean KHR_create_context; + void* handle; + + PFNEGLGETCONFIGATTRIBPROC GetConfigAttrib; + PFNEGLGETCONFIGSPROC GetConfigs; + PFNEGLGETDISPLAYPROC GetDisplay; + PFNEGLGETERRORPROC GetError; + PFNEGLINITIALIZEPROC Initialize; + PFNEGLTERMINATEPROC Terminate; + PFNEGLBINDAPIPROC BindAPI; + PFNEGLCREATECONTEXTPROC CreateContext; + PFNEGLDESTROYSURFACEPROC DestroySurface; + PFNEGLDESTROYCONTEXTPROC DestroyContext; + PFNEGLCREATEWINDOWSURFACEPROC CreateWindowSurface; + PFNEGLMAKECURRENTPROC MakeCurrent; + PFNEGLSWAPBUFFERSPROC SwapBuffers; + PFNEGLSWAPINTERVALPROC SwapInterval; + PFNEGLQUERYSTRINGPROC QueryString; + PFNEGLGETPROCADDRESSPROC GetProcAddress; + } _GLFWlibraryEGL;