[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.
This commit is contained in:
BZLZHH
2026-10-03 15:54:55 +08:00
parent 8245221755
commit f44888ca01
+15 -3
View File
@@ -18289,13 +18289,25 @@ namespace MobileGL::MG_Backend::DirectGLES {
if (const auto* entry = FindSessionSurfaceLocked(session, drawSurface))
windowSurface = entry->Window != static_cast<NativeWindowType>(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<EGLint>(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<std::mutex> lock(g_nativeRegistryMutex);