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

One render thread per window in Qt Quick

    XMLWordPrintable

Details

    • 906d5c5c40183468f9521277c6244a6c46730de6

    Description

      When multiple windows are being displayed in Qt Quick, they are being rendered in sequence. Either on the scene graph rendering thread or on the GUI thread when threaded rendering is enabled. All windows share the same OpenGL context.

      On platforms that queue up buffers and block on a full pipeline, this works fine. However, these setups are few in practice.

      • Mac OS X: Top-level windows become non-vsynced because we're switching render target all the time. Subwindows are vsync locked and we end up with a maximum framerate of 60/WindowCount.
      • X11: Many drivers seem to block on swap, meaning we end up with a max framerate of 60/WindowCount.
      • Windows: We use GUI thread rendering as ANGLE does not support threaded rendering and DesktopGL spins at 100% when using the threaded renderer (though no actual problems are visible).
      • Embedded / EglFS: Only single-window makes sense. (https://codereview.qt-project.org/#change,66706) would bring multi-window support to Qt Quick, but it will have problems with multiple render threads.
      • Android: Only single-window makes sense, multi-window situation unknown.
      • iOS: Only single-window makes sense, multi-window situation unknown.

      Also:

      • By rendering multiple surfaces with the same OpenGL context, we end up with doing QOpenGLContext::makeCurrent() again and again on alternating surfaces. This call is VERY expensive on some platforms. Having one QOpenGLContext per window, each rendering in a separate thread is the only way to fix this issue.
      • Mac OS fails to vsync windows when we make the same GL context current on multiple surfaces within one vsync interval. Again, only workable solution is one thread and one OpenGL context per window.

      Animations

      The animation system is global on the GUI thread, meaning that once it ticks it does so regardless of which window an item is in. Syncing this up with vsync'ed animations driven by one or more windows running vsynced is not straight-forward.

      • The rendering stack does not know which windows are animating
      • Windows can be on multiple screens with different vsync intervals (though no platform seems to support this in a sensible manner. Secondary screens on Mac OS will tear as they are "synced" to the primary screen)
      • All the various vsyncs of all animating windows need to be cooked down to a single "advance animations" on the GUI thread.
        As a perfect combination of all these does not seem feasible, we go for a slightly less complex, but more doable approach:
      • One option is to stick to vsync animations only when we have one and only one window. Decently behaving apps rarely use secondary UI windows anyway, so this will make it perfect for the common case. When no windows or more than two windows are showing, we animate with a timer. The Render Thread animation system will stick tick vsync-based of course.
      • We pick a "primary animation window", most likely the "focusWindow" when the app is active and drive all animations based on this window's vsync. The primary animation window will have to be redrawn with vsync and send "ticks" back to the GUI thread as long as there are animations in ANY other window, even if it, itself, is idle. If the primary animation window has complex graphics, the entire app might deteriorate. Then again, graphics is never the real bottleneck, so chance of this happening is only slight.

      Resource Sharing

      We actually don't want resources sharing between the rendering contexts... Why you ask?

      • Sharing textures will lead to texture state fighting, especially in the texture atlas. To avoid this we would need to lock down the actual rendering part of the renderer (the part where it binds textures and issues glDraw calls). This still would not prevent accidental blocks and/or texture deep copies when textures are bound/used in one thread while at the same time being updated in another thread.
      • The font system is heavily thread-local and updating it to work across multiple threads with caching and all will be non-trivial. The cost of having an extra cache per window is considered acceptable. Generating glyphs on desktop (using Qt.NativeRendering) is fast and the caches are generally quite small. When Qt IS the platform, glyphs should be system-wide and sharing is done on the EGL level and GL context sharing is not needed.
      • Theming resources on platforms where Qt IS the platform should be shared on the EGL level and be process wide, hence these are shared anyway.
      • QtQuick Controls will typically use one unique style item instance per item which means controls in one window will not be able to share textures with controls in another window.

      There is one usecase where context sharing would be required, though... Say that an application uses multiple QQuickWindows and each of them render different angles of the same OpenGL scene where the OpenGL scene is rendered in beforeRendering. In this case, the windows would have to share memory space to avoid duplicating the huge amount of VBO and texture data being used by the raw OpenGL code. One might argue that this usecase is a bit far fetched though, but if needed, we could solve this by adding a QQuickWindow::setShareContext(QOpenGLContext *) or something which all the other contexts would share with. the scene graph would still not share resources, but it makes it possible for the app to share its resources between windows.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            sletta Gunnar Sletta
            sletta Gunnar Sletta
            Votes:
            0 Vote for this issue
            Watchers:
            9 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes