Details
-
Bug
-
Resolution: Fixed
-
P3: Somewhat important
-
None
-
6.5
-
None
Description
Problem
When a QtQuick window is being resized, its content jumps or bounces (see the attached video). "Hello" label should always be snapped to the top left corner, but instead, it bounces.
In order to reproduce this issue yourself, run qml test.qml and resize the window. Note that this issue may not be reproducible with some compositors because they handle interactive resizing differently. Use kwin compositor to reproduce this issue - dbus-run-session kwin_wayland --exit-with-session="qml test.qml".
Cause of the Problem
On Wayland, window updates are double buffered. That is, after changing something, you need to commit the wl_surface. For example
frame 1:
xdg_surface_set_window_geometry(xdg_surface, 0, 0, 100, 100);
wl_surface_attach(surface, buffer with size 100x100, 0, 0);
wl_surface_commit(surface);{}
frame 2:
xdg_surface_set_window_geometry(xdg_surface, 0, 0, 90, 90);
wl_surface_attach(surface, buffer with size 90x90, 0, 0);
wl_surface_commit(surface);
This works as expected if rendering is being done on the main thread. But if rendering is being done in another thread and the window is being resized, it's possible to have a case like this (that can be noticed as glitches)
frame 1:
xdg_surface_set_window_geometry(xdg_surface, 0, 0, 100, 100); # called in main thread
xdg_surface_set_window_geometry(xdg_surface, 0, 0, 90, 90); # called in main thread, but it must target frame 2
wl_surface_attach(surface, buffer with size 100x100, 0, 0); # called in render thread
wl_surface_commit(surface); # called in render thread
frame 2:
wl_surface_attach(surface, buffer with size 90x90, 0, 0); # called in render thread
wl_surface_commit(surface); # called in render thread
Some state that has to be applied in frame 2 is applied in frame 1 instead. This happens because QtWayland sets new state as soon as the GUI thread changes it without properly synchronizing with the render thread.
For example, QtWayland calls xdg_surface_set_window_geometry(xdg_surface, 0, 0, 90, 90) as soon as it processes the corresponding QWindow::setGeometry() call in the GUI thread, but it should wait until the render thread is done rendering.
Potential solutions
- block QWindow::setGeometry() and similar functions until the qtquick thread has finished rendering. Not ideal because it's going to block the GUI thread more than it is currently
- keep a tab on dirty state and flush it when starting to paint. This approach is taken in this path. QWaylandWindow maintains pending state which is updated by QWindow::setGeometry(), QWindow::setMinimumSize(), etc and it is flushed when Qt starts painting the window
- perhaps there are other solutions?