[Feature] (GL): glFlush presents the display host's frame for a compositor that never swaps

kwin draws the desktop into the display host's frame and then calls glFlush - and glFlush alone;
it never calls eglSwapBuffers.  The stream reached the server and the server drew, but the display
host was never told a frame was done, so nothing reached the glass.  When the surfaceless-bind hook
has taken the host frame, glFlush now swaps that surface after flushing the stream: that swap is the
host's "frame is done".

A swap of a surface the EGL state does not know used to return EGL_BAD_SURFACE without a word - the
whole reason the host frame's presents were invisible - so that refusal is now reported once.
This commit is contained in:
BZLZHH
2026-10-01 09:47:12 -04:00
parent c16a51da62
commit 16488d5801
2 changed files with 15 additions and 0 deletions
+1
View File
@@ -254,6 +254,7 @@ namespace MobileGL::MG_Impl::EGLImpl {
return EGL_FALSE;
}
if (!state->ValidateSurfaceOnDisplay(dpy, draw)) {
MGLOG_E_ONCE("eglSwapBuffers: surface %p is not a surface of display %p (EGL_BAD_SURFACE)", draw, dpy);
state->SetError(EGL_BAD_SURFACE);
return EGL_FALSE;
}
@@ -29,6 +29,9 @@
// names is an object eglCreateImageKHR built (its geometry, its fourcc and the descriptors it owns),
// and that object lives in the EGL state. Same include the other GLImpl files that touch it use.
#include <MG_State/EGLState/Core.h>
// The compositor's frame boundary: glFlush presents the display host's frame when the surfaceless
// bind hook took one (see EGLImpl.cpp). The EGL side declares the pair and the swap entry.
#include <MG_Impl/EGLImpl/EGLImpl.h>
#define DECLARE_GL_FUNCTION_STUB_HEAD(type, name, ...) MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
@@ -132,6 +135,17 @@ MOBILEGL_GL_API void glFlush() {
#if MOBILEGL_BUILD_DISAGGREGATED
MobileGL::MG_Pipe::MGPipeClientFlush();
#endif
// A COMPOSITOR'S FRAME BOUNDARY. kwin binds the display host's frame surface and draws the
// desktop into it, then calls glFlush - and glFlush alone. It never calls eglSwapBuffers, so
// without this the stream reached the server and the server drew, but the display host was
// never told a frame was done: the host's own present loop (AHardwareBuffer_acquire ->
// draw -> notify) is what puts pixels on the glass, and its notify is exactly this swap.
// Guarded by whether the surfaceless-bind hook actually took the host frame.
if (MobileGL::MG_Impl::EGLImpl::g_hostFramePresentSurface != nullptr &&
MobileGL::MG_Impl::EGLImpl::g_hostFramePresentDisplay != nullptr) {
MobileGL::MG_Impl::EGLImpl::SwapBuffers(MobileGL::MG_Impl::EGLImpl::g_hostFramePresentDisplay,
MobileGL::MG_Impl::EGLImpl::g_hostFramePresentSurface);
}
}
DECLARE_GL_FUNCTION_HEAD(void, FramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer)
DECLARE_GL_FUNCTION_HEAD(void, FramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferTexture2D, target, attachment, textarget, texture, level)