Added support for choosing the rendering gpu using wgl_nv_affinity

extension.

Added Native API call to get the device context.
This commit is contained in:
BretJackson 2013-07-18 14:22:51 -05:00 committed by Bret Jackson
parent a18b187494
commit 2e99b10800
7 changed files with 106 additions and 7 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -299,6 +299,7 @@ struct _GLFWlibrary
GLboolean glDebug;
int glProfile;
int glRobustness;
int gpu;
} hints;
double cursorPosX, cursorPosY;

View File

@ -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,
@ -490,8 +547,14 @@ void _glfwDestroyContext(_GLFWwindow* window)
if (window->wgl.dc)
{
ReleaseDC(window->win32.handle, window->wgl.dc);
window->wgl.dc = NULL;
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;
}

View File

@ -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;

View File

@ -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);