diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index f7c31257d..77b6207e4 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -711,8 +711,10 @@ void DoVendorChecks(GLPlatform &platform, GLWindowingData context) if(child.ctx) { + GLWindowingData saved; + // switch to child - platform.MakeContextCurrent(child); + platform.PushChildContext(context, child, &saved); // these shouldn't be visible VendorCheck[VendorCheck_EXT_fbo_shared] = (GL.glIsFramebuffer(fbo) != GL_FALSE); @@ -724,7 +726,7 @@ void DoVendorChecks(GLPlatform &platform, GLWindowingData context) RDCWARN("VAOs are shared on this implementation"); // switch back to context - platform.MakeContextCurrent(context); + platform.PopChildContext(context, child, saved); platform.DeleteClonedContext(child); } diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index 83f9a5b38..664218fc0 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -274,6 +274,20 @@ struct GLPlatform virtual GLWindowingData MakeOutputWindow(WindowingData window, bool depth, GLWindowingData share_context) = 0; + // for pushing and popping a child context. The default implementation just does + // MakeContextCurrent but platforms can override this if they need more complex state handling + virtual bool PushChildContext(GLWindowingData existing, GLWindowingData newChild, + GLWindowingData *saved) + { + bool success = MakeContextCurrent(newChild); + *saved = existing; + return success; + } + virtual void PopChildContext(GLWindowingData existing, GLWindowingData newChild, + GLWindowingData saved) + { + MakeContextCurrent(saved); + } // for 'backwards compatible' overlay rendering virtual void DrawQuads(float width, float height, const rdcarray &vertices) = 0; diff --git a/renderdoc/driver/gl/gl_initstate.cpp b/renderdoc/driver/gl/gl_initstate.cpp index bf00a74d9..1fac198a6 100644 --- a/renderdoc/driver/gl/gl_initstate.cpp +++ b/renderdoc/driver/gl/gl_initstate.cpp @@ -567,7 +567,9 @@ bool GLResourceManager::Prepare_InitialState(GLResource res) ContextShareGroup *shareGroup = (ContextShareGroup *)res.ContextShareGroup; - if(m_Driver->m_Platform.MakeContextCurrent(shareGroup->m_BackDoor)) + GLWindowingData savedContext; + + if(m_Driver->m_Platform.PushChildContext(oldContextData, shareGroup->m_BackDoor, &savedContext)) { m_Driver->m_ActiveContexts[Threading::GetCurrentID()] = shareGroup->m_BackDoor; @@ -575,7 +577,7 @@ bool GLResourceManager::Prepare_InitialState(GLResource res) // restore the context m_Driver->m_ActiveContexts[Threading::GetCurrentID()] = oldContextData; - m_Driver->m_Platform.MakeContextCurrent(oldContextData); + m_Driver->m_Platform.PopChildContext(oldContextData, shareGroup->m_BackDoor, savedContext); } } else @@ -1807,7 +1809,7 @@ bool GLResourceManager::Serialise_InitialState(WriteSerialiser &ser, ResourceId GLResourceRecord *record, const GLInitialContents *initial) { - GLResource res = GetCurrentResource(id); + GLResource res = record->Resource; if(IsResourceTrackedForPersistency(res)) { @@ -1815,7 +1817,9 @@ bool GLResourceManager::Serialise_InitialState(WriteSerialiser &ser, ResourceId GLWindowingData backdoor = ((ContextShareGroup *)res.ContextShareGroup)->m_BackDoor; - if(m_Driver->m_Platform.MakeContextCurrent(backdoor)) + GLWindowingData savedContext; + + if(m_Driver->m_Platform.PushChildContext(oldContextData, backdoor, &savedContext)) { m_Driver->m_ActiveContexts[Threading::GetCurrentID()] = backdoor; @@ -1824,7 +1828,7 @@ bool GLResourceManager::Serialise_InitialState(WriteSerialiser &ser, ResourceId // restore the context m_Driver->m_ActiveContexts[Threading::GetCurrentID()] = oldContextData; - m_Driver->m_Platform.MakeContextCurrent(oldContextData); + m_Driver->m_Platform.PopChildContext(oldContextData, backdoor, savedContext); return success; } diff --git a/renderdoc/driver/gl/gl_manager.cpp b/renderdoc/driver/gl/gl_manager.cpp index be6a025bb..ee95ab6bd 100644 --- a/renderdoc/driver/gl/gl_manager.cpp +++ b/renderdoc/driver/gl/gl_manager.cpp @@ -145,12 +145,18 @@ bool GLResourceManager::ResourceTypeRelease(GLResource res) { ContextShareGroup *contextShareGroup = (ContextShareGroup *)res.ContextShareGroup; - if(m_Driver->m_Platform.MakeContextCurrent(contextShareGroup->m_BackDoor)) + GLWindowingData oldContextData = m_Driver->m_ActiveContexts[Threading::GetCurrentID()]; + + GLWindowingData savedContext; + + if(m_Driver->m_Platform.PushChildContext(oldContextData, contextShareGroup->m_BackDoor, + &savedContext)) { m_Driver->ReleaseResource(res); // restore the context - m_Driver->m_Platform.MakeContextCurrent(m_Driver->m_ActiveContexts[Threading::GetCurrentID()]); + m_Driver->m_Platform.PopChildContext(oldContextData, contextShareGroup->m_BackDoor, + savedContext); } else { diff --git a/renderdoc/driver/gl/wgl_platform.cpp b/renderdoc/driver/gl/wgl_platform.cpp index 885f01411..2aa6e9cd1 100644 --- a/renderdoc/driver/gl/wgl_platform.cpp +++ b/renderdoc/driver/gl/wgl_platform.cpp @@ -37,6 +37,41 @@ class WGLPlatform : public GLPlatform return false; } + // pushing/popping contexts is complex on windows due to the really awful rules for DC lifetimes. + // Changing to the child context is easy, but getting back to where we started is hard. The + // 'current' DC may no longer be valid, as it may have been released in the meantime (while + // rendering is still A-OK). We check that the window behind the DC is valid, stored the 'wnd' + // member. If that window is valid then we use GetDC() to get a temporary DC and bind that, + // assuming all will be well. If the window isn't valid then we can't get a valid DC so we can't + // rebind the context exactly as it was, however we assume that rendering to that setup was broken + // (because the bound DC wasn't pointing to a valid window) so instead we just bind the old + // context but with our DC. + + virtual bool PushChildContext(GLWindowingData existing, GLWindowingData newChild, + GLWindowingData *saved) + { + bool success = MakeContextCurrent(newChild); + *saved = existing; + if(::IsWindow(existing.wnd)) + { + saved->DC = GetDC(existing.wnd); + } + else + { + saved->wnd = newChild.wnd; + saved->DC = newChild.DC; + } + + return success; + } + virtual void PopChildContext(GLWindowingData existing, GLWindowingData newChild, + GLWindowingData saved) + { + MakeContextCurrent(saved); + // release the DC now, if we didn't use our own because theirs was invalid + if(saved.DC != newChild.DC) + ::ReleaseDC(saved.wnd, saved.DC); + } GLWindowingData CloneTemporaryContext(GLWindowingData share) { GLWindowingData ret = share;