[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.

This commit is contained in:
2026-10-03 09:05:53 -04:00
parent 77c604061e
commit f52a546707
5 changed files with 56 additions and 5 deletions
+20 -2
View File
@@ -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) {
@@ -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<std::recursive_mutex> 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<int>(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<std::recursive_mutex> 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) {
@@ -53,6 +53,7 @@
#include <unordered_map>
#include <unordered_set>
#include <utility>
namespace MobileGL::MG_Remote::Client {
@@ -156,6 +157,15 @@ namespace MobileGL::MG_Remote::Client {
std::unordered_map<Uint64, Uint32> m_sessionSharedImages; // id -> references taken
// The ids a replaced session held: releasing one is a success with nothing sent.
std::unordered_set<Uint64> 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<EGLSurface, std::pair<Uint32, Uint32>> m_serverOwnedRequests;
void NoteServerOwnedRequest(EGLSurface surface, Uint32 width, Uint32 height) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
m_serverOwnedRequests[surface] = {width, height};
}
};
} // namespace MobileGL::MG_Remote::Client
+8 -1
View File
@@ -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;
+4
View File
@@ -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'