1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
5\title Qt Quick Scene Graph
6\page qtquick-visualcanvas-scenegraph.html
8\section1 The Scene Graph in Qt Quick
10Qt Quick 2 makes use of a dedicated scene graph that is then traversed and
11rendered via a graphics API such as OpenGL ES, OpenGL, Vulkan, Metal, or Direct
123D. Using a scene graph for graphics rather than the traditional imperative
13painting systems (QPainter and similar), means the scene to be rendered can be
14retained between frames and the complete set of primitives to render is known
15before rendering starts. This opens up for a number of optimizations, such as
16batch rendering to minimize state changes and discarding obscured primitives.
18For example, say a user-interface contains a list of ten items
19where each item has a background color, an icon and a text. Using the
20traditional drawing techniques, this would result in 30 draw calls and
21a similar amount of state changes. A scene graph, on the other hand,
22could reorganize the primitives to render such that all backgrounds
23are drawn in one call, then all icons, then all the text, reducing the
24total amount of draw calls to only 3. Batching and state change
25reduction like this can greatly improve performance on some hardware.
27The scene graph is closely tied to Qt Quick 2.0 and can not be used
28stand-alone. The scene graph is managed and rendered by the
29QQuickWindow class and custom Item types can add their graphical
30primitives into the scene graph through a call to
31QQuickItem::updatePaintNode().
33The scene graph is a graphical representation of the Item scene, an
34independent structure that contains enough information to render all
35the items. Once it has been set up, it can be manipulated and rendered
36independently of the state of the items. On many platforms, the scene
37graph will even be rendered on a dedicated render thread while the GUI
38thread is preparing the next frame's state.
40\note Much of the information listed on this page is specific to the built-in,
41default behavior of the Qt Quick Scene graph. When using an alternative scene
42graph adaptation, such as, the \c software adaptation, not all concepts may
43apply. For more information about the different scene graph adaptations see
44\l{qtquick-visualcanvas-adaptations.html}{Scene Graph Adaptations}.
47\section1 Qt Quick Scene Graph Structure
49The scene graph is composed of a number of predefined node types, each
50serving a dedicated purpose. Although we refer to it as a scene graph,
51a more precise definition is node tree. The tree is built from
52QQuickItem types in the QML scene and internally the scene is then
53processed by a renderer which draws the scene. The nodes themselves do
54\b not contain any active drawing code nor virtual \c paint()
57Even though the node tree is mostly built internally by the existing
58Qt Quick QML types, it is possible for users to also add complete
59subtrees with their own content, including subtrees that represent 3D
65The most important node for users is the \l QSGGeometryNode. It is
66used to define custom graphics by defining its geometry and
67material. The geometry is defined using \l QSGGeometry and describes
68the shape or mesh of the graphical primitive. It can be a line, a
69rectangle, a polygon, many disconnected rectangles, or complex 3D
70mesh. The material defines how the pixels in this shape are filled.
72A node can have any number of children and geometry nodes will be
73rendered so they appear in child-order with parents behind their
74children. \note This does not say anything about the actual rendering
75order in the renderer. Only the visual output is guaranteed.
77The available nodes are:
78\annotatedlist{qtquick-scenegraph-nodes}
80Custom nodes are added to the scene graph by subclassing
81QQuickItem::updatePaintNode() and setting the
82\l {QQuickItem::ItemHasContents} flag.
84\warning It is crucial that native graphics (OpenGL, Vulkan, Metal, etc.)
85operations and interaction with the scene graph happens exclusively on the
86render thread, primarily during the updatePaintNode() call. The rule of thumb
87is to only use classes with the "QSG" prefix inside the
88QQuickItem::updatePaintNode() function.
90For more details, see the \l {Scene Graph - Custom Geometry}.
92\section3 Preprocessing
94Nodes have a virtual QSGNode::preprocess() function, which will be
95called before the scene graph is rendered. Node subclasses can set the
96flag \l QSGNode::UsePreprocess and override the QSGNode::preprocess()
97function to do final preparation of their node. For example, dividing a
98bezier curve into the correct level of detail for the current scale
99factor or updating a section of a texture.
101\section3 Node Ownership
103Ownership of the nodes is either done explicitly by the creator or by
104the scene graph by setting the flag \l QSGNode::OwnedByParent.
105Assigning ownership to the scene graph is often preferable as it
106simplifies cleanup when the scene graph lives outside the GUI thread.
111The material describes how the interior of a geometry in a \l QSGGeometryNode
112is filled. It encapsulates graphics shaders for the vertex and fragment stages
113of the graphics pipeline and provides ample flexibility in what can be
114achieved, though most of the Qt Quick items themselves only use very basic
115materials, such as solid color and texture fills.
117For users who just want to apply custom shading to a QML Item type,
118it is possible to do this directly in QML using the \l ShaderEffect
121Below is a complete list of material classes:
122\annotatedlist{qtquick-scenegraph-materials}
124\section2 Convenience Nodes
126The scene graph API is low-level and focuses on performance rather than
127convenience. Writing custom geometries and materials from scratch, even the
128most basic ones, requires a non-trivial amount of code. For this reason, the
129API includes a few convenience classes to make the most common custom nodes
133\li \l QSGSimpleRectNode - a QSGGeometryNode subclass which defines a
134rectangular geometry with a solid color material.
136\li \l QSGSimpleTextureNode - a QSGGeometryNode subclass which defines
137a rectangular geometry with a texture material.
142\section1 Scene Graph and Rendering
144The rendering of the scene graph happens internally in the QQuickWindow class,
145and there is no public API to access it. There are, however, a few places in
146the rendering pipeline where the user can attach application code. This can be
147used to add custom scene graph content or to insert arbitrary rendering
148commands by directly calling the graphics API (OpenGL, Vulkan, Metal, etc.)
149that is in use by the scene graph. The integration points are defined by the
152For detailed description of how the scene graph renderer works, see \l {Qt
153Quick Scene Graph Default Renderer}.
155There are two render loop variants available: \c basic, and \c threaded.
156\c basic is single-threaded, while \c threaded performs scene graph rendering on a
157dedicated thread. Qt attempts to choose a suitable loop based on the platform
158and possibly the graphics drivers in use. When this is not satisfactory, or for
159testing purposes, the environment variable \c QSG_RENDER_LOOP can be used to
160force the usage of a given loop. To verify which render loop is in use, enable
161the \c qt.scenegraph.general \l {QLoggingCategory}{logging category}.
163\section2 Threaded Render Loop ('threaded')
164\target threaded_render_loop
166On many configurations, the scene graph rendering will happen on a
167dedicated render thread. This is done to increase parallelism of
168multi-core processors and make better use of stall times such as
169waiting for a blocking swap buffer call. This offers significant
170performance improvements, but imposes certain restrictions on where
171and when interaction with the scene graph can happen.
173The following is a simple outline of how a frame gets rendered with the
174threaded render loop and OpenGL. The steps are the same with other graphics
175APIs as well, apart from the OpenGL context specifics.
177\image sg-renderloop-threaded.png
181\li A change occurs in the QML scene, causing \c QQuickItem::update()
182to be called. This can be the result of for instance an animation or
183user input. An event is posted to the render thread to initiate a new
186\li The render thread prepares to draw a new frame and initiates a block on the
189\li While the render thread is preparing the new frame, the GUI thread
190calls QQuickItem::updatePolish() to do final touch-up of items before
193\li GUI thread is blocked.
195\li The QQuickWindow::beforeSynchronizing() signal is emitted.
196Applications can make direct connections (using Qt::DirectConnection)
197to this signal to do any preparation required before calls to
198QQuickItem::updatePaintNode().
200\li Synchronization of the QML state into the scene graph. This is
201done by calling the QQuickItem::updatePaintNode() function on all
202items that have changed since the previous frame. This is the only
203time the QML items and the nodes in the scene graph interact.
205\li GUI thread block is released.
207\li The scene graph is rendered:
210 \li The QQuickWindow::beforeRendering() signal is emitted. Applications can
211 make direct connections (using Qt::DirectConnection) to this signal to use
212 custom graphics API calls which will then stack visually beneath the QML
215 \li Items that have specified QSGNode::UsePreprocess, will have their
216 QSGNode::preprocess() function invoked.
218 \li The renderer processes the nodes.
220 \li The renderer generates states and records draw calls for the graphics
223 \li The QQuickWindow::afterRendering() signal is emitted. Applications can
224 make direct connections (using Qt::DirectConnection) to this signal to
225 issue custom graphics API calls which will then stack visually over the QML
228 \li The frame is now ready. The buffers are swapped (OpenGL), or a present
229 command is recorded and the command buffers are submitted to a graphics
230 queue (Vulkan, Metal). QQuickWindow::frameSwapped() is emitted.
234\li While the render thread is rendering, the GUI is free to advance
235animations, process events, etc.
239The threaded renderer is currently used by default on Windows with
240Direct3D 11 and with OpenGL when using opengl32.dll, Linux excluding
241Mesa llvmpipe, \macos with Metal, mobile platforms, and Embedded Linux
242with EGLFS, and with Vulkan regardless of the platform. All this may
243change in future releases. It is always possible to force use of the
244threaded renderer by setting \c {QSG_RENDER_LOOP=threaded} in the
247\section2 Non-threaded Render Loop ('basic')
249The non-threaded render loop is currently used by default on Windows with
250OpenGL when not using the system's standard opengl32.dll, \macos with OpenGL,
251and Linux with some drivers. For the latter this is mostly a precautionary
252measure, as not all combinations of OpenGL drivers and windowing systems have
255On macOS and OpenGL, the threaded render loop is not supported when building
256with XCode 10 (10.14 SDK) or later, since this opts in to layer-backed views on
257macOS 10.14. You can build with Xcode 9 (10.13 SDK) to opt out of
258layer-backing, in which case the threaded render loop is available and used by
259default. There is no such restriction with Metal.
261Even when using the non-threaded render loop, you should write your code as if
262you are using the threaded renderer, as failing to do so will make the code
265The following is a simplified illustration of the frame rendering sequence in
266the non-threaded renderer.
268\image sg-renderloop-singlethreaded.png
271\section2 Driving Animations
273\section3 What does \c{Advance Animations} refer to in the above diagrams?
275By default, a Qt Quick animation (such, as a \l NumberAnimation) is driven by
276the default animation driver. This relies on basic system timers, such as
277QObject::startTimer(). The timer typically runs with an interval of 16
278milliseconds. While this will never be fully accurate and also depends on the
279accuracy of timers in the underlying platform, it has the benefit of being
280independent of the rendering. It provides uniform results regardless of the
281display refresh rate and if synchronization to the display's vertical sync is
282active or not. This is how animations work with the \c basic render loop.
284In order to provide more accurate results with less stutter on-screen,
285independent of the render loop design (be it single threaded or multiple
286threads) a render loop may decide to install its own custom animation driver,
287and take the operation of \c advancing it into its own hands, without relying
290This is what the \c threaded render loop implements. In fact, it installs not
291one, but two animation drivers: one on the gui thread (to drive regular
292animations, such as \l NumberAnimation), and one on the render thread (to drive
293render thread animations, i.e. the \l Animator types, such as \l
294OpacityAnimator or \l XAnimator). Both of these are advanced during the
295preparation of a frame, i.e. animations are now synchronized with rendering.
296This makes sense due to presentation being throttled to the display's vertical
297sync by the underlying graphics stack.
299Therefore, in the diagram for the \c threaded render loop above, there is an
300explicit \c{Advance animations} step on both threads. For the render thread,
301this is trivial: as the thread is being throttled to vsync, advancing
302animations (for \l Animator types) in each frame as if 16.67 milliseconds had
303elapsed gives more accurate results than relying on a system timer. (when
304throttled to the vsync timing, which is \c{1000/60} milliseconds with a 60 Hz
305refresh rate, it is fair to assume that it has been approximately that long
306since the same operation was done for the previous frame)
308The same approach works for animations on the gui (main) thread too: due to the
309essential synchronization of data between the gui and render threads, the gui
310thread is effectively throttled to the same rate as the render thread, while
311still having the benefit of having less work to do, leaving more headroom for
312the application logic since much of the rendering preparations are now
313offloaded to the render thread.
315While the above examples used 60 frames per second, Qt Quick is prepared for
316other refresh rates as well: the rate is queried from the QScreen and the
317platform. For example, with a 144 Hz screen the interval is 6.94 ms. At the
318same time this is exactly what can cause trouble if vsync-based throttling is
319not functioning as expected, because if what the render loop thinks is
320happening is not matching reality, incorrect animation pacing will occur.
322\note Starting from Qt 6.5, the threaded render loop offers the possibility of
323opting in to another animation driver, based solely on the elapsed time
324(QElapsedTimer). To enable this, set the \c{QSG_USE_SIMPLE_ANIMATION_DRIVER}
325environment variable to a non-zero value. This has the benefits of not needing
326any of the infrastructure for falling back to a QTimer when there are multiple
327windows, not needing heuristics trying determine if vsync-based throttling is
328missing or broken, being compatible with any kind of temporal drifts in vsync
329throttling, and not being tied to the primary screen's refresh rate, thus
330potentially working better in multi-screen setups. It also drives render
331thread animations (the \l Animator types) correctly even if vsync-based
332throttling is broken or disabled. On the other hand, animations may be
333perceived as less smooth with this approach. With compatibility in mind, it is
334offered as an opt-in feature at the moment.
336In summary, the \c threaded render loop is expected to provide smoother
337animations with less stutter as long as the following conditions are met:
341\li There is exactly one window (as in QQuickWindow) on-screen.
343\li VSync-based throttling works as expected with the underyling graphics and
348\section3 What if there is no or more than one window visible?
350When there is no renderable window, for example because our QQuickWindow is
351minimized (Windows) or fully obscured (macOS), we cannot present frames, thus
352cannot rely on the thread "working" in lockstep with the screen refresh rate.
353In this case, the \c threaded render loop automatically switches over to a
354system timer based approach to drive animations, i.e. temporarily switching
355over to the mechanism the \c basic loop would use.
357The same is true when there are more than one QQuickWindow instances on-screen.
358The model presented above for advancing animations on the gui thread, enabled
359by its synchronization with the render thread, is not satisfactory anymore, as
360there are now multiple sync points with multiple render threads. (one per
361window.) Here falling back to the system timer based approach becomes necessary
362as well, because how long and often the gui thread will block is now dependent
363on a number of factors, including the content in the windows (are they
364animating? how often are they updating?) and the graphics stack behavior (how
365exactly does it handle two or more threads presenting with wait-for-vsync?). As
366we cannot guarantee being throttled to the presentation rate of the window
367(which window would that be, to begin with?) in a stable, cross-platform
368manner, advancing animations cannot be based on the rendering.
370This switch of animation handling mechanisms is transparent to the
373\section3 What if vsync-based throttling is disfunctional, globally disabled, or the application disabled it itself?
375The \c threaded render loop relies on the graphics API implementation and/or
376the windowing system for throttling, for example, by requesting a swap interval
377of 1 in case of OpenGL (GLX, EGL, WGL), calling Present() with an interval of 1
378for Direct 3D, or using the presentation mode \c FIFO with Vulkan.
380Some graphics drivers allow users to override this setting and turn it off,
381ignoring Qt's request. An example of this would be a system wide control panel
382of the graphics driver that allows overriding the application's settings with
383regards to vsync. It can also happen that a graphics stack is unable to provide
384proper vsync-based throttling, which can be the case in some virtual machines
385(mainly due to using a software rasterization based implementation of OpenGL or
388Without blocking in the swap/present operation (or some other graphics
389operation), such a render loop would advance animations too fast. This would be
390no issue with the \c basic render loop, because that always relies on system
391timers. With \c threaded, the behavior can vary based on the Qt version:
395\li If a system is known to be unable to provide vsync-based throttling, the
396only option before Qt 6.4 was to use the \c basic render loop, by manually
397setting \c {QSG_RENDER_LOOP=basic} in the environment before running the
400\li Starting with Qt 6.4, setting either the \c{QSG_NO_VSYNC} environment
401variable to a non-zero value, or the window's QSurfaceFormat::swapInterval() to
402\c 0 can both alleviate the problem as well: by explicitly requesting disabling
403vsync-based blocking, regardless of the request having any effect in practice,
404the \c threaded render loop can by extension recognize that relying on vsync to
405drive animations is futile, and it will fall back to using system timers, just
406as it would for more than one window.
408\li Even better, starting from Qt 6.4 the scenegraph also attempts to recognize
409using some simple heuristics that the frames are being presented "too fast",
410and automatically switch over to system timers if seen necessary. This means
411that in most cases there will be no need to do anything and applications will
412run animations as expected even when the default render loop is the \c threaded
413one. While this is transparent to applications, for troubleshooting and
414development purposes it is useful to know that this is logged with a \c{"Window
4150x7ffc8489c3d0 is determined to have broken vsync throttling ..."} message
416printed when \c{QSG_INFO} or \c{qt.scenegraph.general} is enabled. This method
417has the downside of activating only after a small set of frames, given that it
418first needs to collect data to evaluate, meaning that when opening a
419QQuickWindow the application may still show overly fast animations for a short
420period of time. Additionally, it may not capture all possible vsync-broken
425Remember however, that by design none of this helps render thread animations
426(the \l Animator types). In the absence of vsync-based blocking,
427\l{Animator}{animators} will advance incorrectly by default, faster than
428expected, even when the workarounds are activated for regular
429\l{Animation}{animations}. If this becomes an issue, consider using the
430alternative animation driver by setting \c{QSG_USE_SIMPLE_ANIMATION_DRIVER}.
432\note Be aware that the rendering loop logic and event processing on the GUI
433(main) thread is not necessarily unthrottled even if waiting for vsync is
434disabled: both render loops schedule updates for windows via
435QWindow::requestUpdate(). This is backed by a 5 ms GUI thread timer on most
436platforms, in order to give time for event processing. On some platforms, e.g.
437macOS, it is using platform-specific APIs (such as, CVDisplayLink) to get
438notified about the appropriate time to prepare a new frame, likely tied to the
439display's vsync in some form. This can be relevant in benchmarking and similar
440situations. For applications and tools attempting to perform low-level
441benchmarking it may be beneficial to set the \c{QT_QPA_UPDATE_IDLE_TIME}
442environment variable to \c 0 in order to potentially reduce idle time on the
443GUI thread. For normal application usage the defaults should, in most cases, be
446\note When in doubt, enable the \c {qt.scenegraph.general} and \c
447{qt.scenegraph.time.renderloop} logging categories for troubleshooting, as
448these may reveal some clues as to why rendering and animations are not running
452\section2 Custom control over rendering with QQuickRenderControl
454When using QQuickRenderControl, the responsibility for driving the
455rendering loop is transferred to the application. In this case no
456built-in render loop is used. Instead, it is up to the application to
457invoke the polish, synchronize and rendering steps at the appropriate
458time. It is possible to implement either a threaded or non-threaded
459behavior similar to the ones shown above.
461Additionally, applications may wish to implement and install their own
462QAnimationDriver in combination with QQuickRenderControl. This gives full
463control over driving Qt Quick animations, which can be particularly important
464for content that is not shown on screen, bearing no relation to the
465presentation rate simply because there is no presenting of the frame happening.
466This is optional, by default animations will advance based on the system timer.
469\section2 Extending the Scene Graph with QRhi-based and native 3D rendering
471The scene graph offers three methods for integrating application-provided
476\li Issuing either \l{QRhi}-based or OpenGL, Vulkan, Metal, Direct3D commands
477directly before or after the scene graph's own rendering. This in effect
478prepends or appends a set of draw calls into the main render pass. No additional
479render target is used.
481\li Rendering to a texture and creating a textured node in the scene graph. This
482involves an additional render pass and render target.
484\li Issuing draw calls inline with the scene graph's own rendering by
485instantiating a QSGRenderNode subclass in the scene graph. This is similar to
486the first approach but the custom draw calls are effectively injected into the
487scene graph's command stream.
491\section3 Underlay/overlay mode
493By connecting to the \l QQuickWindow::beforeRendering() and \l
494QQuickWindow::afterRendering() signals, applications can make \l QRhi or native
4953D API calls directly into the same context as the scene graph is rendering to.
496With APIs like Vulkan or Metal, applications can query native objects, such as,
497the scene graph's command buffer, via QSGRendererInterface, and record commands
498to it as they see fit. As the signal names indicate, the user can then render
499content either under a Qt Quick scene or over it. The benefit of integrating in
500this manner is that no extra render targets are needed to perform the rendering,
501and a possibly expensive texturing step is eliminated. The downside is that the
502custom rendering can only be issued either at the beginning or at the end of Qt
503Quick's own rendering. Using QSGRenderNode instead of the QQuickWindow signals
504can lift that restriction somewhat, but in either case care must be taken when
505it comes to 3D content and depth buffer usage since relying on depth testing and
506rendering with depth write enabled can easily create situations where the custom
507content and the Qt Quick content's depth buffer usage conflict with each other.
509From Qt 6.6 the \l QRhi APIs are considered semi-public, i.e. offered to the
510applications and documented, albeit with a limited compatibility guarantee. This
511allows creating portable, cross-platform 2D/3D rendering code by using the same
512graphics and shader abstractions the scene graph itself uses.
514The \l {Scene Graph - RHI Under QML} example gives an example on how to
515implement the underlay/overlay approach using \l QRhi.
517The \l {Scene Graph - OpenGL Under QML} example gives an example on
518how to use these signals using OpenGL.
520The \l {Scene Graph - Direct3D 11 Under QML} example gives an example on
521how to use these signals using Direct3D.
523The \l {Scene Graph - Metal Under QML} example gives an example on
524how to use these signals using Metal.
526The \l {Scene Graph - Vulkan Under QML} example gives an example on
527how to use these signals using Vulkan.
529Starting with Qt 6.0, direct usage of the underlying graphics API must be
530enclosed by a call to \l QQuickWindow::beginExternalCommands() and \l
531QQuickWindow::endExternalCommands(). This concept may be familiar from \l
532QPainter::beginNativePainting(), and serves a similar purpose: it allows the Qt
533Quick Scene Graph to recognize that any cached state and assumptions about the
534state within the currently recorded render pass, if there is one, are now
535invalid, because the application code may have altered it by working directly
536with the underlying graphics API. This is not applicable and necessary when
539When mixing custom OpenGL rendering with the scene graph, it is important the
540application does not leave the OpenGL context in a state with buffers bound,
541attributes enabled, special values in the z-buffer or stencil-buffer or similar.
542Doing so can result in unpredictable behavior.
544The custom rendering code must be thread aware in the sense that it should not
545assume being executed on the GUI (main) thread of the application. When
546connecting to the \l QQuickWindow signals, the application should use
547Qt::DirectConnection and understand that the connected slots are invoked on the
548scene graph's dedicated render thread, if there is one.
550\section3 The texture-based approach
552The texture-based alternative is the most flexible approach when the application
553needs to have a "flattened", 2D image of some custom 3D rendering within the Qt
554Quick scene. This also allows using a dedicated depth/stencil buffer that is
555independent of the buffers used by the main render pass.
557When using OpenGL, the legacy convenience class QQuickFramebufferObject can be
558used to achieve this. QRhi-based custom renderers and graphics APIs other than
559OpenGL can also follow this approach, even though QQuickFramebufferObject does
560not currently support them. Creating and rendering to a texture directly with
561the underlying API, followed by wrapping and using this resource in a Qt Quick
562scene in a custom QQuickItem, is demonstrated in the following examples:
564\l {Scene Graph - RHI Texture Item} example.
566\l {Scene Graph - Vulkan Texture Import} example.
568\l {Scene Graph - Metal Texture Import} example.
570\section3 The inline approach
572Using \l QSGRenderNode the custom draw calls are injected not at the beginning
573or the end of the recording of the scene graph's render pass, but rather during
574the scene graph's rendering process. This is achieved by creating a custom \l
575QQuickItem based by an instance of \l QSGRenderNode, a scene graph node that
576exists specifically to allow issuing graphics commands either via \l QRhi or a
577native 3D API such as OpenGL, Vulkan, Metal, or Direct 3D.
579The \l {Scene Graph - Custom QSGRenderNode} example gives a demonstration of
582\section2 Custom Items using QPainter
584The QQuickItem provides a subclass, QQuickPaintedItem, which allows
585the users to render content using QPainter.
587\warning Using QQuickPaintedItem uses an indirect 2D surface to render
588its content, either using software rasterization or using an OpenGL
589framebuffer object (FBO), so the rendering is a two-step
590operation. First rasterize the surface, then draw the surface. Using
591scene graph API directly is always significantly faster.
593\section1 Logging Support
595The scene graph has support for a number of logging categories. These
596can be useful in tracking down both performance issues and bugs in
597addition to being helpful to Qt contributors.
601\li \c {qt.scenegraph.time.texture} - logs the time spent doing texture uploads
603\li \c {qt.scenegraph.time.compilation} - logs the time spent doing shader compilation
605\li \c {qt.scenegraph.time.renderer} - logs the time spent in the various steps of the renderer
607\li \c {qt.scenegraph.time.renderloop} - logs the time spent in the various
608steps of the render loop. With the \c threaded render loop this gives an
609insight into the time elapsed between the various frame preparation steps both
610on the GUI and the render thread. It can therefore also be a useful
611troubleshooting tool, for example, to confirm how vsync-based throttling and
612other low-level Qt enablers, such as QWindow::requestUpdate(), affect the
613rendering and presentation pipeline.
615\li \c {qt.scenegraph.time.glyph} - logs the time spent preparing distance field glyphs
617\li \c {qt.scenegraph.general} - logs general information about various parts of the scene graph and the graphics stack
619\li \c {qt.scenegraph.renderloop} - creates a detailed log of the various stages involved in rendering. This log mode is primarily useful for developers working on Qt.
623The legacy \c{QSG_INFO} environment variable is also available. Setting it to a
624non-zero value enables the \c{qt.scenegraph.general} category.
626\note When encountering graphics problems, or when in doubt which render loop
627or graphics API is in use, always start the application with at least
628\c{qt.scenegraph.general} and \c{qt.rhi.*} enabled, or \c{QSG_INFO=1} set. This
629will then print some essential information onto the debug output during
632\section1 Scene Graph Backend
634In addition to the public API, the scene graph has an adaptation layer
635which opens up the implementation to do hardware specific
636adaptations. This is an undocumented, internal and private plugin API,
637which lets hardware adaptation teams make the most of their hardware.
642\li Custom textures; specifically the implementation of
643QQuickWindow::createTextureFromImage and the internal representation
644of the texture used by \l Image and \l BorderImage types.
646\li Custom renderer; the adaptation layer lets the plugin decide how
647the scene graph is traversed and rendered, making it possible to
648optimize the rendering algorithm for a specific hardware or to make
649use of extensions which improve performance.
651\li Custom scene graph implementation of many of the default QML
652types, including its text and font rendering.
654\li Custom animation driver; allows the animation system to hook
655into the low-level display vertical refresh to get smooth rendering.
657\li Custom render loop; allows better control over how QML deals
658with multiple windows.
665 \title Qt Quick Scene Graph Default Renderer
666 \page qtquick-visualcanvas-scenegraph-renderer.html
668 This document explains how the default scene graph renderer works internally,
669 so that one can write code that uses it in an optimal fashion, both
670 performance and feature-wise.
672 One does not need to understand the internals of the renderer to get
673 good performance. However, it might help when integrating with the
674 scene graph or to figure out why it is not possible to squeeze the
675 maximum efficiency out of the graphics chip.
677 \note Even in the case where every frame is unique and everything is
678 uploaded from scratch, the default renderer will perform well.
680 The Qt Quick items in a QML scene populate a tree of QSGNode
681 instances. Once created, this tree is a complete description of how
682 a certain frame should be rendered. It does not contain any
683 references back to the Qt Quick items at all and will on most
684 platforms be processed and rendered in a separate thread. The
685 renderer is a self contained part of the scene graph which traverses
686 the QSGNode tree and uses geometry defined in QSGGeometryNode and
687 shader state defined in QSGMaterial to update the graphics state and
690 If needed, the renderer can be completely replaced using the
691 internal scene graph back-end API. This is mostly interesting for
692 platform vendors who wish to take advantage of non-standard hardware
693 features. For the majority of use cases, the default renderer will be
696 The default renderer focuses on two primary strategies to optimize
697 the rendering: Batching of draw calls, and retention of geometry on
702 Whereas a traditional 2D API, such as QPainter, Cairo or Context2D, is
703 written to handle thousands of individual draw calls per frame, OpenGL and
704 other hardware accelerated APIs perform best when the number of draw calls is
705 very low and state changes are kept to a minimum.
707 \note While \c OpenGL is used as an example in the following sections, the
708 same concepts apply to other graphics APIs as well.
710 Consider the following use case:
712 \image visualcanvas_list.png
714 The simplest way of drawing this list is on a cell-by-cell basis. First,
715 the background is drawn. This is a rectangle of a specific color. In
716 OpenGL terms this means selecting a shader program to do solid color
717 fills, setting up the fill color, setting the transformation matrix
718 containing the x and y offsets and then using for instance
719 \c glDrawArrays to draw two triangles making up the rectangle. The icon
720 is drawn next. In OpenGL terms this means selecting a shader program
721 to draw textures, selecting the active texture to use, setting the
722 transformation matrix, enabling alpha-blending and then using for
723 instance \c glDrawArrays to draw the two triangles making up the
724 bounding rectangle of the icon. The text and separator line between
725 cells follow a similar pattern. And this process is repeated for
726 every cell in the list, so for a longer list, the overhead imposed
727 by OpenGL state changes and draw calls completely outweighs the
728 benefit that using a hardware accelerated API could provide.
730 When each primitive is large, this overhead is negligible, but in
731 the case of a typical UI, there are many small items which add up to
732 a considerable overhead.
734 The default scene graph renderer works within these
735 limitations and will try to merge individual primitives together
736 into batches while preserving the exact same visual result. The
737 result is fewer OpenGL state changes and a minimal amount of draw
738 calls, resulting in optimal performance.
740 \section2 Opaque Primitives
742 The renderer separates between opaque primitives and primitives
743 which require alpha blending. By using OpenGL's Z-buffer and giving
744 each primitive a unique z position, the renderer can freely reorder
745 opaque primitives without any regard for their location on screen
746 and which other elements they overlap with. By looking at each
747 primitive's material state, the renderer will create opaque
748 batches. From Qt Quick core item set, this includes Rectangle items
749 with opaque colors and fully opaque images, such as JPEGs or BMPs.
751 Another benefit of using opaque primitives is that opaque
752 primitives do not require \c GL_BLEND to be enabled, which can be
753 quite costly, especially on mobile and embedded GPUs.
755 Opaque primitives are rendered in a front-to-back manner with
756 \c glDepthMask and \c GL_DEPTH_TEST enabled. On GPUs that internally do
757 early-z checks, this means that the fragment shader does not need to
758 run for pixels or blocks of pixels that are obscured. Beware that
759 the renderer still needs to take these nodes into account and the
760 vertex shader is still run for every vertex in these primitives, so
761 if the application knows that something is fully obscured, the best
762 thing to do is to explicitly hide it using Item::visible or
765 \note The Item::z is used to control an Item's stacking order
766 relative to its siblings. It has no direct relation to the renderer and
769 \section2 Alpha Blended Primitives
771 Once opaque primitives have been drawn, the renderer will disable
772 \c glDepthMask, enable \c GL_BLEND and render all alpha blended primitives
773 in a back-to-front manner.
775 Batching of alpha blended primitives requires a bit more effort in
776 the renderer as elements that are overlapping need to be rendered in
777 the correct order for alpha blending to look correct. Relying on the
778 Z-buffer alone is not enough. The renderer does a pass over all
779 alpha blended primitives and will look at their bounding rect in
780 addition to their material state to figure out which elements can be
781 batched and which can not.
783 \image visualcanvas_overlap.png
785 In the left-most case, the blue backgrounds can be drawn in one call
786 and the two text elements in another call, as the texts only overlap
787 a background which they are stacked in front of. In the right-most
788 case, the background of "Item 4" overlaps the text of "Item 3" so in
789 this case, each of backgrounds and texts needs to be drawn using
792 Z-wise, the alpha primitives are interleaved with the opaque nodes
793 and may trigger early-z when available, but again, setting
794 Item::visible to false is always faster.
796 \section2 Mixing with 3D Primitives
798 The scene graph can support pseudo 3D and proper 3D primitives. For
799 instance, one can implement a "page curl" effect using a
800 ShaderEffect or implement a bumpmapped torus using QSGGeometry and a
801 custom material. While doing so, one needs to take into account that
802 the default renderer already makes use of the depth buffer.
804 The renderer modifies the vertex shader returned from
805 QSGMaterialShader::vertexShader() and compresses the z values of the
806 vertex after the model-view and projection matrices have been applied
807 and then adds a small translation on the z to position it the
810 The compression assumes that the z values are in the range of 0 to
813 \section2 Texture Atlas
815 The active texture is a unique OpenGL state, which means that
816 multiple primitives using different OpenGL textures cannot be
817 batched. The Qt Quick scene graph, for this reason, allows multiple
818 QSGTexture instances to be allocated as smaller sub-regions of a
819 larger texture; a texture atlas.
821 The biggest benefit of texture atlases is that multiple QSGTexture
822 instances now refer to the same OpenGL texture instance. This makes
823 it possible to batch textured draw calls as well, such as Image
824 items, BorderImage items, ShaderEffect items and also C++ types such
825 as QSGSimpleTextureNode and custom QSGGeometryNodes using textures.
827 \note Large textures do not go into the texture atlas.
829 Atlas based textures are created by passing
830 QQuickWindow::TextureCanUseAtlas to the
831 QQuickWindow::createTextureFromImage().
833 \note Atlas based textures do not have texture coordinates ranging
834 from 0 to 1. Use QSGTexture::normalizedTextureSubRect() to get the
835 atlas texture coordinates.
837 The scene graph uses heuristics to figure out how large the atlas
838 should be and what the size threshold for being entered into the
839 atlas is. If different values are needed, it is possible to override
840 them using the environment variables \c {QSG_ATLAS_WIDTH=[width]},
841 \c {QSG_ATLAS_HEIGHT=[height]} and \c
842 {QSG_ATLAS_SIZE_LIMIT=[size]}. Changing these values will mostly be
843 interesting for platform vendors.
845 \section1 Batch Roots
847 In addition to merging compatible primitives into batches, the
848 default renderer also tries to minimize the amount of data that
849 needs to be sent to the GPU for every frame. The default renderer
850 identifies subtrees which belong together and tries to put these
851 into separate batches. Once batches are identified, they are merged,
852 uploaded and stored in GPU memory, using Vertex Buffer Objects.
854 \section2 Transform Nodes
856 Each Qt Quick Item inserts a QSGTransformNode into the scene graph
857 tree to manage its x, y, scale or rotation. Child items will be
858 populated under this transform node. The default renderer tracks
859 the state of transform nodes between frames and will look at
860 subtrees to decide if a transform node is a good candidate to become
861 a root for a set of batches. A transform node which changes between
862 frames and which has a fairly complex subtree can become a batch
865 QSGGeometryNodes in the subtree of a batch root are pre-transformed
866 relative to the root on the CPU. They are then uploaded and retained
867 on the GPU. When the transform changes, the renderer only needs to
868 update the matrix of the root, not each individual item, making list
869 and grid scrolling very fast. For successive frames, as long as
870 nodes are not being added or removed, rendering the list is
871 effectively for free. When new content enters the subtree, the batch
872 that gets it is rebuilt, but this is still relatively fast. There are
873 usually several unchanging frames for every frame with added or
874 removed nodes when panning through a grid or list.
876 Another benefit of identifying transform nodes as batch roots is
877 that it allows the renderer to retain the parts of the tree that have
878 not changed. For instance, say a UI consists of a list and a button
879 row. When the list is being scrolled and delegates are being added
880 and removed, the rest of the UI, the button row, is unchanged and
881 can be drawn using the geometry already stored on the GPU.
883 The node and vertex threshold for a transform node to become a batch
884 root can be overridden using the environment variables \c
885 {QSG_RENDERER_BATCH_NODE_THRESHOLD=[count]} and \c
886 {QSG_RENDERER_BATCH_VERTEX_THRESHOLD=[count]}. Overriding these flags
887 will be mostly useful for platform vendors.
889 \note Beneath a batch root, one batch is created for each unique
890 set of material state and geometry type.
894 When setting Item::clip to true, it will create a QSGClipNode with a
895 rectangle in its geometry. The default renderer will apply this clip
896 by using scissoring in OpenGL. If the item is rotated by a
897 non-90-degree angle, the OpenGL's stencil buffer is used. Qt Quick
898 Item only supports setting a rectangle as clip through QML, but the
899 scene graph API and the default renderer can use any shape for
902 When applying a clip to a subtree, that subtree needs to be rendered
903 with a unique OpenGL state. This means that when Item::clip is true,
904 batching of that item is limited to its children. When there are
905 many children, like a ListView or GridView, or complex children,
906 like a TextArea, this is fine. One should, however, use clip on
907 smaller items with caution as it prevents batching. This includes
908 button label, text field or list delegate and table cells.
909 Clipping a Flickable (or item view) can often be avoided by arranging
910 the UI so that opaque items cover areas around the Flickable, and
911 otherwise relying on the window edges to clip everything else.
913 Setting Item::clip to \c true also sets the \l QQuickItem::ItemIsViewport
914 flag; child items with the \l QQuickItem::ItemObservesViewport flag may
915 use the viewport for a rough pre-clipping step: e.g. \l Text omits
916 lines of text that are completely outside the viewport. Omitting scene
917 graph nodes or limiting the \l {QSGGeometry::vertexCount()}{vertices}
918 is an optimization, which can be achieved by setting the
919 \l {QQuickItem::flags()}{flags} in C++ rather than setting
920 \l Item::clip in QML.
922 When implementing QQuickItem::updatePaintNode() in a custom item,
923 if it can render a lot of details over a large geometric area,
924 you should think about whether it's efficient to limit the graphics
925 to the viewport; if so, you can set the \l {QQuickItem::}
926 {ItemObservesViewport} flag and read the currently exposed area from
927 QQuickItem::clipRect(). One consequence is that updatePaintNode() will be
928 called more often (typically once per frame whenever content is moving in
931 \section2 Vertex Buffers
933 Each batch uses a vertex buffer object (VBO) to store its data on
934 the GPU. This vertex buffer is retained between frames and updated
935 when the part of the scene graph that it represents changes.
937 By default, the renderer will upload data into the VBO using
938 \c GL_STATIC_DRAW. It is possible to select different upload strategy
939 by setting the environment variable \c
940 {QSG_RENDERER_BUFFER_STRATEGY=[strategy]}. Valid values are \c
941 stream and \c dynamic. Changing this value is mostly useful for
944 \section1 Antialiasing
946 The scene graph supports two types of antialiasing. By default, primitives
947 such as rectangles and images will be antialiased by adding more
948 vertices along the edge of the primitives so that the edges fade
949 to transparent. We call this method \e {vertex antialiasing}. If the
950 user requests a multisampled OpenGL context, by setting a QSurfaceFormat
951 with samples greater than \c 0 using QQuickWindow::setFormat(), the
952 scene graph will prefer multisample based antialiasing (MSAA).
953 The two techniques will affect how the rendering happens internally
954 and have different limitations.
956 It is also possible to override the antialiasing method used by
957 setting the environment variable \c {QSG_ANTIALIASING_METHOD}
958 to either \c vertex or \c {msaa}.
960 Vertex antialiasing can produce seams between edges of adjacent
961 primitives, even when the two edges are mathematically the same.
962 Multisample antialiasing does not.
965 \section2 Vertex Antialiasing
967 Vertex antialiasing can be enabled and disabled on a per-item basis
968 using the Item::antialiasing property. It will work regardless of
969 what the underlying hardware supports and produces higher quality
970 antialiasing, both for normally rendered primitives and also for
971 primitives captured into framebuffer objects, for instance using
972 the ShaderEffectSource type.
974 The downside to using vertex antialiasing is that each primitive
975 with antialiasing enabled will have to be blended. In terms of
976 batching, this means that the renderer needs to do more work to
977 figure out if the primitive can be batched or not and due to overlaps
978 with other elements in the scene, it may also result in less batching,
979 which could impact performance.
981 On low-end hardware blending can also be quite expensive so for an
982 image or rounded rectangle that covers most of the screen, the amount
983 of blending needed for the interior of these primitives can result
984 in significant performance loss as the entire primitive must be blended.
986 \section2 Multisample Antialiasing
988 Multisample antialiasing is a hardware feature where the hardware
989 calculates a coverage value per pixel in the primitive. Some hardware
990 can multisample at a very low cost, while other hardware may
991 need both more memory and more GPU cycles to render a frame.
993 Using multisample antialiasing, many primitives, such as rounded
994 rectangles and image elements can be antialiased and still be
995 \e opaque in the scene graph. This means the renderer has an easier
996 job when creating batches and can rely on early-z to avoid overdraw.
998 When multisample antialiasing is used, content rendered into
999 framebuffer objects need additional extensions to support multisampling
1000 of framebuffers. Typically \c GL_EXT_framebuffer_multisample and
1001 \c GL_EXT_framebuffer_blit. Most desktop chips have these extensions
1002 present, but they are less common in embedded chips. When framebuffer
1003 multisampling is not available in the hardware, content rendered into
1004 framebuffer objects will not be antialiased, including the content of
1005 a ShaderEffectSource.
1008 \section1 Performance
1010 As stated in the beginning, understanding the finer details of the
1011 renderer is not required to get good performance. It is written to
1012 optimize for common use cases and will perform quite well under
1013 almost any circumstances.
1017 \li Good performance comes from effective batching, with as little
1018 as possible of the geometry being uploaded again and again. By
1019 setting the environment variable \c {QSG_RENDERER_DEBUG=render}, the
1020 renderer will output statistics on how well the batching goes, how
1021 many batches are used, which batches are retained and which are opaque and
1022 not. When striving for optimal performance, uploads should happen
1023 only when really needed, batches should be fewer than 10 and at
1024 least 3-4 of them should be opaque.
1026 \li The default renderer does not do any CPU-side viewport clipping
1027 nor occlusion detection. If something is not supposed to be visible,
1028 it should not be shown. Use \c {Item::visible: false} for items that
1029 should not be drawn. The primary reason for not adding such logic is
1030 that it adds additional cost which would also hurt applications that
1031 took care in behaving well.
1033 \li Make sure the texture atlas is used. The Image and BorderImage
1034 items will use it unless the image is too large. For textures
1035 created in C++, pass QQuickWindow::TextureCanUseAtlas when
1036 calling QQuickWindow::createTexture().
1037 By setting the environment variable \c {QSG_ATLAS_OVERLAY} all atlas
1038 textures will be colorized so they are easily identifiable in the
1041 \li Use opaque primitives where possible. Opaque primitives are
1042 faster to process in the renderer and faster to draw on the GPU. For
1043 instance, PNG files will often have an alpha channel, even though
1044 each pixel is fully opaque. JPG files are always opaque. When
1045 providing images to a QQuickImageProvider or creating images with
1046 QQuickWindow::createTextureFromImage(), let the image have
1047 QImage::Format_RGB32, when possible.
1049 \li Be aware of that overlapping compound items, like in the
1050 illustration above, cannot be batched.
1052 \li Clipping breaks batching. Never use on a per-item basis, inside
1053 table cells, item delegates or similar. Instead of clipping text,
1054 use eliding. Instead of clipping an image, create a
1055 QQuickImageProvider that returns a cropped image.
1057 \li Batching only works for 16-bit indices. All built-in items use
1058 16-bit indices, but a custom geometry is free to also use 32-bit
1061 \li Some material flags prevent batching, the most limiting one
1062 being QSGMaterial::RequiresFullMatrix which prevents all batching.
1064 \li Applications with a monochrome background should set it using
1065 QQuickWindow::setColor() rather than using a top-level Rectangle item.
1066 QQuickWindow::setColor() will be used in a call to \c glClear(),
1067 which is potentially faster.
1069 \li Mipmapped Image items are not placed in the global atlas and will
1072 \li A bug in the OpenGL driver related to framebuffer object (FBO) readbacks
1073 may corrupt rendered glyphs. If you set the \c QML_USE_GLYPHCACHE_WORKAROUND
1074 environment variable, Qt keeps an additional copy of the glyph in RAM. This
1075 means that performance is slightly lower when drawing glyphs that have not
1076 been drawn before, as Qt accesses the extra copy via the CPU. It also means
1077 that the glyph cache will use twice as much memory. The quality is not
1082 If an application performs poorly, make sure that rendering is
1083 actually the bottleneck. Use a profiler! The environment variable \c
1084 {QSG_RENDER_TIMING=1} will output a number of useful timing
1085 parameters which can be useful in pinpointing where a problem lies.
1087 \section1 Visualizing
1089 To visualize the various aspects of the scene graph's default renderer, the
1090 \c QSG_VISUALIZE environment variable can be set to one of the values
1091 detailed in each section below. We provide examples of the output of
1092 some of the variables using the following QML code:
1108 model: ["Item A", "Item B", "Item C", "Item D"]
1110 delegate: Rectangle {
1117 anchors.fill: parent
1118 horizontalAlignment: Text.AlignHCenter
1119 verticalAlignment: Text.AlignVCenter
1125 id: clippedDelegateList
1126 x: clippedList.x + clippedList.width + 20
1131 model: ["Item A", "Item B", "Item C", "Item D"]
1133 delegate: Rectangle {
1141 anchors.fill: parent
1142 horizontalAlignment: Text.AlignHCenter
1143 verticalAlignment: Text.AlignVCenter
1150 For the ListView on the left, we set its \l {Item::clip}{clip} property to
1151 \c true. For the ListView on right, we also set each delegate's
1152 \l {Item::clip}{clip} property to \c true to illustrate the effects of
1153 clipping on batching.
1155 \image visualize-original.png "Original"
1158 \note The visualized elements do not respect clipping, and rendering order is
1161 \section2 Visualizing Batches
1163 Setting \c QSG_VISUALIZE to \c batches visualizes batches in the renderer.
1164 Merged batches are drawn with a solid color and unmerged batches are drawn
1165 with a diagonal line pattern. Few unique colors means good batching.
1166 Unmerged batches are bad if they contain many individual nodes.
1168 \image visualize-batches.png "batches"
1169 \c QSG_VISUALIZE=batches
1171 \section2 Visualizing Clipping
1173 Setting \c QSG_VISUALIZE to \c clip draws red areas on top of the scene
1174 to indicate clipping. As Qt Quick Items do not clip by default, no clipping
1175 is usually visualized.
1177 \image visualize-clip.png
1178 \c QSG_VISUALIZE=clip
1180 \section2 Visualizing Changes
1182 Setting \c QSG_VISUALIZE to \c changes visualizes changes in the renderer.
1183 Changes in the scenegraph are visualized with a flashing overlay of a random
1184 color. Changes on a primitive are visualized with a solid color, while
1185 changes in an ancestor, such as matrix or opacity changes, are visualized
1188 \section2 Visualizing Overdraw
1190 Setting \c QSG_VISUALIZE to \c overdraw visualizes overdraw in the renderer.
1191 Visualize all items in 3D to highlight overdraws. This mode can also be used
1192 to detect geometry outside the viewport to some extent. Opaque items are
1193 rendered with a green tint, while translucent items are rendered with a red
1194 tint. The bounding box for the viewport is rendered in blue. Opaque content
1195 is easier for the scenegraph to process and is usually faster to render.
1197 Note that the root rectangle in the code above is superfluous as the window
1198 is also white, so drawing the rectangle is a waste of resources in this case.
1199 Changing it to an Item can give a slight performance boost.
1201 \image visualize-overdraw-1.png "overdraw-1"
1202 \image visualize-overdraw-2.png "overdraw-2"
1203 \c QSG_VISUALIZE=overdraw
1205 \section1 Rendering via the Qt Rendering Hardware Interface
1207 From Qt 6.0 onwards, the default adaptation always renders via a graphics
1208 abstraction layer, the Qt Rendering Hardware Interface (RHI), provided by the
1209 \l [QtGui]{Qt GUI} module. This means that, unlike Qt 5, no direct OpenGL calls are made
1210 by the scene graph. Rather, it records resource and draw commands by using the
1211 RHI APIs, which then translate the command stream into OpenGL, Vulkan, Metal,
1212 or Direct 3D calls. Shader handling is also unified by writing shader code
1213 once, compiling to \l{https://www.khronos.org/spir/}{SPIR-V}, and then
1214 translating to the language appropriate for the various graphics APIs.
1216 To control the behavior, the following environment variables can be used:
1220 \li Environment Variable
1225 \li \c QSG_RHI_BACKEND
1226 \li \c vulkan, \c metal, \c opengl, \c d3d11, \c d3d12
1227 \li Requests the specific RHI backend. By default the targeted graphics API
1228 is chosen based on the platform, unless overridden by this variable or the
1229 equivalent C++ APIs. The defaults are currently Direct3D 11 for Windows,
1230 Metal for macOS, OpenGL elsewhere.
1235 \li Like with the OpenGL-based rendering path, setting this enables printing system
1236 information when initializing the Qt Quick scene graph. This can be very useful for
1240 \li \c QSG_RHI_DEBUG_LAYER
1242 \li Where applicable (Vulkan, Direct3D), enables the graphics API implementation's
1243 debug or validation layers, if available, either on the graphics device or the instance
1244 object. For Metal on \macos, set the environment variable
1245 \c{METAL_DEVICE_WRAPPER_TYPE=1} instead.
1248 \li \c QSG_RHI_PREFER_SOFTWARE_RENDERER
1250 \li Requests choosing an adapter or physical device that uses software-based
1251 rasterization. Applicable only when the underlying API has support for
1252 enumerating adapters (for example, Direct3D or Vulkan), and is ignored
1257 Applications wishing to always run with a single given graphics API, can
1258 request this via C++ as well. For example, the following call made early in
1259 main(), before constructing any QQuickWindow, forces the use of Vulkan (and
1260 will fail otherwise):
1263 QQuickWindow::setGraphicsApi(QSGRendererInterface::Vulkan);
1266 See QSGRendererInterface::GraphicsApi. The enum values \c OpenGL, \c Vulkan,
1267 \c Metal, \c Direct3D11, \c Direct3D12 are equivalent in effect to running
1268 with \c QSG_RHI_BACKEND set to the equivalent string key.
1270 All QRhi backends will choose the system default GPU adapter or physical
1271 device, unless overridden by \c{QSG_RHI_PREFER_SOFTWARE_RENDERER} or a
1272 backend-specific variable, such as, \c{QT_D3D_ADAPTER_INDEX} or
1273 \c{QT_VK_PHYSICAL_DEVICE_INDEX}. No further adapter configurability is
1274 provided at this time.
1276 Starting with Qt 6.5, some of the settings that were previously only exposed
1277 as environment variables are available as C++ APIs in
1278 QQuickGraphicsConfiguration. For example, setting \c QSG_RHI_DEBUG_LAYER and
1280 \l{QQuickGraphicsConfiguration::setDebugLayer()}{setDebugLayer(true)}