diff --git a/CMakeLists.txt b/CMakeLists.txt index 414162969..019926a92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ option(GLFW_BUILD_TESTS "Build the GLFW test programs" ON) option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON) option(GLFW_INSTALL "Generate installation target" ON) option(GLFW_VULKAN_STATIC "Use the Vulkan loader statically linked into application" OFF) +option(GLFW_OPENGL_SINGLE_GLRC "Build the GLFW to use only a single OpenGL render context" OFF) include(GNUInstallDirs) @@ -67,6 +68,10 @@ if (GLFW_BUILD_DOCS) find_package(Doxygen) endif() +if (GLFW_OPENGL_SINGLE_GLRC) + add_definitions(-D_GLFW_OPENGL_SINGLE_GLRC) +endif() + #-------------------------------------------------------------------- # Set compiler specific flags #-------------------------------------------------------------------- diff --git a/src/glx_context.c b/src/glx_context.c index adace82d9..09627bd12 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -238,7 +238,14 @@ static void destroyContextGLX(_GLFWwindow* window) if (window->context.glx.handle) { +#ifdef _GLFW_OPENGL_SINGLE_GLRC + if (window->context.customctx) + { + glXDestroyContext(_glfw.x11.display, window->context.glx.handle); + } +#else glXDestroyContext(_glfw.x11.display, window->context.glx.handle); +#endif window->context.glx.handle = NULL; } } @@ -495,112 +502,132 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, _glfwGrabErrorHandlerX11(); - if (_glfw.glx.ARB_create_context) +#ifdef _GLFW_OPENGL_SINGLE_GLRC + if(share) { - int index = 0, mask = 0, flags = 0; - - if (ctxconfig->client == GLFW_OPENGL_API) - { - if (ctxconfig->forward) - flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; - - if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) - mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; - else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) - mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; - } - else - mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; - - if (ctxconfig->debug) - flags |= GLX_CONTEXT_DEBUG_BIT_ARB; - - if (ctxconfig->robustness) - { - if (_glfw.glx.ARB_create_context_robustness) - { - if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) - { - setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - GLX_NO_RESET_NOTIFICATION_ARB); - } - else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) - { - setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - GLX_LOSE_CONTEXT_ON_RESET_ARB); - } - - flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; - } - } - - if (ctxconfig->release) - { - if (_glfw.glx.ARB_context_flush_control) - { - if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) - { - setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, - GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); - } - else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) - { - setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, - GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); - } - } - } - - if (ctxconfig->noerror) - { - if (_glfw.glx.ARB_create_context_no_error) - setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); - } - - // NOTE: Only request an explicitly versioned context when necessary, as - // explicitly requesting version 1.0 does not always return the - // highest version supported by the driver - if (ctxconfig->major != 1 || ctxconfig->minor != 0) - { - setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); - setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); - } - - if (mask) - setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); - - if (flags) - setAttrib(GLX_CONTEXT_FLAGS_ARB, flags); - - setAttrib(None, None); - - window->context.glx.handle = - _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, - native, - share, - True, - attribs); - - // HACK: This is a fallback for broken versions of the Mesa - // implementation of GLX_ARB_create_context_profile that fail - // default 1.0 context creation with a GLXBadProfileARB error in - // violation of the extension spec - if (!window->context.glx.handle) - { - if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && - ctxconfig->client == GLFW_OPENGL_API && - ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && - ctxconfig->forward == GLFW_FALSE) - { - window->context.glx.handle = - createLegacyContextGLX(window, native, share); - } - } + // Use shared context instead of creating a new one + window->context.glx.handle = share; + window->context.customctx = GLFW_FALSE; } else { - window->context.glx.handle = - createLegacyContextGLX(window, native, share); + // Create new GL render context + window->context.glx.handle = NULL; + window->context.customctx = GLFW_TRUE; + } +#endif + +#ifdef _GLFW_OPENGL_SINGLE_GLRC + if (!window->context.glx.handle) +#endif + { + if (_glfw.glx.ARB_create_context) + { + int index = 0, mask = 0, flags = 0; + + if (ctxconfig->client == GLFW_OPENGL_API) + { + if (ctxconfig->forward) + flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) + mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } + else + mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; + + if (ctxconfig->debug) + flags |= GLX_CONTEXT_DEBUG_BIT_ARB; + + if (ctxconfig->robustness) + { + if (_glfw.glx.ARB_create_context_robustness) + { + if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) + { + setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_NO_RESET_NOTIFICATION_ARB); + } + else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) + { + setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + GLX_LOSE_CONTEXT_ON_RESET_ARB); + } + + flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + } + + if (ctxconfig->release) + { + if (_glfw.glx.ARB_context_flush_control) + { + if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + } + else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + } + } + } + + if (ctxconfig->noerror) + { + if (_glfw.glx.ARB_create_context_no_error) + setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE); + } + + // NOTE: Only request an explicitly versioned context when necessary, as + // explicitly requesting version 1.0 does not always return the + // highest version supported by the driver + if (ctxconfig->major != 1 || ctxconfig->minor != 0) + { + setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); + } + + if (mask) + setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); + + if (flags) + setAttrib(GLX_CONTEXT_FLAGS_ARB, flags); + + setAttrib(None, None); + + window->context.glx.handle = + _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, + native, + share, + True, + attribs); + + // HACK: This is a fallback for broken versions of the Mesa + // implementation of GLX_ARB_create_context_profile that fail + // default 1.0 context creation with a GLXBadProfileARB error in + // violation of the extension spec + if (!window->context.glx.handle) + { + if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && + ctxconfig->client == GLFW_OPENGL_API && + ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && + ctxconfig->forward == GLFW_FALSE) + { + window->context.glx.handle = + createLegacyContextGLX(window, native, share); + } + } + } + else + { + window->context.glx.handle = + createLegacyContextGLX(window, native, share); + } } _glfwReleaseErrorHandlerX11(); diff --git a/src/internal.h b/src/internal.h index 3d5e22f7e..bbd1de023 100644 --- a/src/internal.h +++ b/src/internal.h @@ -340,6 +340,11 @@ struct _GLFWcontext int profile; int robustness; int release; +#ifdef _GLFW_OPENGL_SINGLE_GLRC + // Specifies whether this _GLFWcontext has its own GLRC object. + // If not, it must not delete the GLRC object on destruction. + GLFWbool customctx; +#endif PFNGLGETSTRINGIPROC GetStringi; PFNGLGETINTEGERVPROC GetIntegerv; diff --git a/src/nsgl_context.m b/src/nsgl_context.m index 72ed3597c..0e7e2363a 100755 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -57,7 +57,13 @@ static void makeContextCurrentNSGL(_GLFWwindow* window) @autoreleasepool { if (window) + { +#ifdef _GLFW_OPENGL_SINGLE_GLRC + [window->context.nsgl.object setView:window->ns.view]; + [window->context.nsgl.object update]; +#endif [window->context.nsgl.object makeCurrentContext]; + } else [NSOpenGLContext clearCurrentContext]; @@ -139,7 +145,12 @@ static void destroyContextNSGL(_GLFWwindow* window) [window->context.nsgl.pixelFormat release]; window->context.nsgl.pixelFormat = nil; +#ifdef _GLFW_OPENGL_SINGLE_GLRC + if (window->context.customctx) + [window->context.nsgl.object release]; +#else [window->context.nsgl.object release]; +#endif window->context.nsgl.object = nil; } // autoreleasepool @@ -343,6 +354,22 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, return GLFW_FALSE; } +#ifdef _GLFW_OPENGL_SINGLE_GLRC + if (ctxconfig->share) + { + // Use shared context instead of creating a new one + window->context.nsgl.object = ctxconfig->share->context.nsgl.object; + window->context.customctx = GLFW_FALSE; + } + else + { + // Create new GL context + window->context.nsgl.object = + [[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat + shareContext:nil]; + window->context.customctx = GLFW_TRUE; + } +#else NSOpenGLContext* share = NULL; if (ctxconfig->share) @@ -351,6 +378,8 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, window->context.nsgl.object = [[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat shareContext:share]; +#endif + if (window->context.nsgl.object == nil) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, diff --git a/src/wgl_context.c b/src/wgl_context.c index b3e0303cd..aeec55a25 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -389,7 +389,14 @@ static void destroyContextWGL(_GLFWwindow* window) { if (window->context.wgl.handle) { +#ifdef _GLFW_OPENGL_SINGLE_GLRC + if (window->context.customctx) + { + wglDeleteContext(window->context.wgl.handle); + } +#else wglDeleteContext(window->context.wgl.handle); +#endif window->context.wgl.handle = NULL; } } @@ -688,9 +695,23 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, setAttrib(0, 0); - window->context.wgl.handle = - _glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc, - share, attribs); +#ifdef _GLFW_OPENGL_SINGLE_GLRC + if (share) + { + // Use shared context instead of creating a new one + window->context.wgl.handle = share; + window->context.customctx = GLFW_FALSE; + } + else + { + // Create new GL render context + window->context.wgl.handle = _glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc, NULL, attribs); + window->context.customctx = GLFW_TRUE; + } +#else + window->context.wgl.handle = _glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc, share, attribs); +#endif + if (!window->context.wgl.handle) { const DWORD error = GetLastError(); @@ -741,7 +762,23 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, } else { +#ifdef _GLFW_OPENGL_SINGLE_GLRC + if (share) + { + // Use shared context instead of creating a new one + window->context.wgl.handle = share; + window->context.customctx = GLFW_FALSE; + } + else + { + // Create new GL render context + window->context.wgl.handle = wglCreateContext(window->context.wgl.dc); + window->context.customctx = GLFW_TRUE; + } +#else window->context.wgl.handle = wglCreateContext(window->context.wgl.dc); +#endif + if (!window->context.wgl.handle) { _glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE, @@ -749,6 +786,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, return GLFW_FALSE; } +#ifndef _GLFW_OPENGL_SINGLE_GLRC if (share) { if (!wglShareLists(share, window->context.wgl.handle)) @@ -758,6 +796,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, return GLFW_FALSE; } } +#endif } window->context.makeCurrent = makeContextCurrentWGL;