mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Fix] (EGL, Remote): a thread that released a lost context keeps reporting the reset until it binds another.
This commit is contained in:
@@ -629,6 +629,8 @@ namespace MobileGL::MG_Remote::Client {
|
||||
if (session == nullptr) return false;
|
||||
if (session->m_deviceLost.load(std::memory_order_acquire)) return true;
|
||||
if (tl_currentSessionWork != 0) return false;
|
||||
// A thread that released a lost context and has bound none since (MG_State's marker).
|
||||
if (MG_State::tThreadReleasedLostContext) return true;
|
||||
// A thread still on a context from before a recovered loss: lost for good, whatever the
|
||||
// session it would now be writing into.
|
||||
const SharedPtr<MG_State::GLState::GLContext>& context = MG_State::pGLContext;
|
||||
|
||||
@@ -257,6 +257,14 @@ namespace MobileGL {
|
||||
// context's objects ended in the thread-exit destructor of that TLS: outside every
|
||||
// entry point and its lock, writing their records into the middle of another
|
||||
// thread's - torn records, a reply read from the wrong slot, a lost session.
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
{
|
||||
const auto released = context != nullptr ? m_contexts.find(context) : m_contexts.end();
|
||||
tThreadReleasedLostContext = !currentIt->second.RestoreThreadGLState && released != m_contexts.end() &&
|
||||
released->second.GLStateObject &&
|
||||
released->second.GLStateObject->IsFromEndedWireSession();
|
||||
}
|
||||
#endif
|
||||
pGLContext = currentIt->second.RestoreThreadGLState ? Move(currentIt->second.RestoreThreadGLState)
|
||||
: ProcessDefaultGLContext();
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
@@ -1513,6 +1521,9 @@ namespace MobileGL {
|
||||
if (const auto* contextObject = TryGetContext(context); contextObject != nullptr) {
|
||||
pGLContext = contextObject->GLStateObject;
|
||||
}
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
tThreadReleasedLostContext = false;
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1665,4 +1665,7 @@ namespace MobileGL::MG_State {
|
||||
|
||||
// Leak-at-exit storage; see GlobalObjects.cpp.
|
||||
thread_local SharedPtr<GLState::GLContext> pGLContext;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
thread_local Bool tThreadReleasedLostContext = false;
|
||||
#endif
|
||||
} // namespace MobileGL::MG_State
|
||||
|
||||
@@ -762,6 +762,15 @@ namespace MobileGL {
|
||||
// gave it. NULL on a thread for which neither has happened, the same answer a process
|
||||
// that never reached MG_State::Init() (the spawn server image) has always given.
|
||||
extern thread_local SharedPtr<GLState::GLContext> pGLContext;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// True on a thread whose last EGL release let go of a context lost with an ended server
|
||||
// session, until it makes a context current again. The release hands such a thread the
|
||||
// process default rather than the lost context's GL state (which would make the thread's
|
||||
// TLS that state's last owner), so this is what keeps the thread answering as lost: an
|
||||
// application that releases its context before asking glGetGraphicsResetStatus - Qt's
|
||||
// render threads do - still learns that the context is gone and rebuilds it.
|
||||
extern thread_local Bool tThreadReleasedLostContext;
|
||||
#endif
|
||||
|
||||
// The fallback pGLContext starts at and an EGL release edge restores to: the process's
|
||||
// one context for every thread that never bound an EGL context to itself, created on
|
||||
|
||||
@@ -567,6 +567,7 @@ namespace {
|
||||
Int32 staleSwap = -1;
|
||||
Int32 staleSwapError = 0;
|
||||
Int32 staleRelease = 0;
|
||||
Uint32 resetStatusAfterRelease = 0;
|
||||
Int64 recordsByStaleThread = -1;
|
||||
Uint32 pixelAfterStale = 0;
|
||||
Uint32 resetStatusAfterStale = 0xFFFFFFFFu;
|
||||
@@ -621,6 +622,9 @@ namespace {
|
||||
r.staleSwap = EGL::SwapBuffers(egl.dpy, egl.surface);
|
||||
r.staleSwapError = EGL::GetError();
|
||||
r.staleRelease = EGL::MakeCurrent(egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_TRUE;
|
||||
// Released, the thread still answers as lost until it binds a context again: Qt's
|
||||
// render threads release before they ask, and rebuild only when told.
|
||||
r.resetStatusAfterRelease = glGetGraphicsResetStatus();
|
||||
});
|
||||
r.recordsByStaleThread = static_cast<Int64>(PublishedSeq()) - static_cast<Int64>(before);
|
||||
r.destroyOldOk = EGL::DestroyContext(egl.dpy, lost) == EGL_TRUE;
|
||||
@@ -1236,6 +1240,8 @@ TEST_F(ClientRecovery, AThreadStillOnTheLostContextReachesNothingOfTheFreshSessi
|
||||
EXPECT_EQ(r.staleSwap, EGL_FALSE);
|
||||
EXPECT_EQ(r.staleSwapError, EGL_CONTEXT_LOST) << std::hex << r.staleSwapError;
|
||||
EXPECT_EQ(r.staleRelease, 1) << "the second thread could not release the lost context";
|
||||
EXPECT_NE(r.resetStatusAfterRelease, static_cast<Uint32>(GL_NO_ERROR))
|
||||
<< "the thread that released the lost context no longer reports the reset";
|
||||
EXPECT_EQ(r.recordsByStaleThread, 0) << "the thread on the lost context published records on the fresh session";
|
||||
EXPECT_EQ(r.destroyOldOk, 1);
|
||||
EXPECT_EQ(r.pixelAfterStale, kRed) << "the fresh context stopped rendering: " << std::hex << r.pixelAfterStale
|
||||
|
||||
Reference in New Issue
Block a user