diff --git a/MobileGL/MG_Backend/BackendObject.cpp b/MobileGL/MG_Backend/BackendObject.cpp index e1e31c80..835857d6 100644 --- a/MobileGL/MG_Backend/BackendObject.cpp +++ b/MobileGL/MG_Backend/BackendObject.cpp @@ -479,6 +479,12 @@ namespace MobileGL::MG_Backend { return false; } + Bool BackendObject::PresentHostFrameIfCurrent() { + const std::lock_guard lock(m_eglStateMutex); + if (!m_eglSurfaceInitialized || m_eglSurfaceKind != SurfaceKind::HostFrame) return true; + return PresentHostFrame(); + } + Bool BackendObject::IsEGLSurfaceCurrent(EGLSurface surface) const { if (surface == EGL_NO_SURFACE) { return false; diff --git a/MobileGL/MG_Backend/BackendObject.h b/MobileGL/MG_Backend/BackendObject.h index 86abcb13..21cb5996 100644 --- a/MobileGL/MG_Backend/BackendObject.h +++ b/MobileGL/MG_Backend/BackendObject.h @@ -602,6 +602,11 @@ namespace MobileGL { virtual Bool CreateEGLHostFrameSurface(EGLSurface surface, Uint32 width, Uint32 height); virtual Bool InitHostFrameSurface(EGLint width, EGLint height); virtual Bool PresentHostFrame(); + // The present RECORD's half of a host-framed swap. A split client's swap reaches the + // server as a present record (ServerVerbSink::OnPresent), never as SwapEGLBuffers, so + // without this the host was never told a frame was drawn. True when the current + // surface is not host-framed: there is nothing to present then. + Bool PresentHostFrameIfCurrent(); virtual Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); virtual Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw); // Forwards the app-requested eglSwapInterval to the backend's native diff --git a/MobileGL/MG_Remote/Server/PipeApplier.cpp b/MobileGL/MG_Remote/Server/PipeApplier.cpp index a2e2ff5a..ecaeb033 100644 --- a/MobileGL/MG_Remote/Server/PipeApplier.cpp +++ b/MobileGL/MG_Remote/Server/PipeApplier.cpp @@ -404,6 +404,15 @@ namespace MobileGL::MG_Remote::Server { // was wanted, recorded here so a future swap-without-present is looked for rather than // assumed impossible. Presents() is exposed for a lane that wants to make the comparison. table->Present(); + // A HOST-FRAMED SURFACE IS PRESENTED BY TELLING THE HOST, not by the swap above (which + // swaps the pbuffer the context was made with). BackendObject::SwapEGLBuffers is the + // only other route to PresentHostFrame and a split client never reaches it, so this is + // where the display host learns the frame is drawn - before the credit goes back, so a + // client released by it is released by a frame that is on its way to the glass. + if (m_backend != nullptr) { + if (!m_backend->PresentHostFrameIfCurrent()) + MGLOG_E_ONCE("OnPresent: the host frame was not presented (PresentHostFrame failed; see above)"); + } ++m_presents; // FrameSerial 0 means "the server stamps its own" (c1-v1 8.3): P5 has no client-side // present credit, so the client sends 0 and the frame count on this side IS the serial.