From cbd68eb4036c006533be7bffe4615a7a9e0aec05 Mon Sep 17 00:00:00 2001 From: Riteo Date: Mon, 10 Feb 2025 21:34:42 +0100 Subject: [PATCH] Wayland: Fix engine stalls wihle waiting frames There were two edge cases in the frame waiting logic (aka manual frame throttling or emulated vsync) which would cause the editor to stall in one way or another: 1. Waiting right after starting the editor would cause a deadlock between both threads until something happened in the Wayland event queue, in turn unblocking the Wayland thread and kickstartin the whole thing; 2. Starting the editor (and probably other long-loading stuff) without low consumption mode would suspend the window and never commit its surfaces, thus never signaling the compositor that we want frame events. --- platform/linuxbsd/wayland/display_server_wayland.cpp | 4 ++++ platform/linuxbsd/wayland/wayland_thread.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index 6d7d2125c68..5334446b224 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -1317,6 +1317,10 @@ void DisplayServerWayland::process_events() { DEBUG_LOG_WAYLAND("Unsuspending from timeout."); } } + + // Since we're not rendering, nothing is committing the windows' + // surfaces. We have to do it ourselves. + wayland_thread.commit_surfaces(); } #ifdef DBUS_ENABLED diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp index d2a9fde3ee6..14ea203735f 100644 --- a/platform/linuxbsd/wayland/wayland_thread.cpp +++ b/platform/linuxbsd/wayland/wayland_thread.cpp @@ -4298,6 +4298,16 @@ bool WaylandThread::get_reset_frame() { // Dispatches events until a frame event is received, a window is reported as // suspended or the timeout expires. bool WaylandThread::wait_frame_suspend_ms(int p_timeout) { + // This is a bit of a chicken and egg thing... Looks like the main event loop + // has to call its rightfully forever-blocking poll right in between + // `wl_display_prepare_read` and `wl_display_read`. This means, that it will + // basically be guaranteed to stay stuck in a "prepare read" state, where it + // will block any other attempt at reading the display fd, such as ours. The + // solution? Let's make sure the mutex is locked (it should) and unblock the + // main thread with a roundtrip! + MutexLock mutex_lock(mutex); + wl_display_roundtrip(wl_display); + if (main_window.suspended) { // The window is suspended! The compositor is telling us _explicitly_ that we // don't need to draw, without letting us guess through the frame event's