Add special push/pop logic for WGL contexts

* We can't easily restore the application's context if the DC that was current
  has been released. Instead we check to see if the last known window is still
  valid - if so, we get the DC handle from it. If not then we assume that
  rendering to the application's context setup would have failed so we bind our
  own backdoor window (but with the application's context still).
This commit is contained in:
baldurk
2020-01-22 19:05:53 +00:00
parent 14b3a06361
commit 4c9bb5d844
5 changed files with 70 additions and 9 deletions
+4 -2
View File
@@ -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);
}
+14
View File
@@ -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<Vec4f> &vertices) = 0;
+9 -5
View File
@@ -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;
}
+8 -2
View File
@@ -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
{
+35
View File
@@ -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;