diff --git a/README.md b/README.md index 638d956f..84dc23aa 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,8 @@ information on what to include when reporting a bug. (#749,#842) - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) - Added `GLFW_LOCK_KEY_MODS` input mode and `GLFW_MOD_*_LOCK` mod bits (#946) +- Added `GLFW_CONTEXT_RENDERER` window hint and `GLFW_HARDWARE_RENDERER` and + `GLFW_SOFTWARE_RENDERER` hint values (#589) - Added macOS specific `GLFW_COCOA_RETINA_FRAMEBUFFER` window hint - Added macOS specific `GLFW_COCOA_FRAME_AUTOSAVE` window hint (#195) - Added macOS specific `GLFW_COCOA_GRAPHICS_SWITCHING` window hint (#377,#935) diff --git a/docs/window.dox b/docs/window.dox index db29d611..bb0c9227 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -339,6 +339,11 @@ the selected API. in a single process will cause the application to segfault. Stick to one API or the other on Linux for now. +@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 @@ -496,6 +501,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 07f8b172..1ef8e7cb 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -962,6 +962,7 @@ extern "C" { * [attribute](@ref GLFW_CLIENT_API_attrib). */ #define GLFW_CONTEXT_CREATION_API 0x0002200B +#define GLFW_CONTEXT_RENDERER 0x0002200C #define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001 #define GLFW_COCOA_FRAME_AUTOSAVE 0x00023002 @@ -997,6 +998,9 @@ extern "C" { #define GLFW_EGL_CONTEXT_API 0x00036002 #define GLFW_OSMESA_CONTEXT_API 0x00036003 +#define GLFW_HARDWARE_RENDERER 0x00037001 +#define GLFW_SOFTWARE_RENDERER 0x00037002 + /*! @defgroup shapes Standard cursor shapes * @brief Standard system cursor shapes. * diff --git a/src/context.c b/src/context.c index 3842f0a3..3fe4b5ad 100644 --- a/src/context.c +++ b/src/context.c @@ -50,6 +50,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 40da6c2f..cea1c88f 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -460,6 +460,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 84d096c4..2d760aa5 100644 --- a/src/internal.h +++ b/src/internal.h @@ -330,6 +330,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 a7cbf00f..688e1228 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -26,6 +26,8 @@ #include "internal.h" +#include + static void makeContextCurrentNSGL(_GLFWwindow* window) { @@ -165,9 +167,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, NSOpenGLPixelFormatAttribute attribs[40]; int index = 0; - addAttrib(NSOpenGLPFAAccelerated); addAttrib(NSOpenGLPFAClosestPolicy); + if (ctxconfig->renderer == GLFW_HARDWARE_RENDERER) + { + addAttrib(NSOpenGLPFAAccelerated); + } + else if (ctxconfig->renderer == GLFW_SOFTWARE_RENDERER) + { + setAttrib(NSOpenGLPFARendererID, kCGLRendererGenericFloatID); + } + if (ctxconfig->nsgl.offline) { addAttrib(NSOpenGLPFAAllowOfflineRenderers); diff --git a/src/wgl_context.c b/src/wgl_context.c index d864a47c..ff082cd4 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -100,10 +100,21 @@ static int choosePixelFormat(_GLFWwindow* window, continue; } - if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) == - WGL_NO_ACCELERATION_ARB) + if (ctxconfig->renderer == GLFW_HARDWARE_RENDERER) { - continue; + if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) == + WGL_NO_ACCELERATION_ARB) + { + continue; + } + } + else if (ctxconfig->renderer == GLFW_SOFTWARE_RENDERER) + { + if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) != + WGL_NO_ACCELERATION_ARB) + { + continue; + } } u->redBits = getPixelFormatAttrib(window, n, WGL_RED_BITS_ARB); @@ -170,10 +181,21 @@ static int choosePixelFormat(_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 f4468e16..9cec5786 100644 --- a/src/window.c +++ b/src/window.c @@ -239,10 +239,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)); @@ -364,6 +365,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 da2e56ec..2c7a7d70 100644 --- a/tests/glfwinfo.c +++ b/tests/glfwinfo.c @@ -54,6 +54,9 @@ #define BEHAVIOR_NAME_NONE "none" #define BEHAVIOR_NAME_FLUSH "flush" +#define RENDERER_NAME_HW "hw" +#define RENDERER_NAME_SW "sw" + static void usage(void) { printf("Usage: glfwinfo [OPTION]...\n"); @@ -68,6 +71,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"); @@ -365,7 +371,8 @@ int main(int argc, char** argv) GLenum error; GLFWwindow* window; - enum { CLIENT, CONTEXT, BEHAVIOR, DEBUG, FORWARD, HELP, EXTENSIONS, LAYERS, + enum { CLIENT, CONTEXT, RENDERER, BEHAVIOR, DEBUG, FORWARD, + HELP, EXTENSIONS, LAYERS, MAJOR, MINOR, PROFILE, ROBUSTNESS, VERSION, REDBITS, GREENBITS, BLUEBITS, ALPHABITS, DEPTHBITS, STENCILBITS, ACCUMREDBITS, ACCUMGREENBITS, ACCUMBLUEBITS, ACCUMALPHABITS, @@ -375,6 +382,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 }, { "forward", 0, NULL, FORWARD }, { "help", 0, NULL, HELP }, @@ -464,6 +472,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: glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);