From 3dde6bdeb0cec5af8b81a231b9deb851d975a2c2 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 25 Dec 2023 21:42:07 +0100 Subject: [PATCH] Disable swap interval in GLX wxGLCanvas implementation too We need to do it when using XWayland for the same reasons as we had to do it in the EGL version when using either XWayland or Wayland directly: without this, we can block for up to 1 second in glXSwapBuffers() if the window is hidden, see #23512. Closes #24163. Closes #24165. --- include/wx/unix/glx11.h | 2 ++ src/unix/glx11.cpp | 56 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/include/wx/unix/glx11.h b/include/wx/unix/glx11.h index b0e4c89cf9..cad490a878 100644 --- a/include/wx/unix/glx11.h +++ b/include/wx/unix/glx11.h @@ -99,6 +99,8 @@ public: private: GLXFBConfig *m_fbc; void* m_vi; + + bool m_swapIntervalSet = false; }; // ---------------------------------------------------------------------------- diff --git a/src/unix/glx11.cpp b/src/unix/glx11.cpp index fa73d16557..83cba2ba17 100644 --- a/src/unix/glx11.cpp +++ b/src/unix/glx11.cpp @@ -124,6 +124,13 @@ typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) #define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 #endif +namespace +{ + +constexpr const char* TRACE_GLX = "glx"; + +} // anonymous namespace + // ---------------------------------------------------------------------------- // wxGLContextAttrs: OpenGL rendering context attributes // ---------------------------------------------------------------------------- @@ -762,12 +769,59 @@ int wxGLCanvasX11::GetGLXVersion() return s_glxVersion; } +namespace +{ + +// Call glXSwapIntervalEXT() if present. +// +// For now just try using EXT_swap_control extension, in principle there is +// also a MESA one, but it's not clear if it's worth falling back on it (or +// preferring to use it?). +void wxGLSetSwapInterval(Display* dpy, GLXDrawable drawable, int interval) +{ + typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display *dpy, + GLXDrawable drawable, + int interval); + + static PFNGLXSWAPINTERVALEXTPROC s_glXSwapIntervalEXT = nullptr; + static bool s_glXSwapIntervalEXTInit = false; + if ( !s_glXSwapIntervalEXTInit ) + { + s_glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) + glXGetProcAddress((const GLubyte*)"glXSwapIntervalEXT"); + + s_glXSwapIntervalEXTInit = true; + } + + if ( s_glXSwapIntervalEXT ) + { + wxLogTrace(TRACE_GLX, "Setting GLX swap interval to %d", interval); + + s_glXSwapIntervalEXT(dpy, drawable, interval); + } +} + +} // anonymous namespace + bool wxGLCanvasX11::SwapBuffers() { const Window xid = GetXWindow(); wxCHECK2_MSG( xid, return false, wxT("window must be shown") ); - glXSwapBuffers(wxGetX11Display(), xid); + const auto dpy = wxGetX11Display(); + + // Disable blocking in glXSwapBuffers, as this is needed under XWayland for + // the reasons explained in wxGLCanvasEGL::SwapBuffers(). + if ( !m_swapIntervalSet ) + { + wxGLSetSwapInterval(dpy, xid, 0); + + // Don't try again in any case, if we failed this time, we'll fail the + // next one anyhow. + m_swapIntervalSet = true; + } + + glXSwapBuffers(dpy, xid); return true; }