Wayland frontend and server hang rendering threads when the screen turns off
- Dominant language
- C++
- Stars
- 786
- Forks
- 139
- Avg merge
- 5d 37m
- Merged PRs (30d)
- 41
Description
The TMI version of this issue's investigation for Lomiri is https://gitlab.com/ubports/core/lomiri-system-compositor/-/issues/11
TL;DR: When the display turns off on a Mesa system, the mir_frontend's `swap_buffers` will hang after one successful frame. This is because Mesa throttles Wayland frame callbacks to no more than one per vsync, and the vsync has stopped when the display is off. Even if `eglSwapInterval` is set to 0, frame callbacks are throttled.
This seems to be expected behavior from a Wayland compositor, and in fact Mir is much more lenient than other compositors: opinionated compositors like wlroots and Clutter (not so sure about Clutter, but it seems to be part of the folklore online) will stop frame callbacks whenever a client is completely occluded by another client. This is efficient I suppose, saving CPU and GPU resources in buffer swaps and continuous rendering for a client that the user can't see. So I believe that we should not try and change this behavior with secret background timeouts in `swap_buffers` or the like.
However, every interesting Wayland application and toolkit has had to work around this problem since no other compositing protocol on the planet seems to do this. [Firefox](https://bugzilla.mozilla.org/show_bug.cgi?id=1489902) and [Qt](https://bugreports.qt.io/browse/QTBUG-69077) are two examples. [Qt's workaround](https://github.com/qt/qtwayland/commit/85bb158ddf08aca4d76c13c6a9fcd2637d84d3ea) involves timing out the wait for the frame callback and cancelling any further rendering, but I don't think that's a viable solution here. While it's not okay for your web browser or Qt application to hang up because the render thread is blocked on eglSwapBuffers, that's a design decision in many applications. The function which contains eglSwapBuffers often contains other side effects. Without eglSwapBuffers and those side effects completing as assumed, it might not be safe to advance the rendering or main threads.
This issue presents in `egmde` running under Sway since wlroots stops sending frame callbacks to occluded applications. To reproduce the problem, run `egmde` in a terminal (you can open your terminal with Windows+Enter). Move the `egmde` window to another workspace (Windows+Shift+2). Send an interrupt to the egmde process with Control+C in the terminal. Notice the egmde will never actually shut down.
There is some upstream work in Wayland to resolve this problem. [surface-suspension](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/99) is a protocol which allows the compositor to tell the client when its surface is suspended and it will no longer receive any frame callbacks. In the world as intended by this proposal, it seems that we would want all clients on a given (screen? display? display_server?) to be given the suspended signal when vsync is expected to stop.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the mir_frontend swap_buffers path and reproduce the egmde hang under Sway using the workspace and Control+C steps in the issue. Read the linked Wayland surface-suspension proposal and related compositor work before deciding on a supported resolution. Done should mean rendering or shutdown no longer hangs when frame callbacks stop, with the behavior verified in the reproduction case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, linux
- Domain
- desktop, operating-systems
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100