mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[MG_Remote, MG_Backend] (P12 review): a server-owned surface resizes the server's window and reports its real size, every server-owned surface keeps its geometry, and Espryt reports a window's extent only for the server's own window
- Client resize: eglResize on a headless client's server-owned surface only rewrote the backend's record of the window - the phone's SurfaceView kept its size - and the client's EGL state answered the size it asked for. The server now recognises the surface as its own (ServerLoop::m_serverOwnedSurfaces, per session) and resizes it as a geometry request (the lease re-taken by its holder, the display waited for), resizes the backend surface to the window's real extent and replies with it; BackendObject_Remote adopts that extent (ServerResizeServerOwnedWindowSurface). - Size tracking: the client held ONE server-owned surface, so a second one took the first's geometry updates and releasing it left the first with none. ClientSession now tracks every server-owned surface and applies an extent to all of them (they share the server's one window). - Size reports without the knob: Espryt's new extent publish fired for every window surface of a spawn/tcp session, including windows a client named itself without MOBILEGL_IPC_SURFACE=server, switching their consumer to the reallocating arm. ServerLoop now names its own leased window to the backend (MGPipeServerSetOwnedWindow, split-only) and Espryt publishes the extent only for that window.
This commit is contained in:
@@ -16258,8 +16258,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
ApplyRequestedSwapInterval();
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P12 (D3): this publish may carry the window's extent (see the push arm of the publish).
|
||||
g_publishWindowExtent = true;
|
||||
// P12 (D3): this publish may carry the window's extent (see the push arm of the publish) -
|
||||
// review fix: only when the window is the SERVER's own (a headless client's ServerOwned
|
||||
// surface). A window the client named keeps the format-only publish without the knob.
|
||||
g_publishWindowExtent = MG_Pipe::MGPipeServerOwnedWindow() != nullptr &&
|
||||
reinterpret_cast<const void*>(window) == MG_Pipe::MGPipeServerOwnedWindow();
|
||||
PublishDefaultFramebufferDepthStencilFormat();
|
||||
g_publishWindowExtent = false;
|
||||
#else
|
||||
|
||||
@@ -406,6 +406,14 @@ namespace MobileGL::MG_Pipe {
|
||||
|
||||
Bool MGPipeServerContextIsLive() { return g_serverContextLive; }
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
namespace { const void* g_serverOwnedWindow = nullptr; }
|
||||
|
||||
void MGPipeServerSetOwnedWindow(const void* window) { g_serverOwnedWindow = window; }
|
||||
|
||||
const void* MGPipeServerOwnedWindow() { return g_serverOwnedWindow; }
|
||||
#endif
|
||||
|
||||
void MGPipeServerBlockNoteIdentity() {
|
||||
// D10: THE WIDER PREDICATE, and the narrow one was a latent crash rather than a missing
|
||||
// optimisation. Gated on the REHEARSAL, this early-returned for the whole life of a
|
||||
|
||||
@@ -938,6 +938,13 @@ namespace MobileGL::MG_Pipe {
|
||||
// GLContext or resurrected by stamping a verb after teardown.
|
||||
void MGPipeServerSetContextLive(Bool live);
|
||||
Bool MGPipeServerContextIsLive();
|
||||
// P12 review fix (size reports without the knob). The SERVER's own display window while this
|
||||
// session holds its lease (ServerLoop's ServerOwned arm sets it, the lease's end clears it), else
|
||||
// null. A backend whose window surface does not otherwise publish its extent (Espryt) publishes
|
||||
// it only for this window: a window the client named itself keeps the format-only publish every
|
||||
// earlier session relied on. Apply thread only.
|
||||
void MGPipeServerSetOwnedWindow(const void* window);
|
||||
const void* MGPipeServerOwnedWindow();
|
||||
#else
|
||||
// The push-without-transport build has one role and one block, so the fill side's spelling
|
||||
// folds onto gPipeInputs and PipeFill.cpp reads identically in both build flavours. An
|
||||
|
||||
@@ -230,6 +230,36 @@ namespace MobileGL::MG_Remote::Client {
|
||||
|
||||
Bool BackendObject_Remote::ResizeEGLWindowSurface(EGLSurface surface, Uint32 width, Uint32 height) {
|
||||
WaitForApplyBeforeEglForwarder("ResizeEGLWindowSurface");
|
||||
// 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,
|
||||
// and that - not the size asked for, which EGLImpl already wrote into the EGL state - is what
|
||||
// eglQuerySurface answers from here on.
|
||||
if (ClientSession::IsServerOwnedWindowSurface(surface)) {
|
||||
const Server::ServerOwnedWindowReply reply =
|
||||
Server::ServerResizeServerOwnedWindowSurface(surface, width, height);
|
||||
if (!reply.ok) {
|
||||
MGLOG_E("MG_Remote client: the server could not resize the server-owned window surface to %ux%u "
|
||||
"(channel rc=%d, refusal %s)",
|
||||
width, height, static_cast<int>(reply.transport), Server::SurfaceRefusalCodeName(reply.refusal));
|
||||
return false;
|
||||
}
|
||||
const Uint32 realWidth = reply.width != 0 ? reply.width : width;
|
||||
const Uint32 realHeight = reply.height != 0 ? reply.height : height;
|
||||
if (MG_State::pEGLContext) {
|
||||
(void)MG_State::pEGLContext->SetSurfaceExtent(surface, static_cast<EGLint>(realWidth),
|
||||
static_cast<EGLint>(realHeight));
|
||||
}
|
||||
if (ClientSession* session = ClientSession::Active()) {
|
||||
session->NoteServerOwnedWindowSurface(surface, realWidth, realHeight);
|
||||
session->DrainPublishedEvents();
|
||||
}
|
||||
if (realWidth != width || realHeight != height) {
|
||||
MGLOG_W("MG_Remote client: the server window took %ux%u, not the %ux%u asked for; the surface "
|
||||
"reports the window's size",
|
||||
realWidth, realHeight, width, height);
|
||||
}
|
||||
return MG_Backend::BackendObject::ResizeEGLWindowSurface(surface, realWidth, realHeight);
|
||||
}
|
||||
if (!Server::ServerResizeEGLWindowSurface(surface, width, height)) return false;
|
||||
// A resize re-creates the server's swapchain, which re-posts the surface-changed
|
||||
// event - same drain, same reason as CreateEGLWindowSurface.
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -347,22 +348,27 @@ namespace MobileGL::MG_Remote::Client {
|
||||
}
|
||||
}
|
||||
|
||||
// P12 (on-screen server window), D1: the session's server-owned window surface - the
|
||||
// client's EGL handle for it - or EGL_NO_SURFACE. Written on the GL thread by the surface
|
||||
// RPCs (NoteServerOwnedWindowSurface / ForgetServerOwnedWindowSurface) and read by the
|
||||
// drain, which runs on the same thread; atomic only because nothing else pins that.
|
||||
std::atomic<EGLSurface> g_serverOwnedSurface{EGL_NO_SURFACE};
|
||||
// P12 (on-screen server window), D1: the session's server-owned window surfaces - the
|
||||
// client's EGL handles for them. Written by the surface RPCs (NoteServerOwnedWindowSurface /
|
||||
// ForgetServerOwnedWindowSurface) and read by the drain; a mutex because an app may create
|
||||
// and release surfaces from more than one thread. REVIEW FIX: a SET, not one slot - with one
|
||||
// slot a second surface took the geometry updates from the first, and releasing the second
|
||||
// left the first with none. Every one of them is on the server's one window, so an extent
|
||||
// applies to all of them.
|
||||
std::mutex g_serverOwnedSurfacesMutex;
|
||||
std::vector<EGLSurface> g_serverOwnedSurfaces;
|
||||
|
||||
// An event's extent is the SERVER's surface size. For the server-owned window that is the
|
||||
// size the client renders at, so the EGL state's record of the surface follows it:
|
||||
// eglQuerySurface(EGL_WIDTH/EGL_HEIGHT) is what a headless client sizes its viewport from.
|
||||
// A format-only event (Width/Height 0) says nothing about the size and changes nothing.
|
||||
void ApplyServerOwnedSurfaceExtent(Uint32 width, Uint32 height) {
|
||||
if (width == 0 || height == 0) return;
|
||||
const EGLSurface surface = g_serverOwnedSurface.load(std::memory_order_acquire);
|
||||
if (surface == EGL_NO_SURFACE || !MG_State::pEGLContext) return;
|
||||
(void)MG_State::pEGLContext->SetSurfaceExtent(surface, static_cast<EGLint>(width),
|
||||
static_cast<EGLint>(height));
|
||||
if (width == 0 || height == 0 || !MG_State::pEGLContext) return;
|
||||
const std::lock_guard<std::mutex> lock(g_serverOwnedSurfacesMutex);
|
||||
for (const EGLSurface surface : g_serverOwnedSurfaces) {
|
||||
(void)MG_State::pEGLContext->SetSurfaceExtent(surface, static_cast<EGLint>(width),
|
||||
static_cast<EGLint>(height));
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 DrainEventRing(Transport::EventRingConsumer& events) {
|
||||
@@ -2468,13 +2474,25 @@ namespace MobileGL::MG_Remote::Client {
|
||||
}
|
||||
|
||||
void ClientSession::NoteServerOwnedWindowSurface(EGLSurface surface, Uint32 width, Uint32 height) {
|
||||
g_serverOwnedSurface.store(surface, std::memory_order_release);
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(g_serverOwnedSurfacesMutex);
|
||||
if (std::find(g_serverOwnedSurfaces.begin(), g_serverOwnedSurfaces.end(), surface) ==
|
||||
g_serverOwnedSurfaces.end())
|
||||
g_serverOwnedSurfaces.push_back(surface);
|
||||
}
|
||||
ApplyServerOwnedSurfaceExtent(width, height);
|
||||
}
|
||||
|
||||
void ClientSession::ForgetServerOwnedWindowSurface(EGLSurface surface) {
|
||||
EGLSurface expected = surface;
|
||||
(void)g_serverOwnedSurface.compare_exchange_strong(expected, EGL_NO_SURFACE, std::memory_order_acq_rel);
|
||||
const std::lock_guard<std::mutex> lock(g_serverOwnedSurfacesMutex);
|
||||
g_serverOwnedSurfaces.erase(std::remove(g_serverOwnedSurfaces.begin(), g_serverOwnedSurfaces.end(), surface),
|
||||
g_serverOwnedSurfaces.end());
|
||||
}
|
||||
|
||||
Bool ClientSession::IsServerOwnedWindowSurface(EGLSurface surface) {
|
||||
const std::lock_guard<std::mutex> lock(g_serverOwnedSurfacesMutex);
|
||||
return std::find(g_serverOwnedSurfaces.begin(), g_serverOwnedSurfaces.end(), surface) !=
|
||||
g_serverOwnedSurfaces.end();
|
||||
}
|
||||
|
||||
Uint64 ClientSession::EventRingCapacityBytes() const { return m_link->Memory().EventRingCapacity(); }
|
||||
|
||||
@@ -407,10 +407,13 @@ namespace MobileGL::MG_Remote::Client {
|
||||
// goes into the EGL state at once - eglQuerySurface answers it before eglCreateWindowSurface
|
||||
// returns - and every later surface-changed event that carries an extent (the server window
|
||||
// resized or rotated) is applied to the same surface, beside the default-framebuffer
|
||||
// reallocation the drain already does. One surface at a time: the newest wins, and
|
||||
// ForgetServerOwnedWindowSurface drops it when the client releases it.
|
||||
// reallocation the drain already does. Every server-owned surface is tracked (they are all
|
||||
// on the server's one window, so each extent applies to all of them), and
|
||||
// ForgetServerOwnedWindowSurface drops one when the client releases it.
|
||||
void NoteServerOwnedWindowSurface(EGLSurface surface, Uint32 width, Uint32 height);
|
||||
void ForgetServerOwnedWindowSurface(EGLSurface surface);
|
||||
// Whether `surface` is one of them (the resize path asks: it resizes the server's window).
|
||||
static Bool IsServerOwnedWindowSurface(EGLSurface surface);
|
||||
|
||||
// SEG_EVENT's ring capacity, exposed so the readback path can slice a writeback
|
||||
// request into records that always fit (RingProducer::MaxRecordBytes ==
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <MG_Util/Debug/Log.h>
|
||||
#include <MG_Util/Metrics/PipeStats.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
@@ -231,6 +232,7 @@ namespace MobileGL::MG_Remote::Server {
|
||||
// has no window-lost request pending. The apply thread that reads these is not started yet.
|
||||
m_surfaceMode = SessionSurfaceMode::None;
|
||||
m_holdsWindowLease = false;
|
||||
m_serverOwnedSurfaces.clear();
|
||||
m_windowLostRequested.store(false, std::memory_order_release);
|
||||
m_serverWindowsLost.store(0, std::memory_order_release);
|
||||
{
|
||||
@@ -1188,6 +1190,9 @@ namespace MobileGL::MG_Remote::Server {
|
||||
return MOBILEGL_OK;
|
||||
}
|
||||
case SurfaceControlOp::ResizeWindowSurface:
|
||||
// P12 review fix: a server-owned surface is resized by resizing the SERVER's window.
|
||||
if (IsServerOwnedSurface(HandleFromToken<EGLSurface>(frame.surface)))
|
||||
return ApplyServerOwnedWindowResize(backend, frame);
|
||||
frame.ok = backend->ResizeEGLWindowSurface(HandleFromToken<EGLSurface>(frame.surface),
|
||||
static_cast<Uint32>(frame.width),
|
||||
static_cast<Uint32>(frame.height));
|
||||
@@ -1273,6 +1278,7 @@ namespace MobileGL::MG_Remote::Server {
|
||||
case SurfaceControlOp::ReleaseSurface: {
|
||||
const EGLSurface surface = HandleFromToken<EGLSurface>(frame.surface);
|
||||
backend->ReleaseEGLSurface(surface);
|
||||
ForgetServerOwnedSurface(surface);
|
||||
// N-3: a released surface the held tuple names may have taken the context with it
|
||||
// (BackendObject::ReleaseEGLSurface -> OnEGLSurfaceReleased -> DestroyEGLContext once
|
||||
// nothing holds it current). Forgetting when the base class only DEFERRED the destroy
|
||||
@@ -1456,6 +1462,9 @@ namespace MobileGL::MG_Remote::Server {
|
||||
window.Handle = lease.window;
|
||||
window.Width = lease.width;
|
||||
window.Height = lease.height;
|
||||
// Review fix: the backend is told which window is the server's own, so its surface init
|
||||
// reports the extent for this window and for no window a client named (MGPipeServerOwnedWindow).
|
||||
MG_Pipe::MGPipeServerSetOwnedWindow(lease.window);
|
||||
frame.ok = backend->CreateEGLWindowSurface(HandleFromToken<EGLSurface>(frame.surface), window);
|
||||
if (!frame.ok) {
|
||||
MGLOG_E("MG_Remote server: the backend could not create a window surface on the server window %p "
|
||||
@@ -1468,6 +1477,8 @@ namespace MobileGL::MG_Remote::Server {
|
||||
// N-3: as for any window surface - a (re)creation may have destroyed the held context.
|
||||
ForgetCurrentTuple();
|
||||
m_surfaceMode = SessionSurfaceMode::OnScreen;
|
||||
if (!IsServerOwnedSurface(HandleFromToken<EGLSurface>(frame.surface)))
|
||||
m_serverOwnedSurfaces.push_back(HandleFromToken<EGLSurface>(frame.surface));
|
||||
// The reply's geometry (SurfaceReply.width/height): the window's real extent, which is what
|
||||
// the headless client's eglQuerySurface answers from here on.
|
||||
frame.width = static_cast<Int>(lease.width);
|
||||
@@ -1480,9 +1491,48 @@ namespace MobileGL::MG_Remote::Server {
|
||||
return MOBILEGL_OK;
|
||||
}
|
||||
|
||||
Bool ServerLoop::IsServerOwnedSurface(EGLSurface surface) const {
|
||||
return std::find(m_serverOwnedSurfaces.begin(), m_serverOwnedSurfaces.end(), surface) !=
|
||||
m_serverOwnedSurfaces.end();
|
||||
}
|
||||
|
||||
void ServerLoop::ForgetServerOwnedSurface(EGLSurface surface) {
|
||||
m_serverOwnedSurfaces.erase(std::remove(m_serverOwnedSurfaces.begin(), m_serverOwnedSurfaces.end(), surface),
|
||||
m_serverOwnedSurfaces.end());
|
||||
}
|
||||
|
||||
// P12 review fix (client resize). eglResize on a headless client's server-owned surface used to
|
||||
// resize only the backend's record of the window - the phone's SurfaceView kept its size - and
|
||||
// the client's EGL state answered the size it ASKED for. The window is the server's, so the
|
||||
// resize is a geometry request like the creation's: the display is asked for the size and waited
|
||||
// for (the same lease, re-taken by its holder), the backend surface follows the window's REAL
|
||||
// extent, and that extent is the reply's width/height - which the client adopts.
|
||||
MobileGLResult ServerLoop::ApplyServerOwnedWindowResize(MG_Backend::BackendObject* backend,
|
||||
SurfaceControlFrame& frame) {
|
||||
frame.ok = false;
|
||||
frame.refusal = static_cast<Uint8>(SurfaceRefusalCode::None);
|
||||
const Uint32 wantWidth = frame.width > 0 ? static_cast<Uint32>(frame.width) : 0u;
|
||||
const Uint32 wantHeight = frame.height > 0 ? static_cast<Uint32>(frame.height) : 0u;
|
||||
ServerWindowLease lease;
|
||||
SurfaceRefusalCode refusal = SurfaceRefusalCode::None;
|
||||
const MobileGLResult acquired = AcquireServerWindow(wantWidth, wantHeight, kServerWindowWaitMs, &lease, &refusal);
|
||||
if (acquired != MOBILEGL_OK) {
|
||||
frame.refusal = static_cast<Uint8>(refusal);
|
||||
return acquired;
|
||||
}
|
||||
frame.ok = backend->ResizeEGLWindowSurface(HandleFromToken<EGLSurface>(frame.surface), lease.width, lease.height);
|
||||
frame.width = static_cast<Int>(lease.width);
|
||||
frame.height = static_cast<Int>(lease.height);
|
||||
MGLOG_I("MG_Remote server: surface=window %ux%u owner=server resized (ServerOwned seq %llu, %ux%u requested%s)",
|
||||
lease.width, lease.height, static_cast<unsigned long long>(frame.seq), wantWidth, wantHeight,
|
||||
lease.sizeAsRequested ? "" : ", NOT reached");
|
||||
return MOBILEGL_OK;
|
||||
}
|
||||
|
||||
void ServerLoop::EndServerWindowLease() {
|
||||
if (!m_holdsWindowLease) return;
|
||||
m_holdsWindowLease = false;
|
||||
MG_Pipe::MGPipeServerSetOwnedWindow(nullptr);
|
||||
ServerDisplayInstance().EndLease(this);
|
||||
}
|
||||
|
||||
@@ -1574,6 +1624,23 @@ namespace MobileGL::MG_Remote::Server {
|
||||
return reply;
|
||||
}
|
||||
|
||||
ServerOwnedWindowReply ServerResizeServerOwnedWindowSurface(EGLSurface surface, Uint32 width, Uint32 height) {
|
||||
// The ordinary resize frame: the server knows the surface is on its own window.
|
||||
SurfaceControlFrame frame;
|
||||
frame.kind = SurfaceControlOp::ResizeWindowSurface;
|
||||
frame.surface = TokenFromHandle(surface);
|
||||
frame.width = static_cast<Int>(width);
|
||||
frame.height = static_cast<Int>(height);
|
||||
const MobileGLResult rc = ServerLoopInstance().RunSurfaceControlFrame(frame);
|
||||
ServerOwnedWindowReply reply;
|
||||
reply.transport = rc;
|
||||
reply.ok = rc == MOBILEGL_OK && frame.ok;
|
||||
reply.refusal = static_cast<SurfaceRefusalCode>(frame.refusal);
|
||||
reply.width = frame.width > 0 ? static_cast<Uint32>(frame.width) : 0u;
|
||||
reply.height = frame.height > 0 ? static_cast<Uint32>(frame.height) : 0u;
|
||||
return reply;
|
||||
}
|
||||
|
||||
Bool ServerMakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||
SurfaceControlFrame frame;
|
||||
// The release request (the three NO_* markers, ClassifyEglMakeCurrent's ClientRelease
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace MobileGL::MG_Remote::Server {
|
||||
|
||||
@@ -463,6 +464,13 @@ namespace MobileGL::MG_Remote::Server {
|
||||
void ReleaseLostServerWindow();
|
||||
// Ends this loop's display lease if it holds one (after the backend let go of the window).
|
||||
void EndServerWindowLease();
|
||||
// Review fix: the ResizeWindowSurface arm for a server-owned surface - a geometry request to
|
||||
// the display, the backend surface at the window's real extent, that extent in the reply.
|
||||
MobileGLResult ApplyServerOwnedWindowResize(MG_Backend::BackendObject* backend, SurfaceControlFrame& frame);
|
||||
Bool IsServerOwnedSurface(EGLSurface surface) const;
|
||||
void ForgetServerOwnedSurface(EGLSurface surface);
|
||||
// Apply thread only: this session's surfaces created on the server's window; reset by Start().
|
||||
std::vector<EGLSurface> m_serverOwnedSurfaces;
|
||||
// ServerDisplay's lost hook: called under the display's lock from Detach's thread. Sets the
|
||||
// request and rings the apply thread's bell; never blocks.
|
||||
static void ServerWindowLostThunk(void* self);
|
||||
@@ -642,6 +650,9 @@ namespace MobileGL::MG_Remote::Server {
|
||||
Uint32 height = 0;
|
||||
};
|
||||
ServerOwnedWindowReply ServerCreateServerOwnedWindowSurface(EGLSurface surface, Uint32 width, Uint32 height);
|
||||
// P12 review fix: ResizeWindowSurface for a surface created on the server's window. The server
|
||||
// resizes its WINDOW (a geometry request) and replies with the window's real extent.
|
||||
ServerOwnedWindowReply ServerResizeServerOwnedWindowSurface(EGLSurface surface, Uint32 width, Uint32 height);
|
||||
// Also RE-PUBLISHES THE CAPS SNAPSHOT on success (R-12). BackendObject::MakeEGLCurrent runs
|
||||
// InitCapabilities() on the first make-current per surface (BackendObject.cpp:341-347), so
|
||||
// this is the moment the server's answers stop being the empty ones Accept() published -
|
||||
|
||||
Reference in New Issue
Block a user