diff --git a/README.md b/README.md index 5e20a3d6..d21b18f6 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,8 @@ information on what to include when reporting a bug. - Added `GLFW_POINTING_HAND_CURSOR` alias for `GLFW_HAND_CURSOR` (#427) - Added `GLFW_FEATURE_UNAVAILABLE` error for platform limitations (#1692) - Added `GLFW_FEATURE_UNIMPLEMENTED` error for incomplete backends (#1692) + - Added `GLFW_ANGLE_PLATFORM_TYPE` init hint and `GLFW_ANGLE_PLATFORM_TYPE_*` + values to select ANGLE backend (#1380) - Updated the minimum required CMake version to 3.1 - Disabled tests and examples by default when built as a CMake subdirectory - Bugfix: The CMake config-file package used an absolute path and was not @@ -195,6 +197,8 @@ information on what to include when reporting a bug. macOS versions (#1442) - [NSGL] Bugfix: Workaround for swap interval on 10.14 broke on 10.12 (#1483) - [EGL] Added platform selection via the `EGL_EXT_platform_base` extension + - [EGL] Added ANGLE backend selection via `EGL_ANGLE_platform_angle` extension + (#1380) ## Contact diff --git a/docs/intro.dox b/docs/intro.dox index 36e33525..abbe9d11 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -93,6 +93,18 @@ __GLFW_JOYSTICK_HAT_BUTTONS__ specifies whether to also expose joystick hats as buttons, for compatibility with earlier versions of GLFW that did not have @ref glfwGetJoystickHats. Set this with @ref glfwInitHint. +@anchor GLFW_ANGLE_PLATFORM_TYPE_hint +__GLFW_ANGLE_PLATFORM_TYPE__ specifies the platform type (rendering backend) to +request when using OpenGL ES and EGL via +[ANGLE](https://chromium.googlesource.com/angle/angle/). If the requested +platform type is unavailable, ANGLE will use its default. Set this hint with +@ref glfwInitHint. + +@par +The ANGLE platform type is specified via the `EGL_ANGLE_platform_angle` +extension. This extension is not used if this hint is +`GLFW_ANGLE_PLATFORM_TYPE_NONE`, which is the default value. + @subsubsection init_hints_osx macOS specific init hints @@ -109,11 +121,12 @@ a nib or manually by GLFW. Set this with @ref glfwInitHint. @subsubsection init_hints_values Supported and default values -Initialization hint | Default value | Supported values -------------------------------- | ------------- | ---------------- -@ref GLFW_JOYSTICK_HAT_BUTTONS | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` -@ref GLFW_COCOA_CHDIR_RESOURCES | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` -@ref GLFW_COCOA_MENUBAR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` +Initialization hint | Default value | Supported values +------------------------------- | ------------------------------- | ---------------- +@ref GLFW_JOYSTICK_HAT_BUTTONS | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` +@ref GLFW_ANGLE_PLATFORM_TYPE | `GLFW_ANGLE_PLATFORM_TYPE_NONE` | `GLFW_ANGLE_PLATFORM_TYPE_NONE`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGL`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGLES`, `GLFW_ANGLE_PLATFORM_TYPE_D3D9`, `GLFW_ANGLE_PLATFORM_TYPE_D3D11`, `GLFW_ANGLE_PLATFORM_TYPE_VULKAN` or `GLFW_ANGLE_PLATFORM_TYPE_METAL` +@ref GLFW_COCOA_CHDIR_RESOURCES | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` +@ref GLFW_COCOA_MENUBAR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` @subsection intro_init_terminate Terminating GLFW diff --git a/docs/news.dox b/docs/news.dox index 00fc63fd..fccd4166 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -27,6 +27,15 @@ are still available. For more information see @ref cursor_standard. +@subsubsection features_34_angle_backend Support for ANGLE rendering backend selection + +GLFW now provides the +[GLFW_ANGLE_PLATFORM_TYPE](@ref GLFW_ANGLE_PLATFORM_TYPE_hint) init hint for +requesting a specific rendering backend when using +[ANGLE](https://chromium.googlesource.com/angle/angle/) to create OpenGL ES +contexts. + + @subsubsection features_34_win32_keymenu Support for keyboard access to Windows window menu GLFW now provides the @@ -94,6 +103,14 @@ then GLFW will fail to initialize. - @ref GLFW_CONTEXT_DEBUG - @ref GLFW_FEATURE_UNAVAILABLE - @ref GLFW_FEATURE_UNIMPLEMENTED + - @ref GLFW_ANGLE_PLATFORM_TYPE + - @ref GLFW_ANGLE_PLATFORM_TYPE_NONE + - @ref GLFW_ANGLE_PLATFORM_TYPE_OPENGL + - @ref GLFW_ANGLE_PLATFORM_TYPE_OPENGLES + - @ref GLFW_ANGLE_PLATFORM_TYPE_D3D9 + - @ref GLFW_ANGLE_PLATFORM_TYPE_D3D11 + - @ref GLFW_ANGLE_PLATFORM_TYPE_VULKAN + - @ref GLFW_ANGLE_PLATFORM_TYPE_METAL @section news_archive Release notes for earlier versions diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index c5785bfe..d489f2a0 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1104,6 +1104,14 @@ extern "C" { #define GLFW_EGL_CONTEXT_API 0x00036002 #define GLFW_OSMESA_CONTEXT_API 0x00036003 +#define GLFW_ANGLE_PLATFORM_TYPE_NONE 0x00037001 +#define GLFW_ANGLE_PLATFORM_TYPE_OPENGL 0x00037002 +#define GLFW_ANGLE_PLATFORM_TYPE_OPENGLES 0x00037003 +#define GLFW_ANGLE_PLATFORM_TYPE_D3D9 0x00037004 +#define GLFW_ANGLE_PLATFORM_TYPE_D3D11 0x00037005 +#define GLFW_ANGLE_PLATFORM_TYPE_VULKAN 0x00037007 +#define GLFW_ANGLE_PLATFORM_TYPE_METAL 0x00037008 + /*! @defgroup shapes Standard cursor shapes * @brief Standard system cursor shapes. * @@ -1220,6 +1228,11 @@ extern "C" { * Joystick hat buttons [init hint](@ref GLFW_JOYSTICK_HAT_BUTTONS). */ #define GLFW_JOYSTICK_HAT_BUTTONS 0x00050001 +/*! @brief ANGLE rendering backend init hint. + * + * ANGLE rendering backend [init hint](@ref GLFW_ANGLE_PLATFORM_TYPE_hint). + */ +#define GLFW_ANGLE_PLATFORM_TYPE 0x00050002 /*! @brief macOS specific init hint. * * macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES_hint). diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 5ddb34c1..ddce3615 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1721,8 +1721,34 @@ const char* _glfwPlatformGetClipboardString(void) } // autoreleasepool } -EGLenum _glfwPlatformGetEGLPlatform(void) +EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs) { + if (_glfw.egl.ANGLE_platform_angle) + { + int type = 0; + + if (_glfw.egl.ANGLE_platform_angle_opengl) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL) + type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE; + } + + if (_glfw.egl.ANGLE_platform_angle_metal) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_METAL) + type = EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE; + } + + if (type) + { + *attribs = calloc(3, sizeof(EGLint)); + (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE; + (*attribs)[1] = type; + (*attribs)[2] = EGL_NONE; + return EGL_PLATFORM_ANGLE_ANGLE; + } + } + return 0; } diff --git a/src/egl_context.c b/src/egl_context.c index b9736fd1..533ed8e7 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -303,6 +303,7 @@ static void destroyContextEGL(_GLFWwindow* window) GLFWbool _glfwInitEGL(void) { int i; + EGLint* attribs = NULL; const char* extensions; const char* sonames[] = { @@ -408,6 +409,16 @@ GLFWbool _glfwInitEGL(void) _glfwStringInExtensionString("EGL_EXT_platform_x11", extensions); _glfw.egl.EXT_platform_wayland = _glfwStringInExtensionString("EGL_EXT_platform_wayland", extensions); + _glfw.egl.ANGLE_platform_angle = + _glfwStringInExtensionString("EGL_ANGLE_platform_angle", extensions); + _glfw.egl.ANGLE_platform_angle_opengl = + _glfwStringInExtensionString("EGL_ANGLE_platform_angle_opengl", extensions); + _glfw.egl.ANGLE_platform_angle_d3d = + _glfwStringInExtensionString("EGL_ANGLE_platform_angle_d3d", extensions); + _glfw.egl.ANGLE_platform_angle_vulkan = + _glfwStringInExtensionString("EGL_ANGLE_platform_angle_vulkan", extensions); + _glfw.egl.ANGLE_platform_angle_metal = + _glfwStringInExtensionString("EGL_ANGLE_platform_angle_metal", extensions); } if (_glfw.egl.EXT_platform_base) @@ -418,17 +429,19 @@ GLFWbool _glfwInitEGL(void) eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT"); } - _glfw.egl.platform = _glfwPlatformGetEGLPlatform(); + _glfw.egl.platform = _glfwPlatformGetEGLPlatform(&attribs); if (_glfw.egl.platform) { _glfw.egl.display = eglGetPlatformDisplayEXT(_glfw.egl.platform, _glfwPlatformGetEGLNativeDisplay(), - NULL); + attribs); } else _glfw.egl.display = eglGetDisplay(_glfwPlatformGetEGLNativeDisplay()); + free(attribs); + if (_glfw.egl.display == EGL_NO_DISPLAY) { _glfwInputError(GLFW_API_UNAVAILABLE, @@ -633,7 +646,9 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, setAttrib(EGL_NONE, EGL_NONE); native = _glfwPlatformGetEGLNativeWindow(window); - if (_glfw.egl.platform) + // HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT + // despite reporting EGL_EXT_platform_base + if (_glfw.egl.platform && _glfw.egl.platform != EGL_PLATFORM_ANGLE_ANGLE) { window->context.egl.surface = eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, config, native, attribs); diff --git a/src/egl_context.h b/src/egl_context.h index 6b0f8948..9de424c9 100644 --- a/src/egl_context.h +++ b/src/egl_context.h @@ -92,6 +92,15 @@ #define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 #define EGL_PLATFORM_X11_EXT 0x31d5 #define EGL_PLATFORM_WAYLAND_EXT 0x31d8 +#define EGL_PLATFORM_ANGLE_ANGLE 0x3202 +#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 +#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320d +#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320e +#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207 +#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 +#define EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE 0x3450 +#define EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE 0x3489 +#define EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE 0x348f typedef int EGLint; typedef unsigned int EGLBoolean; @@ -173,6 +182,11 @@ typedef struct _GLFWlibraryEGL GLFWbool EXT_platform_base; GLFWbool EXT_platform_x11; GLFWbool EXT_platform_wayland; + GLFWbool ANGLE_platform_angle; + GLFWbool ANGLE_platform_angle_opengl; + GLFWbool ANGLE_platform_angle_d3d; + GLFWbool ANGLE_platform_angle_vulkan; + GLFWbool ANGLE_platform_angle_metal; void* handle; diff --git a/src/init.c b/src/init.c index d23bbfa9..f9ce336a 100644 --- a/src/init.c +++ b/src/init.c @@ -53,6 +53,7 @@ static GLFWerrorfun _glfwErrorCallback; static _GLFWinitconfig _glfwInitHints = { GLFW_TRUE, // hat buttons + GLFW_ANGLE_PLATFORM_TYPE_NONE, // ANGLE backend { GLFW_TRUE, // macOS menu bar GLFW_TRUE // macOS bundle chdir @@ -287,6 +288,9 @@ GLFWAPI void glfwInitHint(int hint, int value) case GLFW_JOYSTICK_HAT_BUTTONS: _glfwInitHints.hatButtons = value; return; + case GLFW_ANGLE_PLATFORM_TYPE: + _glfwInitHints.angleType = value; + return; case GLFW_COCOA_CHDIR_RESOURCES: _glfwInitHints.ns.chdir = value; return; diff --git a/src/internal.h b/src/internal.h index ed19217e..73d2d823 100644 --- a/src/internal.h +++ b/src/internal.h @@ -243,6 +243,7 @@ struct _GLFWerror struct _GLFWinitconfig { GLFWbool hatButtons; + int angleType; struct { GLFWbool menubar; GLFWbool chdir; @@ -684,7 +685,7 @@ void _glfwPlatformWaitEvents(void); void _glfwPlatformWaitEventsTimeout(double timeout); void _glfwPlatformPostEmptyEvent(void); -EGLenum _glfwPlatformGetEGLPlatform(void); +EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs); EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void); EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window); diff --git a/src/win32_window.c b/src/win32_window.c index af2b9c92..d9c30c55 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -2186,8 +2186,44 @@ const char* _glfwPlatformGetClipboardString(void) return _glfw.win32.clipboardString; } -EGLenum _glfwPlatformGetEGLPlatform(void) +EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs) { + if (_glfw.egl.ANGLE_platform_angle) + { + int type = 0; + + if (_glfw.egl.ANGLE_platform_angle_opengl) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL) + type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE; + else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGLES) + type = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE; + } + + if (_glfw.egl.ANGLE_platform_angle_d3d) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_D3D9) + type = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE; + else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_D3D11) + type = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE; + } + + if (_glfw.egl.ANGLE_platform_angle_vulkan) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_VULKAN) + type = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE; + } + + if (type) + { + *attribs = calloc(3, sizeof(EGLint)); + (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE; + (*attribs)[1] = type; + (*attribs)[2] = EGL_NONE; + return EGL_PLATFORM_ANGLE_ANGLE; + } + } + return 0; } diff --git a/src/wl_window.c b/src/wl_window.c index 56db1f8e..d1dad065 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1684,7 +1684,7 @@ const char* _glfwPlatformGetClipboardString(void) return _glfw.wl.clipboardString; } -EGLenum _glfwPlatformGetEGLPlatform(void) +EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs) { if (_glfw.egl.EXT_platform_base && _glfw.egl.EXT_platform_wayland) return EGL_PLATFORM_WAYLAND_EXT; diff --git a/src/x11_window.c b/src/x11_window.c index 494493fe..d56fe3da 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -3048,12 +3048,40 @@ const char* _glfwPlatformGetClipboardString(void) return getSelectionString(_glfw.x11.CLIPBOARD); } -EGLenum _glfwPlatformGetEGLPlatform(void) +EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs) { + if (_glfw.egl.ANGLE_platform_angle) + { + int type = 0; + + if (_glfw.egl.ANGLE_platform_angle_opengl) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL) + type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE; + } + + if (_glfw.egl.ANGLE_platform_angle_vulkan) + { + if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_VULKAN) + type = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE; + } + + if (type) + { + *attribs = calloc(5, sizeof(EGLint)); + (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE; + (*attribs)[1] = type; + (*attribs)[2] = EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE; + (*attribs)[3] = EGL_PLATFORM_X11_EXT; + (*attribs)[4] = EGL_NONE; + return EGL_PLATFORM_ANGLE_ANGLE; + } + } + if (_glfw.egl.EXT_platform_base && _glfw.egl.EXT_platform_x11) return EGL_PLATFORM_X11_EXT; - else - return 0; + + return 0; } EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void) diff --git a/tests/glfwinfo.c b/tests/glfwinfo.c index 18ffac1b..9789f98a 100644 --- a/tests/glfwinfo.c +++ b/tests/glfwinfo.c @@ -55,6 +55,13 @@ #define BEHAVIOR_NAME_NONE "none" #define BEHAVIOR_NAME_FLUSH "flush" +#define ANGLE_TYPE_OPENGL "gl" +#define ANGLE_TYPE_OPENGLES "es" +#define ANGLE_TYPE_D3D9 "d3d9" +#define ANGLE_TYPE_D3D11 "d3d11" +#define ANGLE_TYPE_VULKAN "vk" +#define ANGLE_TYPE_METAL "mtl" + static void usage(void) { printf("Usage: glfwinfo [OPTION]...\n"); @@ -101,6 +108,13 @@ static void usage(void) printf(" --srgb request an sRGB capable framebuffer\n"); printf(" --singlebuffer request single-buffering\n"); printf(" --no-error request a context that does not emit errors\n"); + printf(" --angle-type=TYPE the ANGLE platform type to use (" + ANGLE_TYPE_OPENGL ", " + ANGLE_TYPE_OPENGLES ", " + ANGLE_TYPE_D3D9 ", " + ANGLE_TYPE_D3D11 ", " + ANGLE_TYPE_VULKAN " or " + ANGLE_TYPE_METAL ")\n"); printf(" --graphics-switching request macOS graphics switching\n"); } @@ -344,6 +358,7 @@ int main(int argc, char** argv) bool fb_stereo = false; bool fb_srgb = false; bool fb_doublebuffer = true; + int angle_type = GLFW_ANGLE_PLATFORM_TYPE_NONE; bool cocoa_graphics_switching = false; enum { CLIENT, CONTEXT, BEHAVIOR, DEBUG_CONTEXT, FORWARD, HELP, @@ -352,7 +367,7 @@ int main(int argc, char** argv) REDBITS, GREENBITS, BLUEBITS, ALPHABITS, DEPTHBITS, STENCILBITS, ACCUMREDBITS, ACCUMGREENBITS, ACCUMBLUEBITS, ACCUMALPHABITS, AUXBUFFERS, SAMPLES, STEREO, SRGB, SINGLEBUFFER, NOERROR_SRSLY, - GRAPHICS_SWITCHING }; + ANGLE_TYPE, GRAPHICS_SWITCHING }; const struct option options[] = { { "behavior", 1, NULL, BEHAVIOR }, @@ -384,6 +399,7 @@ int main(int argc, char** argv) { "srgb", 0, NULL, SRGB }, { "singlebuffer", 0, NULL, SINGLEBUFFER }, { "no-error", 0, NULL, NOERROR_SRSLY }, + { "angle-type", 1, NULL, ANGLE_TYPE }, { "graphics-switching", 0, NULL, GRAPHICS_SWITCHING }, { NULL, 0, NULL, 0 } }; @@ -569,6 +585,25 @@ int main(int argc, char** argv) case NOERROR_SRSLY: context_no_error = true; break; + case ANGLE_TYPE: + if (strcmp(optarg, ANGLE_TYPE_OPENGL) == 0) + angle_type = GLFW_ANGLE_PLATFORM_TYPE_OPENGL; + else if (strcmp(optarg, ANGLE_TYPE_OPENGLES) == 0) + angle_type = GLFW_ANGLE_PLATFORM_TYPE_OPENGLES; + else if (strcmp(optarg, ANGLE_TYPE_D3D9) == 0) + angle_type = GLFW_ANGLE_PLATFORM_TYPE_D3D9; + else if (strcmp(optarg, ANGLE_TYPE_D3D11) == 0) + angle_type = GLFW_ANGLE_PLATFORM_TYPE_D3D11; + else if (strcmp(optarg, ANGLE_TYPE_VULKAN) == 0) + angle_type = GLFW_ANGLE_PLATFORM_TYPE_VULKAN; + else if (strcmp(optarg, ANGLE_TYPE_METAL) == 0) + angle_type = GLFW_ANGLE_PLATFORM_TYPE_METAL; + else + { + usage(); + exit(EXIT_FAILURE); + } + break; case GRAPHICS_SWITCHING: cocoa_graphics_switching = true; break; @@ -587,6 +622,8 @@ int main(int argc, char** argv) glfwInitHint(GLFW_COCOA_MENUBAR, false); + glfwInitHint(GLFW_ANGLE_PLATFORM_TYPE, angle_type); + if (!glfwInit()) exit(EXIT_FAILURE);