From f52a546707fe0f26452893579e29384c1554c1cc Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sat, 3 Oct 2026 08:24:08 -0400 Subject: [PATCH] [Fix] (EGL, Remote): a server-owned surface is re-created at the size it asked for, and a lost session's image reference is never released on the fresh one. --- MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp | 22 +++++++++++++++++-- .../MG_Remote/Client/BackendObject_Remote.cpp | 16 ++++++++++++-- .../MG_Remote/Client/BackendObject_Remote.h | 10 +++++++++ MobileGL/MG_State/EGLState/Core.cpp | 9 +++++++- MobileGL/MG_State/EGLState/Core.h | 4 ++++ 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp b/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp index cd7f9166..f19d00a3 100644 --- a/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp +++ b/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp @@ -1643,8 +1643,16 @@ namespace MobileGL::MG_Impl::EGLImpl { state->SetError(EGL_BAD_MATCH); return EGL_NO_IMAGE; } - const EGLImage image = state->CreateSharedImage( - dpy, {.Id = sharedImageId, .Width = request.Width, .Height = request.Height, .Fourcc = request.Fourcc}); +#if MOBILEGL_BUILD_DISAGGREGATED + const Uint64 wireEpoch = MG_State::CurrentWireEpoch(); +#else + const Uint64 wireEpoch = 0; +#endif + const EGLImage image = state->CreateSharedImage(dpy, {.Id = sharedImageId, + .Width = request.Width, + .Height = request.Height, + .Fourcc = request.Fourcc, + .WireEpoch = wireEpoch}); if (image == EGL_NO_IMAGE) (void)backendObject->ReleaseSharedImage(sharedImageId); return image; } @@ -1654,10 +1662,20 @@ namespace MobileGL::MG_Impl::EGLImpl { if (!state) { return EGL_FALSE; } + // The session the image's reference was taken on: a reference of a session that has ended + // died with it, and the same image imported again on the fresh session has the same id - a + // release of the old one sent there would drop the new one's reference. + MG_State::EGLState::EGLContext::SharedImageInfo shared; + const Bool sharedImage = state->GetSharedImage(image, &shared); Uint64 sharedImageId = 0; if (!state->DestroyImage(dpy, image, &sharedImageId)) { return EGL_FALSE; } +#if MOBILEGL_BUILD_DISAGGREGATED + if (sharedImage && shared.WireEpoch != MG_State::CurrentWireEpoch()) sharedImageId = 0; +#else + (void)sharedImage; +#endif // A texture the image was bound to keeps its own reference on the server (EGLImage // siblings outlive the image), so only this handle's goes. if (sharedImageId != 0) { diff --git a/MobileGL/MG_Remote/Client/BackendObject_Remote.cpp b/MobileGL/MG_Remote/Client/BackendObject_Remote.cpp index 7da3ee71..989601ee 100644 --- a/MobileGL/MG_Remote/Client/BackendObject_Remote.cpp +++ b/MobileGL/MG_Remote/Client/BackendObject_Remote.cpp @@ -238,8 +238,12 @@ namespace MobileGL::MG_Remote::Client { // into its registration only; it is re-created at that size when it is next used. { const std::lock_guard lock(m_eglStateMutex); - if (GetRegisteredEGLSurface(surface) != nullptr && m_homedSurfaces.count(surface) == 0) + if (GetRegisteredEGLSurface(surface) != nullptr && m_homedSurfaces.count(surface) == 0) { + // A server-owned one asks the fresh session's window for this size, as a resize would. + if (ClientSession::IsServerOwnedWindowSurface(surface)) + m_serverOwnedRequests[surface] = {width, height}; return MG_Backend::BackendObject::ResizeEGLWindowSurface(surface, width, height); + } } // P12 review fix: a surface on the SERVER's window is resized by resizing that window. The // server asks its display for the size and answers with the extent the window really took, @@ -254,6 +258,7 @@ namespace MobileGL::MG_Remote::Client { width, height, static_cast(reply.transport), Server::SurfaceRefusalCodeName(reply.refusal)); return false; } + NoteServerOwnedRequest(surface, width, height); const Uint32 realWidth = reply.width != 0 ? reply.width : width; const Uint32 realHeight = reply.height != 0 ? reply.height : height; if (MG_State::pEGLContext) { @@ -392,6 +397,7 @@ namespace MobileGL::MG_Remote::Client { local.Width = reply.width; local.Height = reply.height; if (!MG_Backend::BackendObject::CreateEGLWindowSurface(surface, local)) return false; + NoteServerOwnedRequest(surface, handle.Width, handle.Height); NoteHomed(surface); return true; } @@ -481,6 +487,7 @@ namespace MobileGL::MG_Remote::Client { const std::lock_guard lock(m_eglStateMutex); homed = m_homedSurfaces.erase(surface) != 0; m_standInSurfaces.erase(surface); + m_serverOwnedRequests.erase(surface); } if (homed && !ClientSession::SessionLatchedLost()) Server::ServerReleaseEGLSurface(surface); MG_Backend::BackendObject::ReleaseEGLSurface(surface); @@ -534,8 +541,13 @@ namespace MobileGL::MG_Remote::Client { recreated = Server::ServerCreateEGLPbufferSurface(surface, state.Width, state.Height, nullptr, flags); } else if (ClientSession::IsServerOwnedWindowSurface(surface)) { kind = "server-owned window"; + // The window is asked for what the application asked for (its own size for a surface + // created without one), not for the extent it had: that would fix its size for good. + const auto requested = m_serverOwnedRequests.find(surface); + const Uint32 wantWidth = requested != m_serverOwnedRequests.end() ? requested->second.first : 0u; + const Uint32 wantHeight = requested != m_serverOwnedRequests.end() ? requested->second.second : 0u; const Server::ServerOwnedWindowReply reply = - Server::ServerCreateServerOwnedWindowSurface(surface, state.Window.Width, state.Window.Height); + Server::ServerCreateServerOwnedWindowSurface(surface, wantWidth, wantHeight); recreated = reply.ok; if (recreated && reply.width != 0 && reply.height != 0) { if (MG_State::pEGLContext) { diff --git a/MobileGL/MG_Remote/Client/BackendObject_Remote.h b/MobileGL/MG_Remote/Client/BackendObject_Remote.h index 2b73a891..a95a914e 100644 --- a/MobileGL/MG_Remote/Client/BackendObject_Remote.h +++ b/MobileGL/MG_Remote/Client/BackendObject_Remote.h @@ -53,6 +53,7 @@ #include #include +#include namespace MobileGL::MG_Remote::Client { @@ -156,6 +157,15 @@ namespace MobileGL::MG_Remote::Client { std::unordered_map m_sessionSharedImages; // id -> references taken // The ids a replaced session held: releasing one is a success with nothing sent. std::unordered_set m_lostSessionSharedImages; + // The size each server-owned window surface ASKED for (0x0: the window's own), which is what a + // fresh session is asked for again when the surface is re-created there - not the extent the + // window happened to have, which would fix the window's size for good. Guarded by + // m_eglStateMutex. + std::unordered_map> m_serverOwnedRequests; + void NoteServerOwnedRequest(EGLSurface surface, Uint32 width, Uint32 height) { + const std::lock_guard lock(m_eglStateMutex); + m_serverOwnedRequests[surface] = {width, height}; + } }; } // namespace MobileGL::MG_Remote::Client diff --git a/MobileGL/MG_State/EGLState/Core.cpp b/MobileGL/MG_State/EGLState/Core.cpp index 606abc23..15f5eb20 100644 --- a/MobileGL/MG_State/EGLState/Core.cpp +++ b/MobileGL/MG_State/EGLState/Core.cpp @@ -342,7 +342,14 @@ namespace MobileGL { for (auto imageIt = m_images.begin(); imageIt != m_images.end();) { if (imageIt->second.Display == display) { - if (imageIt->second.Shared.Id != 0) m_orphanedSharedImages.push_back(imageIt->second.Shared.Id); + // Only a reference the current session holds is owed a release there. +#if MOBILEGL_BUILD_DISAGGREGATED + const Bool currentSession = imageIt->second.Shared.WireEpoch == CurrentWireEpoch(); +#else + constexpr Bool currentSession = true; +#endif + if (imageIt->second.Shared.Id != 0 && currentSession) + m_orphanedSharedImages.push_back(imageIt->second.Shared.Id); imageIt = m_images.erase(imageIt); } else { ++imageIt; diff --git a/MobileGL/MG_State/EGLState/Core.h b/MobileGL/MG_State/EGLState/Core.h index 399c0121..368bd39a 100644 --- a/MobileGL/MG_State/EGLState/Core.h +++ b/MobileGL/MG_State/EGLState/Core.h @@ -197,6 +197,10 @@ namespace MobileGL { EGLint Width = 0; EGLint Height = 0; Uint32 Fourcc = 0; + // The server session the reference was taken on (MG_State::CurrentWireEpoch() at the + // import). A reference of an ended session died with it and is never released on + // another: the same image imported again on the fresh session has the same Id. + Uint64 WireEpoch = 0; }; static constexpr Uint32 kDrmFourccAbgr8888 = 0x34324241u; // 'AB24' static constexpr Uint32 kDrmFourccXbgr8888 = 0x34324258u; // 'XB24'