[Fix] (EGL, Remote): a thread that released a lost context keeps reporting the reset until it binds another.

This commit is contained in:
2026-10-03 07:17:07 -04:00
parent 2acc6c41bb
commit cf763b4081
5 changed files with 31 additions and 0 deletions
@@ -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;
+11
View File
@@ -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;
}
+3
View File
@@ -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
+9
View File
@@ -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