From 2e99b108009ddabf6d7c960d2d6fa4e9881c06ea Mon Sep 17 00:00:00 2001 From: BretJackson Date: Thu, 18 Jul 2013 14:22:51 -0500 Subject: [PATCH] Added support for choosing the rendering gpu using wgl_nv_affinity extension. Added Native API call to get the device context. --- docs/window.dox | 6 +++ include/GLFW/glfw3.h | 1 + include/GLFW/glfw3native.h | 5 +++ src/internal.h | 1 + src/wgl_context.c | 89 +++++++++++++++++++++++++++++++++++--- src/wgl_platform.h | 5 +++ src/window.c | 6 +++ 7 files changed, 106 insertions(+), 7 deletions(-) diff --git a/docs/window.dox b/docs/window.dox index ab83e5054..05c07106a 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -188,6 +188,11 @@ used by the context. This can be one of `GLFW_NO_RESET_NOTIFICATION` or `GLFW_LOSE_CONTEXT_ON_RESET`, or `GLFW_NO_ROBUSTNESS` to not request a robustness strategy. +The `GLFW_AFFINITY_GPU` hint specifies which GPU should render OpenGL commands +for the associated context. This uses the WGL_NV_gpu_affinity extension, and is +only available on windows systems. The value corresponds with an index position +returned from a call to wglEnumGpusNV(...). Note that if sharing context resources +with another window, both windows must have the same affinity gpu mask. @subsection window_hints_values Supported and default values @@ -218,6 +223,7 @@ a robustness strategy. | `GLFW_OPENGL_FORWARD_COMPAT` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` | | `GLFW_OPENGL_DEBUG_CONTEXT` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` | | `GLFW_OPENGL_PROFILE` | `GLFW_OPENGL_ANY_PROFILE` | `GLFW_OPENGL_ANY_PROFILE`, `GLFW_OPENGL_COMPAT_PROFILE` or `GLFW_OPENGL_CORE_PROFILE` | +| `GLFW_AFFINITY_GPU` | -1 | 0 to maximum number of GPUs | @section window_close Window close flag diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 0f97738c7..b5b090849 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -511,6 +511,7 @@ extern "C" { #define GLFW_SAMPLES 0x0002100D #define GLFW_SRGB_CAPABLE 0x0002100E #define GLFW_REFRESH_RATE 0x0002100F +#define GLFW_AFFINITY_GPU 0x00021010 #define GLFW_CLIENT_API 0x00022001 #define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index d570f5876..04bfc85f0 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -115,6 +115,11 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); * @ingroup native */ GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); +/*! @brief Returns the `HDC` of the specified window. + * @return The `HDC` of the specified window. + * @ingroup native + */ +GLFWAPI HDC glfwGetWGLDC(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_COCOA) diff --git a/src/internal.h b/src/internal.h index 8a24959a3..5159af2a3 100644 --- a/src/internal.h +++ b/src/internal.h @@ -299,6 +299,7 @@ struct _GLFWlibrary GLboolean glDebug; int glProfile; int glRobustness; + int gpu; } hints; double cursorPosX, cursorPosY; diff --git a/src/wgl_context.c b/src/wgl_context.c index 0b3610bd9..d096ca06a 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -46,6 +46,9 @@ static void initWGLExtensions(_GLFWwindow* window) window->wgl.GetExtensionsStringARB = NULL; window->wgl.GetExtensionsStringEXT = NULL; window->wgl.CreateContextAttribsARB = NULL; + window->wgl.CreateAffinityDCNV = NULL; + window->wgl.DeleteDCNV = NULL; + window->wgl.EnumGpusNV = NULL; // This needs to include every extension used below except for // WGL_ARB_extensions_string and WGL_EXT_extensions_string @@ -57,6 +60,7 @@ static void initWGLExtensions(_GLFWwindow* window) window->wgl.ARB_create_context_robustness = GL_FALSE; window->wgl.EXT_swap_control = GL_FALSE; window->wgl.ARB_pixel_format = GL_FALSE; + window->wgl.NV_gpu_affinity = GL_FALSE; window->wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) wglGetProcAddress("wglGetExtensionsStringEXT"); @@ -119,6 +123,21 @@ static void initWGLExtensions(_GLFWwindow* window) if (window->wgl.GetPixelFormatAttribivARB) window->wgl.ARB_pixel_format = GL_TRUE; } + + if (_glfwPlatformExtensionSupported("WGL_NV_gpu_affinity")) + { + window->wgl.EnumGpusNV = (PFNWGLENUMGPUSNVPROC) + wglGetProcAddress("wglEnumGpusNV"); + + window->wgl.CreateAffinityDCNV = (PFNWGLCREATEAFFINITYDCNVPROC) + wglGetProcAddress("wglCreateAffinityDCNV"); + + window->wgl.DeleteDCNV = (PFNWGLDELETEDCNVPROC) + wglGetProcAddress("wglDeleteDCNV"); + + if (window->wgl.EnumGpusNV && window->wgl.CreateAffinityDCNV) + window->wgl.NV_gpu_affinity = GL_TRUE; + } } // Returns the specified attribute of the specified pixel format @@ -358,7 +377,7 @@ int _glfwCreateContext(_GLFWwindow* window, if (wndconfig->share) share = wndconfig->share->wgl.context; - window->wgl.dc = GetDC(window->win32.handle); + window->wgl.dc = GetDC(window->win32.handle); if (!window->wgl.dc) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -384,6 +403,30 @@ int _glfwCreateContext(_GLFWwindow* window, return GL_FALSE; } + // If the nvidia affinity extension is available and the gpu has been set through a hint, create an affinityDC bound to a specific gpu. + // We create the affinityDC and then make an affinity context using the + // affinityDC. Because we are doing onscreen rendering and the affinityDC isn't bound to a window (i.e. doesn't contain a framebuffer), + // we make the affinitycontext current with the normal dc that is bound to the window. + if (window->wgl.NV_gpu_affinity && _glfw.hints.gpu != -1) + { + HGPUNV gpuMask; + window->wgl.EnumGpusNV(_glfw.hints.gpu, &gpuMask); + window->wgl.affinityDC = window->wgl.CreateAffinityDCNV(&gpuMask); + if (!window->wgl.affinityDC) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to create NV Affinity DC for window"); + } + else { + if (!SetPixelFormat(window->wgl.affinityDC, pixelFormat, &pfd)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to set selected pixel format for affinity DC"); + return GL_FALSE; + } + } + } + if (window->wgl.ARB_create_context) { int index = 0, mask = 0, flags = 0, strategy = 0; @@ -437,9 +480,19 @@ int _glfwCreateContext(_GLFWwindow* window, setWGLattrib(0, 0); - window->wgl.context = window->wgl.CreateContextAttribsARB(window->wgl.dc, - share, - attribs); + if (window->wgl.affinityDC) + { + window->wgl.context = window->wgl.CreateContextAttribsARB(window->wgl.affinityDC, + share, + attribs); + } + else + { + window->wgl.context = window->wgl.CreateContextAttribsARB(window->wgl.dc, + share, + attribs); + } + if (!window->wgl.context) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, @@ -449,7 +502,11 @@ int _glfwCreateContext(_GLFWwindow* window, } else { - window->wgl.context = wglCreateContext(window->wgl.dc); + if (window->wgl.affinityDC) + window->wgl.context = wglCreateContext(window->wgl.affinityDC); + else + window->wgl.context = wglCreateContext(window->wgl.dc); + if (!window->wgl.context) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -489,9 +546,15 @@ void _glfwDestroyContext(_GLFWwindow* window) if (window->wgl.dc) { - ReleaseDC(window->win32.handle, window->wgl.dc); - window->wgl.dc = NULL; + ReleaseDC(window->win32.handle, window->wgl.dc); + window->wgl.dc = NULL; } + + if (window->wgl.affinityDC) + { + window->wgl.DeleteDCNV(window->wgl.affinityDC); + window->wgl.affinityDC = NULL; + } } // Analyzes the specified context for possible recreation @@ -570,6 +633,12 @@ int _glfwAnalyzeContext(const _GLFWwindow* window, } } + if (window->wgl.NV_gpu_affinity && _glfw.hints.gpu != -1) + { + // We have requested an nvidia affinity context with a specific gpu + required = GL_TRUE; + } + if (required) return _GLFW_RECREATION_REQUIRED; @@ -668,3 +737,9 @@ GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) return window->wgl.context; } +GLFWAPI HDC glfwGetWGLDC(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->wgl.dc; +} diff --git a/src/wgl_platform.h b/src/wgl_platform.h index bffdf742b..a88043d63 100644 --- a/src/wgl_platform.h +++ b/src/wgl_platform.h @@ -50,6 +50,7 @@ typedef struct _GLFWcontextWGL { // Platform specific window resources HDC dc; // Private GDI device context + HDC affinityDC; // gpu affinity device context HGLRC context; // Permanent rendering context // Platform specific extensions (context specific) @@ -58,6 +59,9 @@ typedef struct _GLFWcontextWGL PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + PFNWGLCREATEAFFINITYDCNVPROC CreateAffinityDCNV; + PFNWGLDELETEDCNVPROC DeleteDCNV; + PFNWGLENUMGPUSNVPROC EnumGpusNV; GLboolean EXT_swap_control; GLboolean ARB_multisample; GLboolean ARB_framebuffer_sRGB; @@ -66,6 +70,7 @@ typedef struct _GLFWcontextWGL GLboolean ARB_create_context_profile; GLboolean EXT_create_context_es2_profile; GLboolean ARB_create_context_robustness; + GLboolean NV_gpu_affinity; } _GLFWcontextWGL; diff --git a/src/window.c b/src/window.c index 4e2b27701..40eee14d0 100644 --- a/src/window.c +++ b/src/window.c @@ -284,6 +284,9 @@ void glfwDefaultWindowHints(void) _glfw.hints.alphaBits = 8; _glfw.hints.depthBits = 24; _glfw.hints.stencilBits = 8; + + // Set the default gpu to -1. + _glfw.hints.gpu = -1; } GLFWAPI void glfwWindowHint(int target, int hint) @@ -366,6 +369,9 @@ GLFWAPI void glfwWindowHint(int target, int hint) break; case GLFW_OPENGL_PROFILE: _glfw.hints.glProfile = hint; + break; + case GLFW_AFFINITY_GPU: + _glfw.hints.gpu = hint; break; default: _glfwInputError(GLFW_INVALID_ENUM, NULL);