Ensure that we call eglSwapInterval() for the correct context

Calling it from the frame callback might change the swap interval for
the wrong context if the active context got changed in the meanwhile,
but by the time SwapBuffers() is called the correct context must be set.

Doing it there also allows to unify X11 and Wayland code branches.

See #24014.

(cherry picked from commit 64afa9d96341f3696ba5311d36fd3a82f7c9de77)
This commit is contained in:
Vadim Zeitlin 2023-10-29 19:37:28 +01:00
parent 414faff190
commit 45ac25826b

View File

@ -453,24 +453,6 @@ void wxGLCanvasEGL::OnWLFrameCallback()
#ifdef GDK_WINDOWING_WAYLAND #ifdef GDK_WINDOWING_WAYLAND
wxLogTrace(TRACE_EGL, "In frame callback handler for %p", this); wxLogTrace(TRACE_EGL, "In frame callback handler for %p", this);
if ( !gs_alreadySetSwapInterval.count(this) )
{
// Ensure that eglSwapBuffers() doesn't block, as we use the surface
// callback to know when we should draw ourselves already.
if ( eglSwapInterval(m_display, 0) )
{
wxLogTrace(TRACE_EGL, "Set EGL swap interval to 0 for %p", this);
// It shouldn't be necessary to set it again.
gs_alreadySetSwapInterval.insert(this);
}
else
{
wxLogTrace(TRACE_EGL, "eglSwapInterval(0) failed for %p: %#x",
this, eglGetError());
}
}
m_readyToDraw = true; m_readyToDraw = true;
g_clear_pointer(&m_wlFrameCallbackHandler, wl_callback_destroy); g_clear_pointer(&m_wlFrameCallbackHandler, wl_callback_destroy);
SendSizeEvent(); SendSizeEvent();
@ -803,15 +785,40 @@ void wxGLCanvasEGL::FreeDefaultConfig()
bool wxGLCanvasEGL::SwapBuffers() bool wxGLCanvasEGL::SwapBuffers()
{ {
// Before doing anything else, ensure that eglSwapBuffers() doesn't block:
// under Wayland we don't want it to because we use the surface callback to
// know when we should draw anyhow and with X11 it blocks for up to a
// second when the window is entirely occluded and because we can't detect
// this currently (our IsShownOnScreen() doesn't account for all cases in
// which this happens) we must prevent it from blocking to avoid making the
// entire application completely unusable just because one of its windows
// using wxGLCanvas got occluded or unmapped (e.g. due to a move to another
// workspace).
if ( !gs_alreadySetSwapInterval.count(this) )
{
// Ensure that eglSwapBuffers() doesn't block, as we use the surface
// callback to know when we should draw ourselves already.
if ( eglSwapInterval(m_display, 0) )
{
wxLogTrace(TRACE_EGL, "Set EGL swap interval to 0 for %p", this);
// It shouldn't be necessary to set it again.
gs_alreadySetSwapInterval.insert(this);
}
else
{
wxLogTrace(TRACE_EGL, "eglSwapInterval(0) failed for %p: %#x",
this, eglGetError());
}
}
GdkWindow* const window = GTKGetDrawingWindow(); GdkWindow* const window = GTKGetDrawingWindow();
#ifdef GDK_WINDOWING_X11 #ifdef GDK_WINDOWING_X11
if (wxGTKImpl::IsX11(window)) if (wxGTKImpl::IsX11(window))
{ {
if ( !IsShownOnScreen() ) if ( !IsShownOnScreen() )
{ {
// Trying to draw on a hidden window is useless and can actually be // Trying to draw on a hidden window is useless.
// harmful if the compositor blocks in eglSwapBuffers() in this
// case, so avoid it.
wxLogTrace(TRACE_EGL, "Window %p is hidden, not drawing", this); wxLogTrace(TRACE_EGL, "Window %p is hidden, not drawing", this);
return false; return false;
} }