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; }