Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-116982

Resizing QtQuick windows on Wayland is glitchy

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P3: Somewhat important
    • None
    • 6.5
    • QPA: Wayland
    • None
    • Linux/Wayland

    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?

      Attachments

        1. 20230912_090337.mp4
          27.45 MB
        2. test.qml
          0.1 kB
        For Gerrit Dashboard: QTBUG-116982
        # Subject Branch Project Status CR V

        Activity

          People

            qt.team.graphics.and.multimedia Qt Graphics Team
            zzag Vlad Zahorodnii
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews