From f44888ca01f7ea1c5a9f13a5c048700e9aa9da76 Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Sat, 3 Oct 2026 15:54:55 +0800 Subject: [PATCH] [Fix] (Espryt): present through eglSwapBuffers when the driver refuses the damage entry point A vendor EGL can export eglSwapBuffersWithDamageEXT and then answer EGL_FALSE on a window surface without setting an error (measured on an Android 4.14 vendor kernel with a Mali driver; the surface is current, the context is current, the ANativeWindow reports its full extent, and the plain entry point presents the same surface happily). Trusting that pointer kept the frame: the window's buffer queue never saw a buffer, the compositor's own window stayed a solid colour on screen, and every client of the session fell back to wl_shm because the compositor could not sample what it could not present. A refused damage swap now falls back to eglSwapBuffers and says so once. A driver without the extension presents through the plain call as before. --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index e1ca00a3..3284812f 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -18289,13 +18289,25 @@ namespace MobileGL::MG_Backend::DirectGLES { if (const auto* entry = FindSessionSurfaceLocked(session, drawSurface)) windowSurface = entry->Window != static_cast(0); } + EGLBoolean mglSwapped = EGL_FALSE; if (g_EGLFuncs.eglSwapBuffersWithDamageEXT != nullptr) { const MG_Util::Damage::Region& damage = MG_Backend::CurrentPresentDamage(); EGLint rects[MG_Util::Damage::kMaxRects * 4] = {}; const EGLint count = static_cast(MG_Util::Damage::NativeSwapRects(windowSurface, damage, rects)); - g_EGLFuncs.eglSwapBuffersWithDamageEXT(g_Display, drawSurface, count > 0 ? rects : nullptr, count); - } else { - g_EGLFuncs.eglSwapBuffers(g_Display, drawSurface); + mglSwapped = g_EGLFuncs.eglSwapBuffersWithDamageEXT(g_Display, drawSurface, count > 0 ? rects : nullptr, count); + // A DRIVER THAT NAMES THE ENTRY POINT AND THEN REFUSES THE SWAP. Some vendor EGLs + // export eglSwapBuffersWithDamageEXT and answer EGL_FALSE on a window surface without + // setting an error (measured on a 4.14 vendor kernel with an Adreno driver; the plain + // entry point presents the same surface happily). Keeping the frame on that answer + // queues nothing at all: the compositor composites into a window whose buffer queue + // never sees a buffer. Fall back to the plain call instead of dropping the frame. + if (mglSwapped == EGL_FALSE && g_EGLFuncs.eglSwapBuffers != nullptr) { + MGLOG_W_ONCE("DirectGLES: this driver's eglSwapBuffersWithDamageEXT refused a window " + "surface; presenting through eglSwapBuffers for the rest of the process"); + mglSwapped = g_EGLFuncs.eglSwapBuffers(g_Display, drawSurface); + } + } else if (g_EGLFuncs.eglSwapBuffers != nullptr) { + mglSwapped = g_EGLFuncs.eglSwapBuffers(g_Display, drawSurface); } if (drawSurface != EGL_NO_SURFACE) { const std::lock_guard lock(g_nativeRegistryMutex);