Add GLFW_CONTEXT_RENDERER

This window hint allows choosing between hardware and software renderers
(where available) for the created OpenGL or OpenGL ES context.

Fixes #589.
diff --git a/README.md b/README.md
index 638d956..84dc23a 100644
--- a/README.md
+++ b/README.md
@@ -160,6 +160,8 @@
   (#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 db29d61..bb0c922 100644
--- a/docs/window.dox
+++ b/docs/window.dox
@@ -339,6 +339,11 @@
 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_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 07f8b17..1ef8e7c 100644
--- a/include/GLFW/glfw3.h
+++ b/include/GLFW/glfw3.h
@@ -962,6 +962,7 @@
  *  [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 @@
 #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 3842f0a..3fe4b5a 100644
--- a/src/context.c
+++ b/src/context.c
@@ -50,6 +50,15 @@
         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 40da6c2..cea1c88 100644
--- a/src/glx_context.c
+++ b/src/glx_context.c
@@ -460,6 +460,9 @@
         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 84d096c..2d760aa 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -330,6 +330,7 @@
     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 a7cbf00..688e122 100644
--- a/src/nsgl_context.m
+++ b/src/nsgl_context.m
@@ -26,6 +26,8 @@
 
 #include "internal.h"
 
+#include <OpenGL/CGLRenderers.h>
+
 
 static void makeContextCurrentNSGL(_GLFWwindow* window)
 {
@@ -165,9 +167,17 @@
     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 d864a47..ff082cd 100644
--- a/src/wgl_context.c
+++ b/src/wgl_context.c
@@ -100,10 +100,21 @@
                 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 @@
                 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 f4468e1..9cec578 100644
--- a/src/window.c
+++ b/src/window.c
@@ -239,10 +239,11 @@
 
     // 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 @@
         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 da2e56e..2c7a7d7 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 @@
                                         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 @@
     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 @@
         { "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 @@
                     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);