Conversation
On Wayland, a compositor may stop sending frame callbacks to a window that is not shown, for example one covered by a fullscreen window on the same workspace, without telling the client it is occluded. The glow backend then blocked in a vsync `eglSwapBuffers` until the window was shown again: no input, no `App::logic`, and unanswered pings, so the compositor reports the app as not responding. The wgpu backend already waits for frame callbacks through `pre_present_notify`, so it did not block, but `App::logic` stopped running. * glow calls `Window::pre_present_notify` before swapping, like wgpu, so winit paces `RedrawRequested` by frame callbacks. * On Wayland, glow swaps with interval 0: frame callbacks already pace it, and with the NVIDIA driver a vsync swap blocks forever for a window that starts on a hidden workspace. * If a requested `RedrawRequested` has not arrived within 250 ms, eframe runs `App::logic` without an egui pass, as it does for other hidden windows, and paints normally once the compositor asks for a frame.
|
Preview is being built... Preview will be available at https://egui-pr-preview.github.io/pr/8631-eframe-wayland-frame-pacing View snapshot changes at kitdiff |
crmne
added a commit
to crmne/zapfast
that referenced
this pull request
Sep 25, 2026
Hyprland stops frame callbacks to a window covered by a fullscreen or maximized one without marking it suspended, so a vsync swap blocked the event loop until the compositor called ZapFast unresponsive (#190). Pin the shared forks: crmne/egui apps-0.36 presents without a blocking swap on Wayland, paces frames by frame callbacks, and runs only the app logic when a redraw is 250 ms overdue (emilk/egui#8631); crmne/winit apps-0.30 reports suspended as Occluded and commits on the app's behalf (rust-windowing/winit#4709). vsync.rs's compositor check goes: vsync is requested everywhere and eframe handles Wayland. Fixes #190
crmne
added a commit
to crmne/chatwithwork-local-agent
that referenced
this pull request
Sep 25, 2026
Hyprland sends no frame callbacks to a window covered by a fullscreen or maximized one, on a hidden workspace, or with the display off, so a vsync swap blocked the event loop the tray shares and the compositor called the app unresponsive. Pin the forks ZapFast, Spotifast, RekordFlash and TonePush share: crmne/egui apps-0.36 paces Wayland frames by frame callbacks (emilk/egui#8631) and crmne/winit apps-0.30 reports suspended as Occluded (rust-windowing/winit#4709). egui_kittest comes from the same revision so the tests share one egui.
crmne
added a commit
to crmne/chatwithwork-local-agent
that referenced
this pull request
Sep 25, 2026
Hyprland sends no frame callbacks to a window covered by a fullscreen or maximized one, on a hidden workspace, or with the display off, so a vsync swap blocked the event loop the tray shares and the compositor called the app unresponsive. Pin the forks ZapFast, Spotifast, RekordFlash and TonePush share: crmne/egui apps-0.36 paces Wayland frames by frame callbacks (emilk/egui#8631) and crmne/winit apps-0.30 reports suspended as Occluded (rust-windowing/winit#4709). egui_kittest comes from the same revision so the tests share one egui.
crmne
added a commit
to crmne/chatwithwork-local-agent
that referenced
this pull request
Sep 25, 2026
Hyprland sends no frame callbacks to a window covered by a fullscreen or maximized one, on a hidden workspace, or with the display off, so a vsync swap blocked the event loop the tray shares and the compositor called the app unresponsive. Pin the forks ZapFast, Spotifast, RekordFlash and TonePush share: crmne/egui apps-0.36 paces Wayland frames by frame callbacks (emilk/egui#8631) and crmne/winit apps-0.30 reports suspended as Occluded (rust-windowing/winit#4709). egui_kittest comes from the same revision so the tests share one egui.
crmne
marked this pull request as ready for review
September 26, 2026 10:10
This was referenced Sep 26, 2026
aquamoth
added a commit
to aquamoth/parterre
that referenced
this pull request
Sep 26, 2026
…r freezes the app On Wayland sessions (WAYLAND_DISPLAY/WAYLAND_SOCKET set, or XDG_SESSION_TYPE=wayland) glow vsync is turned off before run_native, and App::ui sleeps away what is left of 8 ms since the previous frame. A vsync'ed EGL swap of a minimized window waits forever for a frame callback and blocks every viewport (egui#5145). Automated runs keep vsync off there but skip the cap. X11, Windows and macOS are unchanged. Remove the cap once emilk/egui#8631 is released. Closes #38. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #5136.
On Wayland a compositor may stop sending frame callbacks to a window it isn't showing, without telling the client that the window is occluded. Hyprland does this when another window on the same workspace goes fullscreen or maximized. With the glow backend, eframe then blocks in a vsync
eglSwapBuffersuntil the window is shown again. Nothing runs, pings go unanswered, and the compositor reports the app as not responding. With wgpu,pre_present_notifykeeps eframe from blocking, butRedrawRequestednever arrives, soApp::logicstops running.In rust-windowing/winit#4668 the winit maintainers said that winit should keep holding
RedrawRequesteduntil the frame callback arrives, and that a timeout belongs in the toolkit. This PR adds that timeout:Window::pre_present_notifybefore swapping, like egui-wgpu already does, so winit pacesRedrawRequestedby frame callbacks.RedrawRequestedwe asked for hasn't arrived within 250 ms, eframe runsApp::logicwithout an egui pass, the same as for other hidden windows. Once the compositor sends a frame callback again, the window paints normally.glow_options.vsynctherefore has no effect on Wayland. That's what vsync means there anyway, and the docs now say so.Testing
I tested with a small probe that calls
request_repainton everyApp::logiccall and countslogicanduicalls. It ran on Hyprland 0.56.2 with NVIDIA and a headless output, and I counted pings and pongs withWAYLAND_DEBUG=1. Each phase lasted 10 s:eglSwapBuffers, 0 pings answeredlogic/s, no paints, all pings answeredlogiccallslogic/slogic/s, all pings answeredlogic/s, all pings answeredX11 and other platforms: I only checked that they compile. Nothing changes there except that
run_logicmay run if aRedrawRequestedtakes more than 250 ms to arrive, which only callsApp::logicone extra time.When winit reports
Occludedon Wayland (rust-windowing/winit#4709), eframe's existing occluded handling takes over for hidden workspaces. This timeout still covers windows the compositor hides without suspending them.