Add run-time context creation API selection Fixes #145.
diff --git a/CMakeLists.txt b/CMakeLists.txt index 070beae..02040dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -35,13 +35,11 @@ option(GLFW_USE_CHDIR "Make glfwInit chdir to Contents/Resources" ON) option(GLFW_USE_MENUBAR "Populate the menu bar on first window creation" ON) option(GLFW_USE_RETINA "Use the full resolution of Retina displays" ON) -else() - option(GLFW_USE_EGL "Use EGL for context creation" OFF) endif() if (UNIX AND NOT APPLE) - option(GLFW_USE_WAYLAND "Use Wayland for context creation (implies EGL as well)" OFF) - option(GLFW_USE_MIR "Use Mir for context creation (implies EGL as well)" OFF) + option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF) + option(GLFW_USE_MIR "Use Mir for window creation" OFF) endif() if (MSVC) @@ -59,12 +57,6 @@ set(GLFW_LIB_NAME glfw3) endif() -if (GLFW_USE_WAYLAND) - set(GLFW_USE_EGL ON) -elseif (GLFW_USE_MIR) - set(GLFW_USE_EGL ON) -endif() - set(CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules") find_package(Threads REQUIRED) @@ -129,19 +121,9 @@ if (WIN32) set(_GLFW_WIN32 1) message(STATUS "Using Win32 for window creation") - - if (GLFW_USE_EGL) - set(_GLFW_EGL 1) - message(STATUS "Using EGL for context creation") - else() - set(_GLFW_WGL 1) - message(STATUS "Using WGL for context creation") - endif() elseif (APPLE) set(_GLFW_COCOA 1) message(STATUS "Using Cocoa for window creation") - set(_GLFW_NSGL 1) - message(STATUS "Using NSGL for context creation") elseif (UNIX) if (GLFW_USE_WAYLAND) set(_GLFW_WAYLAND 1) @@ -153,14 +135,6 @@ set(_GLFW_X11 1) message(STATUS "Using X11 for window creation") endif() - - if (GLFW_USE_EGL) - set(_GLFW_EGL 1) - message(STATUS "Using EGL for context creation") - else() - set(_GLFW_GLX 1) - message(STATUS "Using GLX for context creation") - endif() else() message(FATAL_ERROR "No supported platform was detected") endif() @@ -306,7 +280,7 @@ #-------------------------------------------------------------------- # Use Cocoa for window creation and NSOpenGL for context creation #-------------------------------------------------------------------- -if (_GLFW_COCOA AND _GLFW_NSGL) +if (_GLFW_COCOA) if (GLFW_USE_MENUBAR) set(_GLFW_USE_MENUBAR 1)
diff --git a/README.md b/README.md index 0321e2c..aa72d5e 100644 --- a/README.md +++ b/README.md
@@ -93,12 +93,14 @@ - Added `GLFW_NO_API` for creating window without contexts - Added `GLFW_CONTEXT_NO_ERROR` context hint for `GL_KHR_no_error` support - Added `GLFW_INCLUDE_VULKAN` for including the Vulkan header + - Added `GLFW_CONTEXT_CREATION_API`, `GLFW_NATIVE_CONTEXT_API` and + `GLFW_EGL_CONTEXT_API` for run-time context creation API selection - Added `GLFW_TRUE` and `GLFW_FALSE` as client API independent boolean values - Added icons to examples on Windows and OS X - Relaxed rules for native access header macros - Removed dependency on external OpenGL or OpenGL ES headers - - Removed `_GLFW_USE_OPENGL`, `_GLFW_USE_GLESV1` and `_GLFW_USE_GLESV2` - configuration macros + - Removed `_GLFW_USE_OPENGL`, `_GLFW_USE_GLESV1`, `_GLFW_USE_GLESV2`, + `_GLFW_WGL`, `_GLFW_NSGL`, `_GLFW_GLX` and `_GLFW_EGL` configuration macros - [Win32] Added support for Windows 8.1 per-monitor DPI - [Win32] Replaced winmm with XInput and DirectInput for joystick input - [Win32] Bugfix: Window creation would segfault if video mode setting required
diff --git a/docs/compile.dox b/docs/compile.dox index e164671..adadf77 100644 --- a/docs/compile.dox +++ b/docs/compile.dox
@@ -225,19 +225,13 @@ will not work if GLFW is built as a DLL. -@subsubsection compile_options_egl EGL specific CMake options - -`GLFW_USE_EGL` determines whether to use EGL instead of the platform-specific -context creation API. Note that EGL is not yet provided on all supported -platforms. - - @section compile_manual Compiling GLFW manually If you wish to compile GLFW without its CMake build environment then you will have to do at least some of the platform detection yourself. GLFW needs -a number of configuration macros to be defined in order to know what it's being -compiled for and has many optional, platform-specific ones for various features. +a configuration macro to be defined in order to know what window system it's +being compiled for and also has optional, platform-specific ones for various +features. When building with CMake, the `glfw_config.h` configuration header is generated based on the current platform and CMake options. The GLFW CMake environment @@ -245,10 +239,6 @@ `internal.h`. Without this macro, GLFW will expect the necessary configuration macros to be defined on the command-line. -Three macros _must_ be defined when compiling GLFW: one selecting the window -creation API and one selecting the context creation API. Exactly one of each -kind must be defined for GLFW to compile and link. - The window creation API is used to create windows, handle input, monitors, gamma ramps and clipboard. The options are: @@ -258,19 +248,14 @@ - `_GLFW_WAYLAND` to use the Wayland API (experimental and incomplete) - `_GLFW_MIR` to use the Mir API (experimental and incomplete) -The context creation API is used to enumerate pixel formats / framebuffer -configurations and to create contexts. The options are: - - - `_GLFW_NSGL` to use the Cocoa OpenGL framework - - `_GLFW_WGL` to use the Win32 WGL API - - `_GLFW_GLX` to use the X11 GLX API - - `_GLFW_EGL` to use the EGL API - -Wayland and Mir both require the EGL backend. - If you are building GLFW as a shared library / dynamic library / DLL then you must also define `_GLFW_BUILD_DLL`. Otherwise, you must not define it. +For the EGL context creation API, the following options are available: + + - `_GLFW_USE_EGLPLATFORM_H` to use `EGL/eglplatform.h` for native handle + definitions (fallback) + If you are using the X11 window creation API, support for the following X11 extensions can be enabled: @@ -287,12 +272,6 @@ - `_GLFW_USE_RETINA` to have windows use the full resolution of Retina displays (recommended) -If you are using the EGL context creation API, the following options are -available: - - - `_GLFW_USE_EGLPLATFORM_H` to use `EGL/eglplatform.h` for native handle - definitions (fallback) - @note None of the @ref build_macros may be defined during the compilation of GLFW. If you define any of these in your build files, make sure they are not applied to the GLFW sources.
diff --git a/docs/context.dox b/docs/context.dox index 62bbc61..7cc1f12 100644 --- a/docs/context.dox +++ b/docs/context.dox
@@ -177,9 +177,10 @@ @endcode The `--no-loader` option is added because GLFW already provides a function for -loading OpenGL and OpenGL ES function pointers and glad can call this instead of -having to implement its own. There are several other command-line options as -well. See the glad documentation for details. +loading OpenGL and OpenGL ES function pointers, one that automatically uses the +selected context creation API, and glad can call this instead of having to +implement its own. There are several other command-line options as well. See +the glad documentation for details. Add the generated `output/src/glad.c`, `output/include/glad/glad.h` and `output/include/KHR/khrplatform.h` files to your build. Then you need to
diff --git a/docs/news.dox b/docs/news.dox index dae8430..e0fb5f8 100644 --- a/docs/news.dox +++ b/docs/news.dox
@@ -61,6 +61,12 @@ glfwWaitEventsTimeout. +@subsection news_32_contextapi Run-time context creation API selection + +GLFW now supports selecting the context creation API at run-time with +[GLFW_CONTEXT_CREATION_API](@ref window_hints_ctx). + + @section news_31 New features in 3.1 These are the release highlights. For a full list of changes see the
diff --git a/docs/window.dox b/docs/window.dox index 953e2ea..b66874b 100644 --- a/docs/window.dox +++ b/docs/window.dox
@@ -159,6 +159,7 @@ - `GLFW_STEREO` - `GLFW_DOUBLEBUFFER` - `GLFW_CLIENT_API` +- `GLFW_CONTEXT_CREATION_API` The following additional hints are hard constraints when requesting an OpenGL context, but are ignored when requesting an OpenGL ES context: @@ -249,6 +250,24 @@ Possible values are `GLFW_OPENGL_API`, `GLFW_OPENGL_ES_API` and `GLFW_NO_API`. This is a hard constraint. +`GLFW_CONTEXT_CREATION_API` specifies which context creation API to use to +create the context. Possible values are `GLFW_NATIVE_CONTEXT_API` and +`GLFW_EGL_CONTEXT_API`. This is a hard constraint. If no client API is +requested, this hint is ignored. + +@par +__OS X:__ The EGL API is not available on this platform and requests to use it +will fail. + +@par +__Wayland, Mir:__ The EGL API _is_ the native context creation API, so this hint +will have no effect. + +@note An OpenGL extension loader library that assumes it knows which context +creation API is used on a given platform may fail if you change this hint. This +can be resolved by having it load via @ref glfwGetProcAddress, which always uses +the selected API. + `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` specify the client API version that the created context must be compatible with. The exact behavior of these hints depend on the requested client API. @@ -362,6 +381,7 @@ `GLFW_SRGB_CAPABLE` | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` `GLFW_DOUBLEBUFFER` | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` `GLFW_CLIENT_API` | `GLFW_OPENGL_API` | `GLFW_OPENGL_API`, `GLFW_OPENGL_ES_API` or `GLFW_NO_API` +`GLFW_CONTEXT_CREATION_API` | `GLFW_NATIVE_CONTEXT_API` | `GLFW_NATIVE_CONTEXT_API` or `GLFW_EGL_CONTEXT_API` `GLFW_CONTEXT_VERSION_MAJOR` | 1 | Any valid major version number of the chosen client API `GLFW_CONTEXT_VERSION_MINOR` | 0 | Any valid minor version number of the chosen client API `GLFW_CONTEXT_ROBUSTNESS` | `GLFW_NO_ROBUSTNESS` | `GLFW_NO_ROBUSTNESS`, `GLFW_NO_RESET_NOTIFICATION` or `GLFW_LOSE_CONTEXT_ON_RESET` @@ -889,6 +909,10 @@ `GLFW_CLIENT_API` indicates the client API provided by the window's context; either `GLFW_OPENGL_API`, `GLFW_OPENGL_ES_API` or `GLFW_NO_API`. +`GLFW_CONTEXT_CREATION_API` indicates the context creation API used to create +the window's context; either `GLFW_NATIVE_CONTEXT_API` or +`GLFW_EGL_CONTEXT_API`. + `GLFW_CONTEXT_VERSION_MAJOR`, `GLFW_CONTEXT_VERSION_MINOR` and `GLFW_CONTEXT_REVISION` indicate the client API version of the window's context.
diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 06c722c..4e4bdcd 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h
@@ -655,6 +655,7 @@ #define GLFW_OPENGL_PROFILE 0x00022008 #define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 #define GLFW_CONTEXT_NO_ERROR 0x0002200A +#define GLFW_CONTEXT_CREATION_API 0x0002200B #define GLFW_NO_API 0 #define GLFW_OPENGL_API 0x00030001 @@ -680,6 +681,9 @@ #define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 #define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 +#define GLFW_NATIVE_CONTEXT_API 0x00036001 +#define GLFW_EGL_CONTEXT_API 0x00036002 + /*! @defgroup shapes Standard cursor shapes * * See [standard cursor creation](@ref cursor_standard) for how these are used.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dab94ef..5042aba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt
@@ -7,23 +7,29 @@ if (_GLFW_COCOA) set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h - posix_tls.h) + posix_tls.h nsgl_context.h) set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m - cocoa_monitor.m cocoa_window.m cocoa_time.c posix_tls.c) + cocoa_monitor.m cocoa_window.m cocoa_time.c posix_tls.c + nsgl_context.m) elseif (_GLFW_WIN32) - set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h) + set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h + wgl_context.h egl_context.h) set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_joystick.c - win32_monitor.c win32_time.c win32_tls.c win32_window.c) + win32_monitor.c win32_time.c win32_tls.c win32_window.c + wgl_context.c egl_context.c) elseif (_GLFW_X11) set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h - linux_joystick.h posix_time.h posix_tls.h) + linux_joystick.h posix_time.h posix_tls.h glx_context.h + egl_context.h) set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c - xkb_unicode.c linux_joystick.c posix_time.c posix_tls.c) + xkb_unicode.c linux_joystick.c posix_time.c posix_tls.c + glx_context.c egl_context.c) elseif (_GLFW_WAYLAND) set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h - posix_time.h posix_tls.h xkb_unicode.h) + posix_time.h posix_tls.h xkb_unicode.h egl_context.h) set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c - linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c) + linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c + egl_context.c) ecm_add_wayland_client_protocol(glfw_SOURCES PROTOCOL @@ -35,23 +41,10 @@ BASENAME pointer-constraints-unstable-v1) elseif (_GLFW_MIR) set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h - posix_time.h posix_tls.h xkb_unicode.h) + posix_time.h posix_tls.h xkb_unicode.h egl_context.h) set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c - linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c) -endif() - -if (_GLFW_EGL) - list(APPEND glfw_HEADERS ${common_HEADERS} egl_context.h) - list(APPEND glfw_SOURCES ${common_SOURCES} egl_context.c) -elseif (_GLFW_NSGL) - list(APPEND glfw_HEADERS ${common_HEADERS} nsgl_context.h) - list(APPEND glfw_SOURCES ${common_SOURCES} nsgl_context.m) -elseif (_GLFW_WGL) - list(APPEND glfw_HEADERS ${common_HEADERS} wgl_context.h) - list(APPEND glfw_SOURCES ${common_SOURCES} wgl_context.c) -elseif (_GLFW_X11) - list(APPEND glfw_HEADERS ${common_HEADERS} glx_context.h) - list(APPEND glfw_SOURCES ${common_SOURCES} glx_context.c) + linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c + egl_context.c) endif() if (APPLE)
diff --git a/src/cocoa_init.m b/src/cocoa_init.m index 16b8c9f..9b6434d 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m
@@ -280,10 +280,7 @@ const char* _glfwPlatformGetVersionString(void) { - return _GLFW_VERSION_NUMBER " Cocoa" -#if defined(_GLFW_NSGL) - " NSGL" -#endif + return _GLFW_VERSION_NUMBER " Cocoa NSGL" #if defined(_GLFW_USE_CHDIR) " chdir" #endif
diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index eeeb472..95eae62 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h
@@ -41,12 +41,7 @@ #include "posix_tls.h" #include "cocoa_joystick.h" - -#if defined(_GLFW_NSGL) - #include "nsgl_context.h" -#else - #error "The Cocoa backend depends on NSGL platform support" -#endif +#include "nsgl_context.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) @@ -58,6 +53,9 @@ #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns +#define _GLFW_EGL_CONTEXT_STATE +#define _GLFW_EGL_LIBRARY_CONTEXT_STATE + // Cocoa-specific per-window data //
diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 6f51439..f5e9928 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m
@@ -209,7 +209,7 @@ - (void)windowDidResize:(NSNotification *)notification { - if (window->context.api != GLFW_NO_API) + if (window->context.client != GLFW_NO_API) [window->context.nsgl.object update]; if (_glfw.cursorWindow == window && @@ -227,7 +227,7 @@ - (void)windowDidMove:(NSNotification *)notification { - if (window->context.api != GLFW_NO_API) + if (window->context.client != GLFW_NO_API) [window->context.nsgl.object update]; if (_glfw.cursorWindow == window && @@ -1002,10 +1002,18 @@ if (!createWindow(window, wndconfig)) return GLFW_FALSE; - if (ctxconfig->api != GLFW_NO_API) + if (ctxconfig->client != GLFW_NO_API) { - if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig)) + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else + { + _glfwInputError(GLFW_API_UNAVAILABLE, "Cocoa: EGL not available"); return GLFW_FALSE; + } } if (window->monitor) @@ -1026,8 +1034,8 @@ if (window->monitor) releaseMonitor(window); - if (window->context.api != GLFW_NO_API) - _glfwDestroyContextNSGL(window); + if (window->context.client != GLFW_NO_API) + window->context.destroyContext(window); [window->ns.object setDelegate:nil]; [window->ns.delegate release];
diff --git a/src/context.c b/src/context.c index eb8a561..5f4a08c 100644 --- a/src/context.c +++ b/src/context.c
@@ -90,17 +90,26 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) { - if (ctxconfig->api != GLFW_NO_API && - ctxconfig->api != GLFW_OPENGL_API && - ctxconfig->api != GLFW_OPENGL_ES_API) + if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API && + ctxconfig->source != GLFW_EGL_CONTEXT_API) { _glfwInputError(GLFW_INVALID_ENUM, - "Invalid client API %i", - ctxconfig->api); + "Invalid context creation API %i", + ctxconfig->source); return GLFW_FALSE; } - if (ctxconfig->api == GLFW_OPENGL_API) + if (ctxconfig->client != GLFW_NO_API && + ctxconfig->client != GLFW_OPENGL_API && + ctxconfig->client != GLFW_OPENGL_ES_API) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid client API %i", + ctxconfig->client); + return GLFW_FALSE; + } + + if (ctxconfig->client == GLFW_OPENGL_API) { if ((ctxconfig->major < 1 || ctxconfig->minor < 0) || (ctxconfig->major == 1 && ctxconfig->minor > 5) || @@ -150,7 +159,7 @@ return GLFW_FALSE; } } - else if (ctxconfig->api == GLFW_OPENGL_ES_API) + else if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (ctxconfig->major < 1 || ctxconfig->minor < 0 || (ctxconfig->major == 1 && ctxconfig->minor > 1) || @@ -366,8 +375,13 @@ glfwGetProcAddress("glGetIntegerv"); window->context.GetString = (PFNGLGETSTRINGPROC) glfwGetProcAddress("glGetString"); + if (!window->context.GetIntegerv || !window->context.GetString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); + return GLFW_FALSE; + } - if (!parseVersionString(&window->context.api, + if (!parseVersionString(&window->context.client, &window->context.major, &window->context.minor, &window->context.revision)) @@ -375,6 +389,8 @@ return GLFW_FALSE; } + window->context.source = ctxconfig->source; + if (window->context.major < ctxconfig->major || (window->context.major == ctxconfig->major && window->context.minor < ctxconfig->minor)) @@ -409,7 +425,7 @@ } } - if (window->context.api == GLFW_OPENGL_API) + if (window->context.client == GLFW_OPENGL_API) { // Read back context flags (OpenGL 3.0 and above) if (window->context.major >= 3) @@ -507,7 +523,7 @@ { PFNGLCLEARPROC glClear = (PFNGLCLEARPROC) glfwGetProcAddress("glClear"); glClear(GL_COLOR_BUFFER_BIT); - _glfwPlatformSwapBuffers(window); + window->context.swapBuffers(window); } return GLFW_TRUE; @@ -547,16 +563,24 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFWwindow* previous = _glfwPlatformGetCurrentContext(); _GLFW_REQUIRE_INIT(); - if (window && window->context.api == GLFW_NO_API) + if (window && window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return; } - _glfwPlatformMakeContextCurrent(window); + if (previous) + { + if (!window || window->context.source != previous->context.source) + previous->context.makeContextCurrent(NULL); + } + + if (window) + window->context.makeContextCurrent(window); } GLFWAPI GLFWwindow* glfwGetCurrentContext(void) @@ -572,26 +596,29 @@ _GLFW_REQUIRE_INIT(); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return; } - _glfwPlatformSwapBuffers(window); + window->context.swapBuffers(window); } GLFWAPI void glfwSwapInterval(int interval) { + _GLFWwindow* window; + _GLFW_REQUIRE_INIT(); - if (!_glfwPlatformGetCurrentContext()) + window = _glfwPlatformGetCurrentContext(); + if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); return; } - _glfwPlatformSwapInterval(interval); + window->context.swapInterval(interval); } GLFWAPI int glfwExtensionSupported(const char* extension) @@ -657,21 +684,23 @@ } // Check if extension is in the platform-specific string - return _glfwPlatformExtensionSupported(extension); + return window->context.extensionSupported(extension); } GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) { + _GLFWwindow* window; assert(procname != NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (!_glfwPlatformGetCurrentContext()) + window = _glfwPlatformGetCurrentContext(); + if (!window) { _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); return NULL; } - return _glfwPlatformGetProcAddress(procname); + return window->context.getProcAddress(procname); }
diff --git a/src/egl_context.c b/src/egl_context.c index 26df456..0620302 100644 --- a/src/egl_context.c +++ b/src/egl_context.c
@@ -125,7 +125,7 @@ continue; #endif // _GLFW_X11 - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (ctxconfig->major == 1) { @@ -138,7 +138,7 @@ continue; } } - else if (ctxconfig->api == GLFW_OPENGL_API) + else if (ctxconfig->client == GLFW_OPENGL_API) { if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT)) continue; @@ -169,6 +169,110 @@ return closest != NULL; } +static void makeContextCurrent(_GLFWwindow* window) +{ + if (window) + { + if (!eglMakeCurrent(_glfw.egl.display, + window->context.egl.surface, + window->context.egl.surface, + window->context.egl.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to make context current: %s", + getErrorString(eglGetError())); + return; + } + } + else + { + if (!eglMakeCurrent(_glfw.egl.display, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + EGL_NO_CONTEXT)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to clear current context: %s", + getErrorString(eglGetError())); + return; + } + } + + _glfwPlatformSetCurrentContext(window); +} + +static void swapBuffers(_GLFWwindow* window) +{ + if (window != _glfwPlatformGetCurrentContext()) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: The context must be current on the calling thread when swapping buffers"); + return; + } + + eglSwapBuffers(_glfw.egl.display, window->context.egl.surface); +} + +static void swapInterval(int interval) +{ + eglSwapInterval(_glfw.egl.display, interval); +} + +static int extensionSupported(const char* extension) +{ + const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddress(const char* procname) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (window->context.egl.client) + { + GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client, + procname); + if (proc) + return proc; + } + + return eglGetProcAddress(procname); +} + +static void destroyContext(_GLFWwindow* window) +{ +#if defined(_GLFW_X11) + // NOTE: Do not unload libGL.so.1 while the X11 display is still open, + // as it will make XCloseDisplay segfault + if (window->context.client != GLFW_OPENGL_API) +#endif // _GLFW_X11 + { + if (window->context.egl.client) + { + _glfw_dlclose(window->context.egl.client); + window->context.egl.client = NULL; + } + } + + if (window->context.egl.surface) + { + eglDestroySurface(_glfw.egl.display, window->context.egl.surface); + window->context.egl.surface = EGL_NO_SURFACE; + } + + if (window->context.egl.handle) + { + eglDestroyContext(_glfw.egl.display, window->context.egl.handle); + window->context.egl.handle = EGL_NO_CONTEXT; + } +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -200,10 +304,7 @@ } if (!_glfw.egl.handle) - { - _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to load EGL"); return GLFW_FALSE; - } _glfw.egl.GetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib"); @@ -244,6 +345,8 @@ _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to get EGL display: %s", getErrorString(eglGetError())); + + _glfwTerminateEGL(); return GLFW_FALSE; } @@ -252,15 +355,17 @@ _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Failed to initialize EGL: %s", getErrorString(eglGetError())); + + _glfwTerminateEGL(); return GLFW_FALSE; } _glfw.egl.KHR_create_context = - _glfwPlatformExtensionSupported("EGL_KHR_create_context"); + extensionSupported("EGL_KHR_create_context"); _glfw.egl.KHR_create_context_no_error = - _glfwPlatformExtensionSupported("EGL_KHR_create_context_no_error"); + extensionSupported("EGL_KHR_create_context_no_error"); _glfw.egl.KHR_gl_colorspace = - _glfwPlatformExtensionSupported("EGL_KHR_gl_colorspace"); + extensionSupported("EGL_KHR_gl_colorspace"); return GLFW_TRUE; } @@ -299,6 +404,12 @@ EGLConfig config; EGLContext share = NULL; + if (!_glfw.egl.display) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available"); + return GLFW_FALSE; + } + if (ctxconfig->share) share = ctxconfig->share->context.egl.handle; @@ -309,7 +420,7 @@ return GLFW_FALSE; } - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (!eglBindAPI(EGL_OPENGL_ES_API)) { @@ -334,7 +445,7 @@ { int index = 0, mask = 0, flags = 0; - if (ctxconfig->api == GLFW_OPENGL_API) + if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; @@ -388,7 +499,7 @@ { int index = 0; - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) setEGLattrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); setEGLattrib(EGL_NONE, EGL_NONE); @@ -477,7 +588,7 @@ NULL }; - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (ctxconfig->major == 1) sonames = es1sonames; @@ -502,41 +613,18 @@ } } + window->context.makeContextCurrent = makeContextCurrent; + window->context.swapBuffers = swapBuffers; + window->context.swapInterval = swapInterval; + window->context.extensionSupported = extensionSupported; + window->context.getProcAddress = getProcAddress; + window->context.destroyContext = destroyContext; + return GLFW_TRUE; } #undef setEGLattrib -// Destroy the OpenGL context -// -void _glfwDestroyContextEGL(_GLFWwindow* window) -{ -#if defined(_GLFW_X11) - // NOTE: Do not unload libGL.so.1 while the X11 display is still open, - // as it will make XCloseDisplay segfault - if (window->context.api != GLFW_OPENGL_API) -#endif // _GLFW_X11 - { - if (window->context.egl.client) - { - _glfw_dlclose(window->context.egl.client); - window->context.egl.client = NULL; - } - } - - if (window->context.egl.surface) - { - eglDestroySurface(_glfw.egl.display, window->context.egl.surface); - window->context.egl.surface = EGL_NO_SURFACE; - } - - if (window->context.egl.handle) - { - eglDestroyContext(_glfw.egl.display, window->context.egl.handle); - window->context.egl.handle = EGL_NO_CONTEXT; - } -} - // Returns the Visual and depth of the chosen EGLConfig // #if defined(_GLFW_X11) @@ -581,87 +669,6 @@ ////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) -{ - if (window) - { - if (!eglMakeCurrent(_glfw.egl.display, - window->context.egl.surface, - window->context.egl.surface, - window->context.egl.handle)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "EGL: Failed to make context current: %s", - getErrorString(eglGetError())); - return; - } - } - else - { - if (!eglMakeCurrent(_glfw.egl.display, - EGL_NO_SURFACE, - EGL_NO_SURFACE, - EGL_NO_CONTEXT)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "EGL: Failed to clear current context: %s", - getErrorString(eglGetError())); - return; - } - } - - _glfwPlatformSetCurrentContext(window); -} - -void _glfwPlatformSwapBuffers(_GLFWwindow* window) -{ - if (window != _glfwPlatformGetCurrentContext()) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "EGL: The context must be current on the calling thread when swapping buffers"); - return; - } - - eglSwapBuffers(_glfw.egl.display, window->context.egl.surface); -} - -void _glfwPlatformSwapInterval(int interval) -{ - eglSwapInterval(_glfw.egl.display, interval); -} - -int _glfwPlatformExtensionSupported(const char* extension) -{ - const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); - if (extensions) - { - if (_glfwStringInExtensionString(extension, extensions)) - return GLFW_TRUE; - } - - return GLFW_FALSE; -} - -GLFWglproc _glfwPlatformGetProcAddress(const char* procname) -{ - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - - if (window->context.egl.client) - { - GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client, - procname); - if (proc) - return proc; - } - - return eglGetProcAddress(procname); -} - - -////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// @@ -676,7 +683,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return EGL_NO_CONTEXT; @@ -690,7 +697,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return EGL_NO_SURFACE;
diff --git a/src/egl_context.h b/src/egl_context.h index 0b0b4dc..aed8a25 100644 --- a/src/egl_context.h +++ b/src/egl_context.h
@@ -149,8 +149,8 @@ #define eglQueryString _glfw.egl.QueryString #define eglGetProcAddress _glfw.egl.GetProcAddress -#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextEGL egl -#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl +#define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl +#define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl // EGL-specific per-context data @@ -204,7 +204,6 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); -void _glfwDestroyContextEGL(_GLFWwindow* window); #if defined(_GLFW_X11) GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig,
diff --git a/src/glfw_config.h.in b/src/glfw_config.h.in index ab57dd5..aed7f7a 100644 --- a/src/glfw_config.h.in +++ b/src/glfw_config.h.in
@@ -45,15 +45,6 @@ // Define this to 1 if building GLFW for Mir #cmakedefine _GLFW_MIR -// Define this to 1 if building GLFW for EGL -#cmakedefine _GLFW_EGL -// Define this to 1 if building GLFW for GLX -#cmakedefine _GLFW_GLX -// Define this to 1 if building GLFW for WGL -#cmakedefine _GLFW_WGL -// Define this to 1 if building GLFW for NSGL -#cmakedefine _GLFW_NSGL - // Define this to 1 if building as a shared library / dynamic library / DLL #cmakedefine _GLFW_BUILD_DLL
diff --git a/src/glx_context.c b/src/glx_context.c index 0a5b833..1760582 100644 --- a/src/glx_context.c +++ b/src/glx_context.c
@@ -142,6 +142,96 @@ True); } +static void makeContextCurrent(_GLFWwindow* window) +{ + if (window) + { + if (!glXMakeCurrent(_glfw.x11.display, + window->context.glx.window, + window->context.glx.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to make context current"); + return; + } + } + else + { + if (!glXMakeCurrent(_glfw.x11.display, None, NULL)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to clear current context"); + return; + } + } + + _glfwPlatformSetCurrentContext(window); +} + +static void swapBuffers(_GLFWwindow* window) +{ + glXSwapBuffers(_glfw.x11.display, window->context.glx.window); +} + +static void swapInterval(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (_glfw.glx.EXT_swap_control) + { + _glfw.glx.SwapIntervalEXT(_glfw.x11.display, + window->context.glx.window, + interval); + } + else if (_glfw.glx.MESA_swap_control) + _glfw.glx.SwapIntervalMESA(interval); + else if (_glfw.glx.SGI_swap_control) + { + if (interval > 0) + _glfw.glx.SwapIntervalSGI(interval); + } +} + +static int extensionSupported(const char* extension) +{ + const char* extensions = + glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddress(const char* procname) +{ + if (_glfw.glx.GetProcAddress) + return _glfw.glx.GetProcAddress((const GLubyte*) procname); + else if (_glfw.glx.GetProcAddressARB) + return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); + else + return dlsym(_glfw.glx.handle, procname); +} + +// Destroy the OpenGL context +// +static void destroyContext(_GLFWwindow* window) +{ + if (window->context.glx.window) + { + glXDestroyWindow(_glfw.x11.display, window->context.glx.window); + window->context.glx.window = None; + } + + if (window->context.glx.handle) + { + glXDestroyContext(_glfw.x11.display, window->context.glx.handle); + window->context.glx.handle = NULL; + } +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -229,61 +319,61 @@ return GLFW_FALSE; } - if (_glfwPlatformExtensionSupported("GLX_EXT_swap_control")) + if (extensionSupported("GLX_EXT_swap_control")) { _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) - _glfwPlatformGetProcAddress("glXSwapIntervalEXT"); + getProcAddress("glXSwapIntervalEXT"); if (_glfw.glx.SwapIntervalEXT) _glfw.glx.EXT_swap_control = GLFW_TRUE; } - if (_glfwPlatformExtensionSupported("GLX_SGI_swap_control")) + if (extensionSupported("GLX_SGI_swap_control")) { _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) - _glfwPlatformGetProcAddress("glXSwapIntervalSGI"); + getProcAddress("glXSwapIntervalSGI"); if (_glfw.glx.SwapIntervalSGI) _glfw.glx.SGI_swap_control = GLFW_TRUE; } - if (_glfwPlatformExtensionSupported("GLX_MESA_swap_control")) + if (extensionSupported("GLX_MESA_swap_control")) { _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) - _glfwPlatformGetProcAddress("glXSwapIntervalMESA"); + getProcAddress("glXSwapIntervalMESA"); if (_glfw.glx.SwapIntervalMESA) _glfw.glx.MESA_swap_control = GLFW_TRUE; } - if (_glfwPlatformExtensionSupported("GLX_ARB_multisample")) + if (extensionSupported("GLX_ARB_multisample")) _glfw.glx.ARB_multisample = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_ARB_framebuffer_sRGB")) + if (extensionSupported("GLX_ARB_framebuffer_sRGB")) _glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_EXT_framebuffer_sRGB")) + if (extensionSupported("GLX_EXT_framebuffer_sRGB")) _glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_ARB_create_context")) + if (extensionSupported("GLX_ARB_create_context")) { _glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) - _glfwPlatformGetProcAddress("glXCreateContextAttribsARB"); + getProcAddress("glXCreateContextAttribsARB"); if (_glfw.glx.CreateContextAttribsARB) _glfw.glx.ARB_create_context = GLFW_TRUE; } - if (_glfwPlatformExtensionSupported("GLX_ARB_create_context_robustness")) + if (extensionSupported("GLX_ARB_create_context_robustness")) _glfw.glx.ARB_create_context_robustness = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_ARB_create_context_profile")) + if (extensionSupported("GLX_ARB_create_context_profile")) _glfw.glx.ARB_create_context_profile = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_EXT_create_context_es2_profile")) + if (extensionSupported("GLX_EXT_create_context_es2_profile")) _glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE; - if (_glfwPlatformExtensionSupported("GLX_ARB_context_flush_control")) + if (extensionSupported("GLX_ARB_context_flush_control")) _glfw.glx.ARB_context_flush_control = GLFW_TRUE; return GLFW_TRUE; @@ -330,7 +420,7 @@ return GLFW_FALSE; } - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (!_glfw.glx.ARB_create_context || !_glfw.glx.ARB_create_context_profile || @@ -369,7 +459,7 @@ { int index = 0, mask = 0, flags = 0; - if (ctxconfig->api == GLFW_OPENGL_API) + if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; @@ -454,7 +544,7 @@ if (!window->context.glx.handle) { if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && - ctxconfig->api == GLFW_OPENGL_API && + ctxconfig->client == GLFW_OPENGL_API && ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && ctxconfig->forward == GLFW_FALSE) { @@ -482,28 +572,18 @@ return GLFW_FALSE; } + window->context.makeContextCurrent = makeContextCurrent; + window->context.swapBuffers = swapBuffers; + window->context.swapInterval = swapInterval; + window->context.extensionSupported = extensionSupported; + window->context.getProcAddress = getProcAddress; + window->context.destroyContext = destroyContext; + return GLFW_TRUE; } #undef setGLXattrib -// Destroy the OpenGL context -// -void _glfwDestroyContextGLX(_GLFWwindow* window) -{ - if (window->context.glx.window) - { - glXDestroyWindow(_glfw.x11.display, window->context.glx.window); - window->context.glx.window = None; - } - - if (window->context.glx.handle) - { - glXDestroyContext(_glfw.x11.display, window->context.glx.handle); - window->context.glx.handle = NULL; - } -} - // Returns the Visual and depth of the chosen GLXFBConfig // GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, @@ -537,84 +617,6 @@ ////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) -{ - if (window) - { - if (!glXMakeCurrent(_glfw.x11.display, - window->context.glx.window, - window->context.glx.handle)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "GLX: Failed to make context current"); - return; - } - } - else - { - if (!glXMakeCurrent(_glfw.x11.display, None, NULL)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "GLX: Failed to clear current context"); - return; - } - } - - _glfwPlatformSetCurrentContext(window); -} - -void _glfwPlatformSwapBuffers(_GLFWwindow* window) -{ - glXSwapBuffers(_glfw.x11.display, window->context.glx.window); -} - -void _glfwPlatformSwapInterval(int interval) -{ - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - - if (_glfw.glx.EXT_swap_control) - { - _glfw.glx.SwapIntervalEXT(_glfw.x11.display, - window->context.glx.window, - interval); - } - else if (_glfw.glx.MESA_swap_control) - _glfw.glx.SwapIntervalMESA(interval); - else if (_glfw.glx.SGI_swap_control) - { - if (interval > 0) - _glfw.glx.SwapIntervalSGI(interval); - } -} - -int _glfwPlatformExtensionSupported(const char* extension) -{ - const char* extensions = - glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen); - if (extensions) - { - if (_glfwStringInExtensionString(extension, extensions)) - return GLFW_TRUE; - } - - return GLFW_FALSE; -} - -GLFWglproc _glfwPlatformGetProcAddress(const char* procname) -{ - if (_glfw.glx.GetProcAddress) - return _glfw.glx.GetProcAddress((const GLubyte*) procname); - else if (_glfw.glx.GetProcAddressARB) - return _glfw.glx.GetProcAddressARB((const GLubyte*) procname); - else - return dlsym(_glfw.glx.handle, procname); -} - - -////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// @@ -623,7 +625,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; @@ -637,7 +639,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(None); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return None;
diff --git a/src/internal.h b/src/internal.h index e830477..6c084f8 100644 --- a/src/internal.h +++ b/src/internal.h
@@ -58,6 +58,13 @@ typedef struct _GLFWmonitor _GLFWmonitor; typedef struct _GLFWcursor _GLFWcursor; +typedef void (* _GLFWmakecontextcurrentfun)(_GLFWwindow*); +typedef void (* _GLFWswapbuffersfun)(_GLFWwindow*); +typedef void (* _GLFWswapintervalfun)(int); +typedef int (* _GLFWextensionsupportedfun)(const char*); +typedef GLFWglproc (* _GLFWgetprocaddressfun)(const char*); +typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*); + #define GL_VERSION 0x1f02 #define GL_NONE 0 #define GL_COLOR_BUFFER_BIT 0x00004000 @@ -258,7 +265,8 @@ */ struct _GLFWctxconfig { - int api; + int client; + int source; int major; int minor; GLFWbool forward; @@ -304,7 +312,8 @@ */ struct _GLFWcontext { - int api; + int client; + int source; int major, minor, revision; GLFWbool forward, debug, noerror; int profile; @@ -315,8 +324,17 @@ PFNGLGETINTEGERVPROC GetIntegerv; PFNGLGETSTRINGPROC GetString; + _GLFWmakecontextcurrentfun makeContextCurrent; + _GLFWswapbuffersfun swapBuffers; + _GLFWswapintervalfun swapInterval; + _GLFWextensionsupportedfun extensionSupported; + _GLFWgetprocaddressfun getProcAddress; + _GLFWdestroycontextfun destroyContext; + // This is defined in the context API's context.h _GLFW_PLATFORM_CONTEXT_STATE; + // This is defined in egl_context.h + _GLFW_EGL_CONTEXT_STATE; }; @@ -461,6 +479,8 @@ _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE; // This is defined in the platform's tls.h _GLFW_PLATFORM_LIBRARY_TLS_STATE; + // This is defined in egl_context.h + _GLFW_EGL_LIBRARY_CONTEXT_STATE; }; @@ -742,11 +762,6 @@ */ void _glfwPlatformPostEmptyEvent(void); -/*! @copydoc glfwMakeContextCurrent - * @ingroup platform - */ -void _glfwPlatformMakeContextCurrent(_GLFWwindow* window); - /*! @ingroup platform */ void _glfwPlatformSetCurrentContext(_GLFWwindow* context); @@ -756,26 +771,6 @@ */ _GLFWwindow* _glfwPlatformGetCurrentContext(void); -/*! @copydoc glfwSwapBuffers - * @ingroup platform - */ -void _glfwPlatformSwapBuffers(_GLFWwindow* window); - -/*! @copydoc glfwSwapInterval - * @ingroup platform - */ -void _glfwPlatformSwapInterval(int interval); - -/*! @copydoc glfwExtensionSupported - * @ingroup platform - */ -int _glfwPlatformExtensionSupported(const char* extension); - -/*! @copydoc glfwGetProcAddress - * @ingroup platform - */ -GLFWglproc _glfwPlatformGetProcAddress(const char* procname); - /*! @copydoc glfwCreateCursor * @ingroup platform */
diff --git a/src/mir_platform.h b/src/mir_platform.h index 5d328c2..66c6776 100644 --- a/src/mir_platform.h +++ b/src/mir_platform.h
@@ -51,12 +51,7 @@ #include "posix_time.h" #include "linux_joystick.h" #include "xkb_unicode.h" - -#if defined(_GLFW_EGL) - #include "egl_context.h" -#else - #error "The Mir backend depends on EGL platform support" -#endif +#include "egl_context.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) @@ -70,6 +65,9 @@ #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorMir mir +#define _GLFW_PLATFORM_CONTEXT_STATE +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE + // Mir-specific Event Queue //
diff --git a/src/mir_window.c b/src/mir_window.c index 8ab4a4f..26ee526 100644 --- a/src/mir_window.c +++ b/src/mir_window.c
@@ -378,7 +378,7 @@ window->mir.window = mir_buffer_stream_get_egl_native_window( mir_surface_get_buffer_stream(window->mir.surface)); - if (ctxconfig->api != GLFW_NO_API) + if (ctxconfig->client != GLFW_NO_API) { if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) return GLFW_FALSE; @@ -395,7 +395,8 @@ window->mir.surface = NULL; } - _glfwDestroyContextEGL(window); + if (window->context.client != GLFW_NO_API) + window->context.destroyContext(window); } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
diff --git a/src/nsgl_context.m b/src/nsgl_context.m index 714d527..1b515cb 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m
@@ -27,6 +27,63 @@ #include "internal.h" +static void makeContextCurrent(_GLFWwindow* window) +{ + if (window) + [window->context.nsgl.object makeCurrentContext]; + else + [NSOpenGLContext clearCurrentContext]; + + _glfwPlatformSetCurrentContext(window); +} + +static void swapBuffers(_GLFWwindow* window) +{ + // ARP appears to be unnecessary, but this is future-proof + [window->context.nsgl.object flushBuffer]; +} + +static void swapInterval(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + GLint sync = interval; + [window->context.nsgl.object setValues:&sync + forParameter:NSOpenGLCPSwapInterval]; +} + +static int extensionSupported(const char* extension) +{ + // There are no NSGL extensions + return GLFW_FALSE; +} + +static GLFWglproc getProcAddress(const char* procname) +{ + CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, + procname, + kCFStringEncodingASCII); + + GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework, + symbolName); + + CFRelease(symbolName); + + return symbol; +} + +// Destroy the OpenGL context +// +static void destroyContext(_GLFWwindow* window) +{ + [window->context.nsgl.pixelFormat release]; + window->context.nsgl.pixelFormat = nil; + + [window->context.nsgl.object release]; + window->context.nsgl.object = nil; +} + + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -61,7 +118,7 @@ { unsigned int attributeCount = 0; - if (ctxconfig->api == GLFW_OPENGL_ES_API) + if (ctxconfig->client == GLFW_OPENGL_ES_API) { _glfwInputError(GLFW_API_UNAVAILABLE, "NSGL: OpenGL ES is not available on OS X"); @@ -216,70 +273,17 @@ } [window->context.nsgl.object setView:window->ns.view]; + + window->context.makeContextCurrent = makeContextCurrent; + window->context.swapBuffers = swapBuffers; + window->context.swapInterval = swapInterval; + window->context.extensionSupported = extensionSupported; + window->context.getProcAddress = getProcAddress; + window->context.destroyContext = destroyContext; + return GLFW_TRUE; } -// Destroy the OpenGL context -// -void _glfwDestroyContextNSGL(_GLFWwindow* window) -{ - [window->context.nsgl.pixelFormat release]; - window->context.nsgl.pixelFormat = nil; - - [window->context.nsgl.object release]; - window->context.nsgl.object = nil; -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) -{ - if (window) - [window->context.nsgl.object makeCurrentContext]; - else - [NSOpenGLContext clearCurrentContext]; - - _glfwPlatformSetCurrentContext(window); -} - -void _glfwPlatformSwapBuffers(_GLFWwindow* window) -{ - // ARP appears to be unnecessary, but this is future-proof - [window->context.nsgl.object flushBuffer]; -} - -void _glfwPlatformSwapInterval(int interval) -{ - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - - GLint sync = interval; - [window->context.nsgl.object setValues:&sync - forParameter:NSOpenGLCPSwapInterval]; -} - -int _glfwPlatformExtensionSupported(const char* extension) -{ - // There are no NSGL extensions - return GLFW_FALSE; -} - -GLFWglproc _glfwPlatformGetProcAddress(const char* procname) -{ - CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, - procname, - kCFStringEncodingASCII); - - GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework, - symbolName); - - CFRelease(symbolName); - - return symbol; -} - ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// @@ -290,7 +294,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(nil); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL;
diff --git a/src/wgl_context.c b/src/wgl_context.c index 608587c..55399cb 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c
@@ -32,55 +32,6 @@ #include <assert.h> -// Initialize WGL-specific extensions -// -static void loadExtensions(void) -{ - // Functions for WGL_EXT_extension_string - // NOTE: These are needed by _glfwPlatformExtensionSupported - _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) - wglGetProcAddress("wglGetExtensionsStringEXT"); - _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) - wglGetProcAddress("wglGetExtensionsStringARB"); - - // Functions for WGL_ARB_create_context - _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) - wglGetProcAddress("wglCreateContextAttribsARB"); - - // Functions for WGL_EXT_swap_control - _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) - wglGetProcAddress("wglSwapIntervalEXT"); - - // Functions for WGL_ARB_pixel_format - _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) - wglGetProcAddress("wglGetPixelFormatAttribivARB"); - - // This needs to include every extension used below except for - // WGL_ARB_extensions_string and WGL_EXT_extensions_string - _glfw.wgl.ARB_multisample = - _glfwPlatformExtensionSupported("WGL_ARB_multisample"); - _glfw.wgl.ARB_framebuffer_sRGB = - _glfwPlatformExtensionSupported("WGL_ARB_framebuffer_sRGB"); - _glfw.wgl.EXT_framebuffer_sRGB = - _glfwPlatformExtensionSupported("WGL_EXT_framebuffer_sRGB"); - _glfw.wgl.ARB_create_context = - _glfwPlatformExtensionSupported("WGL_ARB_create_context"); - _glfw.wgl.ARB_create_context_profile = - _glfwPlatformExtensionSupported("WGL_ARB_create_context_profile"); - _glfw.wgl.EXT_create_context_es2_profile = - _glfwPlatformExtensionSupported("WGL_EXT_create_context_es2_profile"); - _glfw.wgl.ARB_create_context_robustness = - _glfwPlatformExtensionSupported("WGL_ARB_create_context_robustness"); - _glfw.wgl.EXT_swap_control = - _glfwPlatformExtensionSupported("WGL_EXT_swap_control"); - _glfw.wgl.ARB_pixel_format = - _glfwPlatformExtensionSupported("WGL_ARB_pixel_format"); - _glfw.wgl.ARB_context_flush_control = - _glfwPlatformExtensionSupported("WGL_ARB_context_flush_control"); - - _glfw.wgl.extensionsLoaded = GLFW_TRUE; -} - // Returns the specified attribute of the specified pixel format // static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib) @@ -280,6 +231,157 @@ return enabled; } +static void makeContextCurrent(_GLFWwindow* window) +{ + if (window) + { + if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) + _glfwPlatformSetCurrentContext(window); + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to make context current"); + _glfwPlatformSetCurrentContext(NULL); + } + } + else + { + if (!wglMakeCurrent(NULL, NULL)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to clear current context"); + } + + _glfwPlatformSetCurrentContext(NULL); + } +} + +static void swapBuffers(_GLFWwindow* window) +{ + // HACK: Use DwmFlush when desktop composition is enabled + if (isCompositionEnabled() && !window->monitor) + { + int count = abs(window->context.wgl.interval); + while (count--) + _glfw_DwmFlush(); + } + + SwapBuffers(window->context.wgl.dc); +} + +static void swapInterval(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + window->context.wgl.interval = interval; + + // HACK: Disable WGL swap interval when desktop composition is enabled to + // avoid interfering with DWM vsync + if (isCompositionEnabled() && !window->monitor) + interval = 0; + + if (_glfw.wgl.EXT_swap_control) + _glfw.wgl.SwapIntervalEXT(interval); +} + +static int extensionSupported(const char* extension) +{ + const char* extensions; + + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (_glfw.wgl.GetExtensionsStringEXT) + { + extensions = _glfw.wgl.GetExtensionsStringEXT(); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + } + + if (_glfw.wgl.GetExtensionsStringARB) + { + extensions = _glfw.wgl.GetExtensionsStringARB(window->context.wgl.dc); + if (extensions) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GLFW_TRUE; + } + } + + return GLFW_FALSE; +} + +static GLFWglproc getProcAddress(const char* procname) +{ + const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname); + if (proc) + return proc; + + return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname); +} + +// Destroy the OpenGL context +// +static void destroyContext(_GLFWwindow* window) +{ + if (window->context.wgl.handle) + { + wglDeleteContext(window->context.wgl.handle); + window->context.wgl.handle = NULL; + } +} + +// Initialize WGL-specific extensions +// +static void loadExtensions(void) +{ + // Functions for WGL_EXT_extension_string + // NOTE: These are needed by extensionSupported + _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) + wglGetProcAddress("wglGetExtensionsStringEXT"); + _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) + wglGetProcAddress("wglGetExtensionsStringARB"); + + // Functions for WGL_ARB_create_context + _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) + wglGetProcAddress("wglCreateContextAttribsARB"); + + // Functions for WGL_EXT_swap_control + _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) + wglGetProcAddress("wglSwapIntervalEXT"); + + // Functions for WGL_ARB_pixel_format + _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) + wglGetProcAddress("wglGetPixelFormatAttribivARB"); + + // This needs to include every extension used below except for + // WGL_ARB_extensions_string and WGL_EXT_extensions_string + _glfw.wgl.ARB_multisample = + extensionSupported("WGL_ARB_multisample"); + _glfw.wgl.ARB_framebuffer_sRGB = + extensionSupported("WGL_ARB_framebuffer_sRGB"); + _glfw.wgl.EXT_framebuffer_sRGB = + extensionSupported("WGL_EXT_framebuffer_sRGB"); + _glfw.wgl.ARB_create_context = + extensionSupported("WGL_ARB_create_context"); + _glfw.wgl.ARB_create_context_profile = + extensionSupported("WGL_ARB_create_context_profile"); + _glfw.wgl.EXT_create_context_es2_profile = + extensionSupported("WGL_EXT_create_context_es2_profile"); + _glfw.wgl.ARB_create_context_robustness = + extensionSupported("WGL_ARB_create_context_robustness"); + _glfw.wgl.EXT_swap_control = + extensionSupported("WGL_EXT_swap_control"); + _glfw.wgl.ARB_pixel_format = + extensionSupported("WGL_ARB_pixel_format"); + _glfw.wgl.ARB_context_flush_control = + extensionSupported("WGL_ARB_context_flush_control"); + + _glfw.wgl.extensionsLoaded = GLFW_TRUE; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -336,7 +438,7 @@ PIXELFORMATDESCRIPTOR pfd; HGLRC share = NULL; - if (ctxconfig->api == GLFW_NO_API) + if (ctxconfig->client == GLFW_NO_API) return GLFW_TRUE; if (ctxconfig->share) @@ -372,7 +474,7 @@ { int index = 0, mask = 0, flags = 0; - if (ctxconfig->api == GLFW_OPENGL_API) + if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; @@ -474,22 +576,18 @@ } } + window->context.makeContextCurrent = makeContextCurrent; + window->context.swapBuffers = swapBuffers; + window->context.swapInterval = swapInterval; + window->context.extensionSupported = extensionSupported; + window->context.getProcAddress = getProcAddress; + window->context.destroyContext = destroyContext; + return GLFW_TRUE; } #undef setWGLattrib -// Destroy the OpenGL context -// -void _glfwDestroyContextWGL(_GLFWwindow* window) -{ - if (window->context.wgl.handle) - { - wglDeleteContext(window->context.wgl.handle); - window->context.wgl.handle = NULL; - } -} - // Analyzes the specified context for possible recreation // int _glfwAnalyzeContextWGL(_GLFWwindow* window, @@ -501,10 +599,10 @@ if (_glfw.wgl.extensionsLoaded) return _GLFW_RECREATION_NOT_NEEDED; - _glfwPlatformMakeContextCurrent(window); + makeContextCurrent(window); loadExtensions(); - if (ctxconfig->api == GLFW_OPENGL_API) + if (ctxconfig->client == GLFW_OPENGL_API) { if (ctxconfig->forward) { @@ -588,102 +686,6 @@ ////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) -{ - if (window) - { - if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle)) - _glfwPlatformSetCurrentContext(window); - else - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Failed to make context current"); - _glfwPlatformSetCurrentContext(NULL); - } - } - else - { - if (!wglMakeCurrent(NULL, NULL)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Failed to clear current context"); - } - - _glfwPlatformSetCurrentContext(NULL); - } -} - -void _glfwPlatformSwapBuffers(_GLFWwindow* window) -{ - // HACK: Use DwmFlush when desktop composition is enabled - if (isCompositionEnabled() && !window->monitor) - { - int count = abs(window->context.wgl.interval); - while (count--) - _glfw_DwmFlush(); - } - - SwapBuffers(window->context.wgl.dc); -} - -void _glfwPlatformSwapInterval(int interval) -{ - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - - window->context.wgl.interval = interval; - - // HACK: Disable WGL swap interval when desktop composition is enabled to - // avoid interfering with DWM vsync - if (isCompositionEnabled() && !window->monitor) - interval = 0; - - if (_glfw.wgl.EXT_swap_control) - _glfw.wgl.SwapIntervalEXT(interval); -} - -int _glfwPlatformExtensionSupported(const char* extension) -{ - const char* extensions; - - _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - - if (_glfw.wgl.GetExtensionsStringEXT) - { - extensions = _glfw.wgl.GetExtensionsStringEXT(); - if (extensions) - { - if (_glfwStringInExtensionString(extension, extensions)) - return GLFW_TRUE; - } - } - - if (_glfw.wgl.GetExtensionsStringARB) - { - extensions = _glfw.wgl.GetExtensionsStringARB(window->context.wgl.dc); - if (extensions) - { - if (_glfwStringInExtensionString(extension, extensions)) - return GLFW_TRUE; - } - } - - return GLFW_FALSE; -} - -GLFWglproc _glfwPlatformGetProcAddress(const char* procname) -{ - const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname); - if (proc) - return proc; - - return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname); -} - - -////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// @@ -692,7 +694,7 @@ _GLFWwindow* window = (_GLFWwindow*) handle; _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - if (window->context.api == GLFW_NO_API) + if (window->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL;
diff --git a/src/wgl_context.h b/src/wgl_context.h index cca55e0..f1e653c 100644 --- a/src/wgl_context.h +++ b/src/wgl_context.h
@@ -148,7 +148,6 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); -void _glfwDestroyContextWGL(_GLFWwindow* window); int _glfwAnalyzeContextWGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
diff --git a/src/win32_init.c b/src/win32_init.c index 521f045..0bfe34c 100644 --- a/src/win32_init.c +++ b/src/win32_init.c
@@ -421,14 +421,10 @@ _glfwPlatformPollEvents(); -#if defined(_GLFW_WGL) if (!_glfwInitWGL()) return GLFW_FALSE; -#elif defined(_GLFW_EGL) - if (!_glfwInitEGL()) - return GLFW_FALSE; -#endif + _glfwInitEGL(); _glfwInitTimerWin32(); _glfwInitJoysticksWin32(); @@ -449,11 +445,8 @@ free(_glfw.win32.clipboardString); -#if defined(_GLFW_WGL) _glfwTerminateWGL(); -#elif defined(_GLFW_EGL) _glfwTerminateEGL(); -#endif _glfwTerminateJoysticksWin32(); _glfwTerminateThreadLocalStorageWin32(); @@ -463,12 +456,7 @@ const char* _glfwPlatformGetVersionString(void) { - return _GLFW_VERSION_NUMBER " Win32" -#if defined(_GLFW_WGL) - " WGL" -#elif defined(_GLFW_EGL) - " EGL" -#endif + return _GLFW_VERSION_NUMBER " Win32 WGL EGL" #if defined(__MINGW32__) " MinGW" #elif defined(_MSC_VER)
diff --git a/src/win32_platform.h b/src/win32_platform.h index d44ca3b..f3570bc 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h
@@ -205,16 +205,8 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t); #include "win32_joystick.h" - -#if defined(_GLFW_WGL) - #include "wgl_context.h" -#elif defined(_GLFW_EGL) - #define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->win32.handle) - #define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY - #include "egl_context.h" -#else - #error "No supported context creation API selected" -#endif +#include "wgl_context.h" +#include "egl_context.h" #define _GLFW_WNDCLASSNAME L"GLFW30" @@ -222,6 +214,9 @@ #define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle) #define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name) +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->win32.handle) +#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY + #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32 #define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeWin32 win32_time
diff --git a/src/win32_window.c b/src/win32_window.c index 944bff6..b5c03ea 100644 --- a/src/win32_window.c +++ b/src/win32_window.c
@@ -940,55 +940,58 @@ if (!createWindow(window, wndconfig)) return GLFW_FALSE; - if (ctxconfig->api != GLFW_NO_API) + if (ctxconfig->client != GLFW_NO_API) { -#if defined(_GLFW_WGL) - if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) - return GLFW_FALSE; - - status = _glfwAnalyzeContextWGL(window, ctxconfig, fbconfig); - - if (status == _GLFW_RECREATION_IMPOSSIBLE) - return GLFW_FALSE; - - if (status == _GLFW_RECREATION_REQUIRED) + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) { - // Some window hints require us to re-create the context using WGL - // extensions retrieved through the current context, as we cannot - // check for WGL extensions or retrieve WGL entry points before we - // have a current context (actually until we have implicitly loaded - // the vendor ICD) - - // Yes, this is strange, and yes, this is the proper way on WGL - - // As Windows only allows you to set the pixel format once for - // a window, we need to destroy the current window and create a new - // one to be able to use the new pixel format - - // Technically, it may be possible to keep the old window around if - // we're just creating an OpenGL 3.0+ context with the same pixel - // format, but it's not worth the added code complexity - - // First we clear the current context (the one we just created) - // This is usually done by glfwDestroyWindow, but as we're not doing - // full GLFW window destruction, it's duplicated here - _glfwPlatformMakeContextCurrent(NULL); - - // Next destroy the Win32 window and WGL context (without resetting - // or destroying the GLFW window object) - _glfwDestroyContextWGL(window); - destroyWindow(window); - - // ...and then create them again, this time with better APIs - if (!createWindow(window, wndconfig)) - return GLFW_FALSE; if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) return GLFW_FALSE; + + status = _glfwAnalyzeContextWGL(window, ctxconfig, fbconfig); + + if (status == _GLFW_RECREATION_IMPOSSIBLE) + return GLFW_FALSE; + + if (status == _GLFW_RECREATION_REQUIRED) + { + // Some window hints require us to re-create the context using WGL + // extensions retrieved through the current context, as we cannot + // check for WGL extensions or retrieve WGL entry points before we + // have a current context (actually until we have implicitly loaded + // the vendor ICD) + + // Yes, this is strange, and yes, this is the proper way on WGL + + // As Windows only allows you to set the pixel format once for + // a window, we need to destroy the current window and create a new + // one to be able to use the new pixel format + + // Technically, it may be possible to keep the old window around if + // we're just creating an OpenGL 3.0+ context with the same pixel + // format, but it's not worth the added code complexity + + // First we clear the current context (the one we just created) + // This is usually done by glfwDestroyWindow, but as we're not doing + // full GLFW window destruction, it's duplicated here + window->context.makeContextCurrent(NULL); + + // Next destroy the Win32 window and WGL context (without resetting + // or destroying the GLFW window object) + window->context.destroyContext(window); + destroyWindow(window); + + // ...and then create them again, this time with better APIs + if (!createWindow(window, wndconfig)) + return GLFW_FALSE; + if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } } -#elif defined(_GLFW_EGL) - if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) - return GLFW_FALSE; -#endif + else + { + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } } if (window->monitor) @@ -1007,14 +1010,8 @@ if (window->monitor) releaseMonitor(window); - if (window->context.api != GLFW_NO_API) - { -#if defined(_GLFW_WGL) - _glfwDestroyContextWGL(window); -#elif defined(_GLFW_EGL) - _glfwDestroyContextEGL(window); -#endif - } + if (window->context.client != GLFW_NO_API) + window->context.destroyContext(window); destroyWindow(window);
diff --git a/src/window.c b/src/window.c index fee08b2..89b0189 100644 --- a/src/window.c +++ b/src/window.c
@@ -155,7 +155,7 @@ if (ctxconfig.share) { - if (ctxconfig.share->context.api == GLFW_NO_API) + if (ctxconfig.share->context.client == GLFW_NO_API) { _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); return NULL; @@ -192,29 +192,31 @@ // Save the currently current context so it can be restored later previous = _glfwPlatformGetCurrentContext(); + if (ctxconfig.client != GLFW_NO_API) + glfwMakeContextCurrent(NULL); // Open the actual window and create its context if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) { + glfwMakeContextCurrent((GLFWwindow*) previous); glfwDestroyWindow((GLFWwindow*) window); - _glfwPlatformMakeContextCurrent(previous); return NULL; } - if (ctxconfig.api != GLFW_NO_API) + if (ctxconfig.client != GLFW_NO_API) { - _glfwPlatformMakeContextCurrent(window); + window->context.makeContextCurrent(window); // Retrieve the actual (as opposed to requested) context attributes if (!_glfwRefreshContextAttribs(&ctxconfig)) { + glfwMakeContextCurrent((GLFWwindow*) previous); glfwDestroyWindow((GLFWwindow*) window); - _glfwPlatformMakeContextCurrent(previous); return NULL; } // Restore the previously current context (or NULL) - _glfwPlatformMakeContextCurrent(previous); + glfwMakeContextCurrent((GLFWwindow*) previous); } if (window->monitor) @@ -247,9 +249,10 @@ memset(&_glfw.hints, 0, sizeof(_glfw.hints)); // The default is OpenGL with minimum version 1.0 - _glfw.hints.context.api = GLFW_OPENGL_API; - _glfw.hints.context.major = 1; - _glfw.hints.context.minor = 0; + _glfw.hints.context.client = GLFW_OPENGL_API; + _glfw.hints.context.source = GLFW_NATIVE_CONTEXT_API; + _glfw.hints.context.major = 1; + _glfw.hints.context.minor = 0; // The default is a focused, visible, resizable window with decorations _glfw.hints.window.resizable = GLFW_TRUE; @@ -345,7 +348,10 @@ _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; break; case GLFW_CLIENT_API: - _glfw.hints.context.api = value; + _glfw.hints.context.client = value; + break; + case GLFW_CONTEXT_CREATION_API: + _glfw.hints.context.source = value; break; case GLFW_CONTEXT_VERSION_MAJOR: _glfw.hints.context.major = value; @@ -396,7 +402,7 @@ // The window's context must not be current on another thread when the // window is destroyed if (window == _glfwPlatformGetCurrentContext()) - _glfwPlatformMakeContextCurrent(NULL); + glfwMakeContextCurrent(NULL); // Clear the focused window pointer if this is the focused window if (_glfw.cursorWindow == window) @@ -683,7 +689,9 @@ case GLFW_FLOATING: return window->floating; case GLFW_CLIENT_API: - return window->context.api; + return window->context.client; + case GLFW_CONTEXT_CREATION_API: + return window->context.source; case GLFW_CONTEXT_VERSION_MAJOR: return window->context.major; case GLFW_CONTEXT_VERSION_MINOR:
diff --git a/src/wl_platform.h b/src/wl_platform.h index d75c025..221108e 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h
@@ -49,12 +49,7 @@ #include "posix_time.h" #include "linux_joystick.h" #include "xkb_unicode.h" - -#if defined(_GLFW_EGL) - #include "egl_context.h" -#else - #error "The Wayland backend depends on EGL platform support" -#endif +#include "egl_context.h" #include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h" @@ -71,6 +66,9 @@ #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWayland wl +#define _GLFW_PLATFORM_CONTEXT_STATE +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE + // Wayland-specific video mode data //
diff --git a/src/wl_window.c b/src/wl_window.c index 194c0ec..5ff9990 100644 --- a/src/wl_window.c +++ b/src/wl_window.c
@@ -373,7 +373,7 @@ if (!createSurface(window, wndconfig)) return GLFW_FALSE; - if (ctxconfig->api != GLFW_NO_API) + if (ctxconfig->client != GLFW_NO_API) { if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) return GLFW_FALSE; @@ -417,7 +417,8 @@ _glfwInputWindowFocus(window, GLFW_FALSE); } - _glfwDestroyContextEGL(window); + if (window->context.client != GLFW_NO_API) + window->context.destroyContext(window); if (window->wl.native) wl_egl_window_destroy(window->wl.native);
diff --git a/src/x11_init.c b/src/x11_init.c index b81afcc..112e454 100644 --- a/src/x11_init.c +++ b/src/x11_init.c
@@ -766,17 +766,13 @@ if (!_glfwInitThreadLocalStoragePOSIX()) return GLFW_FALSE; -#if defined(_GLFW_GLX) if (!_glfwInitGLX()) return GLFW_FALSE; -#elif defined(_GLFW_EGL) - if (!_glfwInitEGL()) - return GLFW_FALSE; -#endif if (!_glfwInitJoysticksLinux()) return GLFW_FALSE; + _glfwInitEGL(); _glfwInitTimerPOSIX(); return GLFW_TRUE; @@ -804,9 +800,7 @@ _glfw.x11.im = NULL; } -#if defined(_GLFW_EGL) _glfwTerminateEGL(); -#endif if (_glfw.x11.display) { @@ -816,9 +810,7 @@ // NOTE: This needs to be done after XCloseDisplay, as libGL registers // cleanup callbacks that get called by it -#if defined(_GLFW_GLX) _glfwTerminateGLX(); -#endif _glfwTerminateJoysticksLinux(); _glfwTerminateThreadLocalStoragePOSIX(); @@ -826,12 +818,7 @@ const char* _glfwPlatformGetVersionString(void) { - return _GLFW_VERSION_NUMBER " X11" -#if defined(_GLFW_GLX) - " GLX" -#elif defined(_GLFW_EGL) - " EGL" -#endif + return _GLFW_VERSION_NUMBER " X11 GLX EGL" #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) " clock_gettime" #else
diff --git a/src/x11_platform.h b/src/x11_platform.h index a12374a..9c76d18 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h
@@ -87,21 +87,16 @@ #include "posix_time.h" #include "linux_joystick.h" #include "xkb_unicode.h" - -#if defined(_GLFW_GLX) - #include "glx_context.h" -#elif defined(_GLFW_EGL) - #define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle) - #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display) - #include "egl_context.h" -#else - #error "No supported context creation API selected" -#endif +#include "glx_context.h" +#include "egl_context.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle) +#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display) + #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
diff --git a/src/x11_window.c b/src/x11_window.c index 7cf26ce..19b9d24 100644 --- a/src/x11_window.c +++ b/src/x11_window.c
@@ -1478,34 +1478,40 @@ Visual* visual; int depth; - if (ctxconfig->api == GLFW_NO_API) + if (ctxconfig->client == GLFW_NO_API) { visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen); depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen); } else { -#if defined(_GLFW_GLX) - if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth)) - return GLFW_FALSE; -#elif defined(_GLFW_EGL) - if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth)) - return GLFW_FALSE; -#endif + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; + } + else + { + if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; + } } if (!createWindow(window, wndconfig, visual, depth)) return GLFW_FALSE; - if (ctxconfig->api != GLFW_NO_API) + if (ctxconfig->client != GLFW_NO_API) { -#if defined(_GLFW_GLX) - if (!_glfwCreateContextGLX(window, ctxconfig, fbconfig)) - return GLFW_FALSE; -#elif defined(_GLFW_EGL) - if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) - return GLFW_FALSE; -#endif + if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) + { + if (!_glfwCreateContextGLX(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } + else + { + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + } } if (window->monitor) @@ -1530,14 +1536,8 @@ window->x11.ic = NULL; } - if (window->context.api != GLFW_NO_API) - { -#if defined(_GLFW_GLX) - _glfwDestroyContextGLX(window); -#elif defined(_GLFW_EGL) - _glfwDestroyContextEGL(window); -#endif - } + if (window->context.client != GLFW_NO_API) + window->context.destroyContext(window); if (window->x11.handle) {
diff --git a/tests/glfwinfo.c b/tests/glfwinfo.c index 01d8ac0..e85b385 100644 --- a/tests/glfwinfo.c +++ b/tests/glfwinfo.c
@@ -41,6 +41,9 @@ #define API_NAME_OPENGL "gl" #define API_NAME_OPENGL_ES "es" +#define API_NAME_NATIVE "native" +#define API_NAME_EGL "egl" + #define PROFILE_NAME_CORE "core" #define PROFILE_NAME_COMPAT "compat" @@ -60,6 +63,9 @@ printf(" -b, --behavior=BEHAVIOR the release behavior to use (" BEHAVIOR_NAME_NONE " or " BEHAVIOR_NAME_FLUSH ")\n"); + printf(" -c, --context-api=API the context creation API to use (" + API_NAME_NATIVE " or " + API_NAME_EGL ")\n"); printf(" -d, --debug request a debug context\n"); printf(" -f, --forward require a forward-compatible context\n"); printf(" -h, --help show this help\n"); @@ -165,15 +171,15 @@ return "unknown"; } -static void list_context_extensions(int api, int major, int minor) +static void list_context_extensions(int client, int major, int minor) { int i; GLint count; const GLubyte* extensions; - printf("%s context extensions:\n", get_api_name(api)); + printf("%s context extensions:\n", get_api_name(client)); - if (api == GLFW_OPENGL_API && major > 2) + if (client == GLFW_OPENGL_API && major > 2) { glGetIntegerv(GL_NUM_EXTENSIONS, &count); @@ -351,13 +357,13 @@ int main(int argc, char** argv) { - int ch, api, major, minor, revision, profile; + int ch, client, context, major, minor, revision, profile; GLint redbits, greenbits, bluebits, alphabits, depthbits, stencilbits; int list_extensions = GLFW_FALSE, list_layers = GLFW_FALSE; GLenum error; GLFWwindow* window; - enum { API, BEHAVIOR, DEBUG, FORWARD, HELP, EXTENSIONS, LAYERS, + enum { CLIENT, CONTEXT, BEHAVIOR, DEBUG, FORWARD, HELP, EXTENSIONS, LAYERS, MAJOR, MINOR, PROFILE, ROBUSTNESS, VERSION, REDBITS, GREENBITS, BLUEBITS, ALPHABITS, DEPTHBITS, STENCILBITS, ACCUMREDBITS, ACCUMGREENBITS, ACCUMBLUEBITS, ACCUMALPHABITS, @@ -365,7 +371,8 @@ const struct option options[] = { { "behavior", 1, NULL, BEHAVIOR }, - { "client-api", 1, NULL, API }, + { "client-api", 1, NULL, CLIENT }, + { "context-api", 1, NULL, CONTEXT }, { "debug", 0, NULL, DEBUG }, { "forward", 0, NULL, FORWARD }, { "help", 0, NULL, HELP }, @@ -410,7 +417,7 @@ switch (ch) { case 'a': - case API: + case CLIENT: if (strcasecmp(optarg, API_NAME_OPENGL) == 0) glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); else if (strcasecmp(optarg, API_NAME_OPENGL_ES) == 0) @@ -439,6 +446,18 @@ exit(EXIT_FAILURE); } break; + case 'c': + case CONTEXT: + if (strcasecmp(optarg, API_NAME_NATIVE) == 0) + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API); + else if (strcasecmp(optarg, API_NAME_EGL) == 0) + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); + else + { + usage(); + exit(EXIT_FAILURE); + } + break; case 'd': case DEBUG: glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); @@ -616,30 +635,31 @@ // Report client API version - api = glfwGetWindowAttrib(window, GLFW_CLIENT_API); + client = glfwGetWindowAttrib(window, GLFW_CLIENT_API); + context = glfwGetWindowAttrib(window, GLFW_CONTEXT_CREATION_API); major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR); minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR); revision = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION); profile = glfwGetWindowAttrib(window, GLFW_OPENGL_PROFILE); printf("%s context version string: \"%s\"\n", - get_api_name(api), + get_api_name(client), glGetString(GL_VERSION)); printf("%s context version parsed by GLFW: %u.%u.%u\n", - get_api_name(api), + get_api_name(client), major, minor, revision); // Report client API context properties - if (api == GLFW_OPENGL_API) + if (client == GLFW_OPENGL_API) { if (major >= 3) { GLint flags; glGetIntegerv(GL_CONTEXT_FLAGS, &flags); - printf("%s context flags (0x%08x):", get_api_name(api), flags); + printf("%s context flags (0x%08x):", get_api_name(client), flags); if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) printf(" forward-compatible"); @@ -651,7 +671,7 @@ printf(" no-error"); putchar('\n'); - printf("%s context flags parsed by GLFW:", get_api_name(api)); + printf("%s context flags parsed by GLFW:", get_api_name(client)); if (glfwGetWindowAttrib(window, GLFW_OPENGL_FORWARD_COMPAT)) printf(" forward-compatible"); @@ -670,12 +690,12 @@ glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); printf("%s profile mask (0x%08x): %s\n", - get_api_name(api), + get_api_name(client), mask, get_profile_name_gl(mask)); printf("%s profile mask parsed by GLFW: %s\n", - get_api_name(api), + get_api_name(client), get_profile_name_glfw(profile)); } @@ -686,33 +706,33 @@ glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy); printf("%s robustness strategy (0x%08x): %s\n", - get_api_name(api), + get_api_name(client), strategy, get_strategy_name_gl(strategy)); printf("%s robustness strategy parsed by GLFW: %s\n", - get_api_name(api), + get_api_name(client), get_strategy_name_glfw(robustness)); } } printf("%s context renderer string: \"%s\"\n", - get_api_name(api), + get_api_name(client), glGetString(GL_RENDERER)); printf("%s context vendor string: \"%s\"\n", - get_api_name(api), + get_api_name(client), glGetString(GL_VENDOR)); if (major >= 2) { printf("%s context shading language version: \"%s\"\n", - get_api_name(api), + get_api_name(client), glGetString(GL_SHADING_LANGUAGE_VERSION)); } - printf("%s framebuffer:\n", get_api_name(api)); + printf("%s framebuffer:\n", get_api_name(client)); - if (api == GLFW_OPENGL_API && profile == GLFW_OPENGL_CORE_PROFILE) + if (client == GLFW_OPENGL_API && profile == GLFW_OPENGL_CORE_PROFILE) { glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_BACK_LEFT, @@ -752,7 +772,7 @@ printf(" red: %u green: %u blue: %u alpha: %u depth: %u stencil: %u\n", redbits, greenbits, bluebits, alphabits, depthbits, stencilbits); - if (api == GLFW_OPENGL_ES_API || + if (client == GLFW_OPENGL_ES_API || glfwExtensionSupported("GL_ARB_multisample") || major > 1 || minor >= 3) { @@ -763,7 +783,7 @@ printf(" samples: %u sample buffers: %u\n", samples, samplebuffers); } - if (api == GLFW_OPENGL_API && profile != GLFW_OPENGL_CORE_PROFILE) + if (client == GLFW_OPENGL_API && profile != GLFW_OPENGL_CORE_PROFILE) { GLint accumredbits, accumgreenbits, accumbluebits, accumalphabits; GLint auxbuffers; @@ -779,7 +799,7 @@ } if (list_extensions) - list_context_extensions(api, major, minor); + list_context_extensions(client, major, minor); printf("Vulkan loader: %s\n", glfwVulkanSupported() ? "available" : "missing");