diff --git a/README.md b/README.md index 10044faf..c74f7c39 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,8 @@ information on what to include when reporting a bug. - [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless` - [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to `GLFW_NATIVE_CONTEXT_API` (#2518) + - Added `GLFW_CONTEXT_RENDERER` window hint and `GLFW_HARDWARE_RENDERER` and + `GLFW_SOFTWARE_RENDERER` hint values (#589) ## Contact diff --git a/docs/window.md b/docs/window.md index 371baa56..a79bcb18 100644 --- a/docs/window.md +++ b/docs/window.md @@ -375,6 +375,11 @@ does not update the window contents when its buffers are swapped. Use OpenGL functions or the OSMesa native access functions @ref glfwGetOSMesaColorBuffer and @ref glfwGetOSMesaDepthBuffer to retrieve the framebuffer contents. +@anchor GLFW_CONTEXT_RENDERER_hint +__GLFW_CONTEXT_RENDERER__ specifies whether to create the context using +a hardware or software renderer, if that is possible to control on the current +platform. + @anchor GLFW_CONTEXT_VERSION_MAJOR_hint @anchor GLFW_CONTEXT_VERSION_MINOR_hint __GLFW_CONTEXT_VERSION_MAJOR__ and __GLFW_CONTEXT_VERSION_MINOR__ specify the @@ -566,6 +571,7 @@ GLFW_SRGB_CAPABLE | `GLFW_FALSE` | `GLFW_TRUE` or `GL 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`, `GLFW_EGL_CONTEXT_API` or `GLFW_OSMESA_CONTEXT_API` +GLFW_CONTEXT_RENDERER | `GLFW_HARDWARE_RENDERER` | `GLFW_HARDWARE_RENDERER` or `GLFW_SOFTWARE_RENDERER` 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` diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 79b06288..ffa82225 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1108,6 +1108,8 @@ extern "C" { * [GLFW_SCALE_FRAMEBUFFER](@ref GLFW_SCALE_FRAMEBUFFER_hint) window hint for * compatibility with earlier versions. */ +#define GLFW_CONTEXT_RENDERER 0x0002200E + #define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001 /*! @brief macOS specific * [window hint](@ref GLFW_COCOA_FRAME_NAME_hint). @@ -1180,6 +1182,9 @@ extern "C" { #define GLFW_WAYLAND_PREFER_LIBDECOR 0x00038001 #define GLFW_WAYLAND_DISABLE_LIBDECOR 0x00038002 +#define GLFW_HARDWARE_RENDERER 0x00039001 +#define GLFW_SOFTWARE_RENDERER 0x00039002 + #define GLFW_ANY_POSITION 0x80000000 /*! @defgroup shapes Standard cursor shapes diff --git a/src/context.c b/src/context.c index f4fa63ad..457f8dc0 100644 --- a/src/context.c +++ b/src/context.c @@ -56,6 +56,15 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) return GLFW_FALSE; } + if (ctxconfig->renderer != GLFW_HARDWARE_RENDERER && + ctxconfig->renderer != GLFW_SOFTWARE_RENDERER) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid context renderer 0x%08X", + ctxconfig->renderer); + return GLFW_FALSE; + } + if (ctxconfig->client != GLFW_NO_API && ctxconfig->client != GLFW_OPENGL_API && ctxconfig->client != GLFW_OPENGL_ES_API) diff --git a/src/glx_context.c b/src/glx_context.c index a2464a9d..6994a82e 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -467,6 +467,9 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, return GLFW_FALSE; } + if (ctxconfig->renderer == GLFW_SOFTWARE_RENDERER) + setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1); + if (ctxconfig->client == GLFW_OPENGL_ES_API) { if (!_glfw.glx.ARB_create_context || diff --git a/src/internal.h b/src/internal.h index 4f097aa8..1d33f045 100644 --- a/src/internal.h +++ b/src/internal.h @@ -449,6 +449,7 @@ struct _GLFWctxconfig int profile; int robustness; int release; + int renderer; _GLFWwindow* share; struct { GLFWbool offline; diff --git a/src/nsgl_context.m b/src/nsgl_context.m index 5ec34c11..90706568 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -31,6 +31,8 @@ #include #include #include +#include + static void makeContextCurrentNSGL(_GLFWwindow* window) { @@ -228,9 +230,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, NSOpenGLPixelFormatAttribute attribs[40]; int index = 0; - ADD_ATTRIB(NSOpenGLPFAAccelerated); ADD_ATTRIB(NSOpenGLPFAClosestPolicy); + if (ctxconfig->renderer == GLFW_HARDWARE_RENDERER) + { + ADD_ATTRIB(NSOpenGLPFAAccelerated); + } + else if (ctxconfig->renderer == GLFW_SOFTWARE_RENDERER) + { + SET_ATTRIB(NSOpenGLPFARendererID, kCGLRendererGenericFloatID); + } + if (ctxconfig->nsgl.offline) { ADD_ATTRIB(NSOpenGLPFAAllowOfflineRenderers); diff --git a/src/wgl_context.c b/src/wgl_context.c index 1c9189fa..925ad381 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -166,8 +166,22 @@ static int choosePixelFormatWGL(_GLFWwindow* window, if (FIND_ATTRIB_VALUE(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) continue; - if (FIND_ATTRIB_VALUE(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) - continue; + if (ctxconfig->renderer == GLFW_HARDWARE_RENDERER) + { + if (FIND_ATTRIB_VALUE(WGL_ACCELERATION_ARB) == + WGL_NO_ACCELERATION_ARB) + { + continue; + } + } + else if (ctxconfig->renderer == GLFW_SOFTWARE_RENDERER) + { + if (FIND_ATTRIB_VALUE(WGL_ACCELERATION_ARB) != + WGL_NO_ACCELERATION_ARB) + { + continue; + } + } if (FIND_ATTRIB_VALUE(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer) continue; @@ -235,10 +249,21 @@ static int choosePixelFormatWGL(_GLFWwindow* window, continue; } - if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && - (pfd.dwFlags & PFD_GENERIC_FORMAT)) + if (ctxconfig->renderer == GLFW_HARDWARE_RENDERER) { - continue; + if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && + (pfd.dwFlags & PFD_GENERIC_FORMAT)) + { + continue; + } + } + else if (ctxconfig->renderer == GLFW_SOFTWARE_RENDERER) + { + if ((pfd.dwFlags & PFD_GENERIC_ACCELERATED) && + !(pfd.dwFlags & PFD_GENERIC_FORMAT)) + { + continue; + } } if (pfd.iPixelType != PFD_TYPE_RGBA) diff --git a/src/window.c b/src/window.c index e03121a4..1648d7fc 100644 --- a/src/window.c +++ b/src/window.c @@ -259,10 +259,11 @@ void glfwDefaultWindowHints(void) // The default is OpenGL with minimum version 1.0 memset(&_glfw.hints.context, 0, sizeof(_glfw.hints.context)); - _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; + _glfw.hints.context.client = GLFW_OPENGL_API; + _glfw.hints.context.source = GLFW_NATIVE_CONTEXT_API; + _glfw.hints.context.renderer = GLFW_HARDWARE_RENDERER; + _glfw.hints.context.major = 1; + _glfw.hints.context.minor = 0; // The default is a focused, visible, resizable window with decorations memset(&_glfw.hints.window, 0, sizeof(_glfw.hints.window)); @@ -404,6 +405,9 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_CONTEXT_CREATION_API: _glfw.hints.context.source = value; return; + case GLFW_CONTEXT_RENDERER: + _glfw.hints.context.renderer = value; + return; case GLFW_CONTEXT_VERSION_MAJOR: _glfw.hints.context.major = value; return; diff --git a/tests/glfwinfo.c b/tests/glfwinfo.c index 12acbccc..e5dd709f 100644 --- a/tests/glfwinfo.c +++ b/tests/glfwinfo.c @@ -71,6 +71,9 @@ #define PLATFORM_NAME_X11 "x11" #define PLATFORM_NAME_NULL "null" +#define RENDERER_NAME_HW "hw" +#define RENDERER_NAME_SW "sw" + static void usage(void) { printf("Usage: glfwinfo [OPTION]...\n"); @@ -92,6 +95,9 @@ static void usage(void) API_NAME_NATIVE " or " API_NAME_EGL " or " API_NAME_OSMESA ")\n"); + printf(" --renderer=RENDERER the renderer to use (" + RENDERER_NAME_HW " or " + RENDERER_NAME_SW ")\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"); @@ -384,7 +390,7 @@ int main(int argc, char** argv) bool cocoa_graphics_switching = false; bool disable_xcb_surface = false; - enum { PLATFORM, CLIENT, CONTEXT, BEHAVIOR, DEBUG_CONTEXT, FORWARD, HELP, + enum { PLATFORM, CLIENT, CONTEXT, RENDERER, BEHAVIOR, DEBUG_CONTEXT, FORWARD, HELP, EXTENSIONS, LAYERS, MAJOR, MINOR, PROFILE, ROBUSTNESS, VERSION, REDBITS, GREENBITS, BLUEBITS, ALPHABITS, DEPTHBITS, STENCILBITS, @@ -397,6 +403,7 @@ int main(int argc, char** argv) { "behavior", 1, NULL, BEHAVIOR }, { "client-api", 1, NULL, CLIENT }, { "context-api", 1, NULL, CONTEXT }, + { "renderer", 1, NULL, RENDERER }, { "debug", 0, NULL, DEBUG_CONTEXT }, { "forward", 0, NULL, FORWARD }, { "help", 0, NULL, HELP }, @@ -490,6 +497,17 @@ int main(int argc, char** argv) exit(EXIT_FAILURE); } break; + case RENDERER: + if (strcasecmp(optarg, RENDERER_NAME_HW) == 0) + glfwWindowHint(GLFW_CONTEXT_RENDERER, GLFW_HARDWARE_RENDERER); + else if (strcasecmp(optarg, RENDERER_NAME_SW) == 0) + glfwWindowHint(GLFW_CONTEXT_RENDERER, GLFW_SOFTWARE_RENDERER); + else + { + usage(); + exit(EXIT_FAILURE); + } + break; case 'd': case DEBUG_CONTEXT: context_debug = true;