// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
\title Qt Quick Scene Graph
\page qtquick-visualcanvas-scenegraph.html

\section1 The Scene Graph in Qt Quick

Qt Quick 2 makes use of a dedicated scene graph that is then traversed and
rendered via a graphics API such as OpenGL ES, OpenGL, Vulkan, Metal, or Direct
3D. Using a scene graph for graphics rather than the traditional imperative
painting systems (QPainter and similar), means the scene to be rendered can be
retained between frames and the complete set of primitives to render is known
before rendering starts. This opens up for a number of optimizations, such as
batch rendering to minimize state changes and discarding obscured primitives.

For example, say a user-interface contains a list of ten items
where each item has a background color, an icon and a text. Using the
traditional drawing techniques, this would result in 30 draw calls and
a similar amount of state changes. A scene graph, on the other hand,
could reorganize the primitives to render such that all backgrounds
are drawn in one call, then all icons, then all the text, reducing the
total amount of draw calls to only 3. Batching and state change
reduction like this can greatly improve performance on some hardware.

The scene graph is closely tied to Qt Quick 2.0 and can not be used
stand-alone. The scene graph is managed and rendered by the
QQuickWindow class and custom Item types can add their graphical
primitives into the scene graph through a call to
QQuickItem::updatePaintNode().

The scene graph is a graphical representation of the Item scene, an
independent structure that contains enough information to render all
the items. Once it has been set up, it can be manipulated and rendered
independently of the state of the items. On many platforms, the scene
graph will even be rendered on a dedicated render thread while the GUI
thread is preparing the next frame's state.

\note Much of the information listed on this page is specific to the built-in,
default behavior of the Qt Quick Scene graph. When using an alternative scene
graph adaptation, such as, the \c software adaptation, not all concepts may
apply. For more information about the different scene graph adaptations see
\l{qtquick-visualcanvas-adaptations.html}{Scene Graph Adaptations}.


\section1 Qt Quick Scene Graph Structure

The scene graph is composed of a number of predefined node types, each
serving a dedicated purpose. Although we refer to it as a scene graph,
a more precise definition is node tree. The tree is built from
QQuickItem types in the QML scene and internally the scene is then
processed by a renderer which draws the scene. The nodes themselves do
\b not contain any active drawing code nor virtual \c paint()
function.

Even though the node tree is mostly built internally by the existing
Qt Quick QML types, it is possible for users to also add complete
subtrees with their own content, including subtrees that represent 3D
models.


\section2 Nodes

The most important node for users is the \l QSGGeometryNode. It is
used to define custom graphics by defining its geometry and
material. The geometry is defined using \l QSGGeometry and describes
the shape or mesh of the graphical primitive. It can be a line, a
rectangle, a polygon, many disconnected rectangles, or complex 3D
mesh. The material defines how the pixels in this shape are filled.

A node can have any number of children and geometry nodes will be
rendered so they appear in child-order with parents behind their
children. \note This does not say anything about the actual rendering
order in the renderer. Only the visual output is guaranteed.

The available nodes are:
\annotatedlist{qtquick-scenegraph-nodes}

Custom nodes are added to the scene graph by subclassing
QQuickItem::updatePaintNode() and setting the
\l {QQuickItem::ItemHasContents} flag.

\warning It is crucial that native graphics (OpenGL, Vulkan, Metal, etc.)
operations and interaction with the scene graph happens exclusively on the
render thread, primarily during the updatePaintNode() call. The rule of thumb
is to only use classes with the "QSG" prefix inside the
QQuickItem::updatePaintNode() function.

For more details, see the \l {Scene Graph - Custom Geometry}.

\section3 Preprocessing

Nodes have a virtual QSGNode::preprocess() function, which will be
called before the scene graph is rendered. Node subclasses can set the
flag \l QSGNode::UsePreprocess and override the QSGNode::preprocess()
function to do final preparation of their node. For example, dividing a
bezier curve into the correct level of detail for the current scale
factor or updating a section of a texture.

\section3 Node Ownership

Ownership of the nodes is either done explicitly by the creator or by
the scene graph by setting the flag \l QSGNode::OwnedByParent.
Assigning ownership to the scene graph is often preferable as it
simplifies cleanup when the scene graph lives outside the GUI thread.


\section2 Materials

The material describes how the interior of a geometry in a \l QSGGeometryNode
is filled. It encapsulates graphics shaders for the vertex and fragment stages
of the graphics pipeline and provides ample flexibility in what can be
achieved, though most of the Qt Quick items themselves only use very basic
materials, such as solid color and texture fills.

For users who just want to apply custom shading to a QML Item type,
it is possible to do this directly in QML using the \l ShaderEffect
type.

Below is a complete list of material classes:
\annotatedlist{qtquick-scenegraph-materials}

\section2 Convenience Nodes

The scene graph API is low-level and focuses on performance rather than
convenience. Writing custom geometries and materials from scratch, even the
most basic ones, requires a non-trivial amount of code. For this reason, the
API includes a few convenience classes to make the most common custom nodes
readily available.

\list
\li \l QSGSimpleRectNode - a QSGGeometryNode subclass which defines a
rectangular geometry with a solid color material.

\li \l QSGSimpleTextureNode - a QSGGeometryNode subclass which defines
a rectangular geometry with a texture material.
\endlist



\section1 Scene Graph and Rendering

The rendering of the scene graph happens internally in the QQuickWindow class,
and there is no public API to access it. There are, however, a few places in
the rendering pipeline where the user can attach application code. This can be
used to add custom scene graph content or to insert arbitrary rendering
commands by directly calling the graphics API (OpenGL, Vulkan, Metal, etc.)
that is in use by the scene graph. The integration points are defined by the
render loop.

For detailed description of how the scene graph renderer works, see \l {Qt
Quick Scene Graph Default Renderer}.

There are two render loop variants available: \c basic, and \c threaded.
\c basic is single-threaded, while \c threaded performs scene graph rendering on a
dedicated thread. Qt attempts to choose a suitable loop based on the platform
and possibly the graphics drivers in use. When this is not satisfactory, or for
testing purposes, the environment variable \c QSG_RENDER_LOOP can be used to
force the usage of a given loop. To verify which render loop is in use, enable
the \c qt.scenegraph.general \l {QLoggingCategory}{logging category}.

\section2 Threaded Render Loop ('threaded')
\target threaded_render_loop

On many configurations, the scene graph rendering will happen on a
dedicated render thread. This is done to increase parallelism of
multi-core processors and make better use of stall times such as
waiting for a blocking swap buffer call. This offers significant
performance improvements, but imposes certain restrictions on where
and when interaction with the scene graph can happen.

The following is a simple outline of how a frame gets rendered with the
threaded render loop and OpenGL. The steps are the same with other graphics
APIs as well, apart from the OpenGL context specifics.

\image sg-renderloop-threaded.png

\list 1

\li A change occurs in the QML scene, causing \c QQuickItem::update()
to be called. This can be the result of for instance an animation or
user input. An event is posted to the render thread to initiate a new
frame.

\li The render thread prepares to draw a new frame and initiates a block on the
GUI thread.

\li While the render thread is preparing the new frame, the GUI thread
calls QQuickItem::updatePolish() to do final touch-up of items before
they are rendered.

\li GUI thread is blocked.

\li The QQuickWindow::beforeSynchronizing() signal is emitted.
Applications can make direct connections (using Qt::DirectConnection)
to this signal to do any preparation required before calls to
QQuickItem::updatePaintNode().

\li Synchronization of the QML state into the scene graph. This is
done by calling the QQuickItem::updatePaintNode() function on all
items that have changed since the previous frame. This is the only
time the QML items and the nodes in the scene graph interact.

\li GUI thread block is released.

\li The scene graph is rendered:
    \list 1

    \li The QQuickWindow::beforeRendering() signal is emitted. Applications can
    make direct connections (using Qt::DirectConnection) to this signal to use
    custom graphics API calls which will then stack visually beneath the QML
    scene.

    \li Items that have specified QSGNode::UsePreprocess, will have their
    QSGNode::preprocess() function invoked.

    \li The renderer processes the nodes.

    \li The renderer generates states and records draw calls for the graphics
    API in use.

    \li The QQuickWindow::afterRendering() signal is emitted. Applications can
    make direct connections (using Qt::DirectConnection) to this signal to
    issue custom graphics API calls which will then stack visually over the QML
    scene.

    \li The frame is now ready. The buffers are swapped (OpenGL), or a present
    command is recorded and the command buffers are submitted to a graphics
    queue (Vulkan, Metal). QQuickWindow::frameSwapped() is emitted.

    \endlist

\li While the render thread is rendering, the GUI is free to advance
animations, process events, etc.

\endlist

The threaded renderer is currently used by default on Windows with
Direct3D 11 and with OpenGL when using opengl32.dll, Linux excluding
Mesa llvmpipe, \macos with Metal, mobile platforms, and Embedded Linux
with EGLFS, and with Vulkan regardless of the platform. All this may
change in future releases.  It is always possible to force use of the
threaded renderer by setting \c {QSG_RENDER_LOOP=threaded} in the
environment.

\section2 Non-threaded Render Loop ('basic')

The non-threaded render loop is currently used by default on Windows with
OpenGL when not using the system's standard opengl32.dll, \macos with OpenGL,
and Linux with some drivers. For the latter this is mostly a precautionary
measure, as not all combinations of OpenGL drivers and windowing systems have
been tested.

On macOS and OpenGL, the threaded render loop is not supported when building
with XCode 10 (10.14 SDK) or later, since this opts in to layer-backed views on
macOS 10.14. You can build with Xcode 9 (10.13 SDK) to opt out of
layer-backing, in which case the threaded render loop is available and used by
default. There is no such restriction with Metal.

Even when using the non-threaded render loop, you should write your code as if
you are using the threaded renderer, as failing to do so will make the code
non-portable.

The following is a simplified illustration of the frame rendering sequence in
the non-threaded renderer.

\image sg-renderloop-singlethreaded.png


\section2 Driving Animations

\section3 What does \c{Advance Animations} refer to in the above diagrams?

By default, a Qt Quick animation (such, as a \l NumberAnimation) is driven by
the default animation driver. This relies on basic system timers, such as
QObject::startTimer(). The timer typically runs with an interval of 16
milliseconds. While this will never be fully accurate and also depends on the
accuracy of timers in the underlying platform, it has the benefit of being
independent of the rendering. It provides uniform results regardless of the
display refresh rate and if synchronization to the display's vertical sync is
active or not. This is how animations work with the \c basic render loop.

In order to provide more accurate results with less stutter on-screen,
independent of the render loop design (be it single threaded or multiple
threads) a render loop may decide to install its own custom animation driver,
and take the operation of \c advancing it into its own hands, without relying
on timers.

This is what the \c threaded render loop implements. In fact, it installs not
one, but two animation drivers: one on the gui thread (to drive regular
animations, such as \l NumberAnimation), and one on the render thread (to drive
render thread animations, i.e. the \l Animator types, such as \l
OpacityAnimator or \l XAnimator). Both of these are advanced during the
preparation of a frame, i.e. animations are now synchronized with rendering.
This makes sense due to presentation being throttled to the display's vertical
sync by the underlying graphics stack.

Therefore, in the diagram for the \c threaded render loop above, there is an
explicit \c{Advance animations} step on both threads. For the render thread,
this is trivial: as the thread is being throttled to vsync, advancing
animations (for \l Animator types) in each frame as if 16.67 milliseconds had
elapsed gives more accurate results than relying on a system timer. (when
throttled to the vsync timing, which is \c{1000/60} milliseconds with a 60 Hz
refresh rate, it is fair to assume that it has been approximately that long
since the same operation was done for the previous frame)

The same approach works for animations on the gui (main) thread too: due to the
essential synchronization of data between the gui and render threads, the gui
thread is effectively throttled to the same rate as the render thread, while
still having the benefit of having less work to do, leaving more headroom for
the application logic since much of the rendering preparations are now
offloaded to the render thread.

While the above examples used 60 frames per second, Qt Quick is prepared for
other refresh rates as well: the rate is queried from the QScreen and the
platform. For example, with a 144 Hz screen the interval is 6.94 ms. At the
same time this is exactly what can cause trouble if vsync-based throttling is
not functioning as expected, because if what the render loop thinks is
happening is not matching reality, incorrect animation pacing will occur.

In summary, the \c threaded render loop is expected to provide smoother
animations with less stutter as long as the following conditions are met:

\list

\li There is exactly one window (as in QQuickWindow) on-screen.

\li VSync-based throttling works as expected with the underyling graphics and
display stack.

\endlist

\section3 What if there is no or more than one window visible?

When there is no renderable window, for example because our QQuickWindow is
minimized (Windows) or fully obscured (macOS), we cannot present frames, thus
cannot rely on the thread "working" in lockstep with the screen refresh rate.
In this case, the \c threaded render loop automatically switches over to a
system timer based approach to drive animations, i.e. temporarily switching
over to the mechanism the \c basic loop would use.

The same is true when there are more than one QQuickWindow instances on-screen.
The model presented above for advancing animations on the gui thread, enabled
by its synchronization with the render thread, is not satisfactory anymore, as
there are now multiple sync points with multiple render threads. (one per
window.) Here falling back to the system timer based approach becomes necessary
as well, because how long and often the gui thread will block is now dependent
on a number of factors, including the content in the windows (are they
animating? how often are they updating?) and the graphics stack behavior (how
exactly does it handle two or more threads presenting with wait-for-vsync?). As
we cannot guarantee being throttled to the presentation rate of the window
(which window would that be, to begin with?) in a stable, cross-platform
manner, advancing animations cannot be based on the rendering.

This switch of animation handling mechanisms is transparent to the
applications.

\section3 What if vsync-based throttling is disfunctional, globally disabled, or the application disabled it itself?

The \c threaded render loop relies on the graphics API implementation and/or
the windowing system for throttling, for example, by requesting a swap interval
of 1 in case of OpenGL (GLX, EGL, WGL), calling Present() with an interval of 1
for Direct 3D, or using the presentation mode \c FIFO with Vulkan.

Some graphics drivers allow users to override this setting and turn it off,
ignoring Qt's request. An example of this would be a system wide control panel
of the graphics driver that allows overriding the application's settings with
regards to vsync. It can also happen that a graphics stack is unable to provide
proper vsync-based throttling, which can be the case in some virtual machines
(mainly due to using a software rasterization based implementation of OpenGL or
Vulkan).

Without blocking in the swap/present operation (or some other graphics
operation), such a render loop would advance animations too fast. This would be
no issue with the \c basic render loop, because that always relies on system
timers. With \c threaded, the behavior can vary based on the Qt version:

\list

\li If a system is known to be unable to provide vsync-based throttling, the
only option before Qt 6.4 was to use the \c basic render loop, by manually
setting \c {QSG_RENDER_LOOP=basic} in the environment before running the
application.

\li Starting with Qt 6.4, setting either the \c{QSG_NO_VSYNC} environment
variable to a non-zero value, or the window's QSurfaceFormat::swapInterval() to
\c 0 can both alleviate the problem as well: by explicitly requesting disabling
vsync-based blocking, regardless of the request having any effect in practice,
the \c threaded render loop can by extension recognize that relying on vsync to
drive animations is futile, and it will fall back to using system timers, just
as it would for more than one window.

\li Even better, starting from Qt 6.4 the scenegraph also attempts to recognize
using some simple heuristics that the frames are being presented "too fast",
and automatically switch over to system timers if seen necessary. This means
that in most cases there will be no need to do anything and applications will
run animations as expected even when the default render loop is the \c threaded
one. While this is transparent to applications, for troubleshooting and
development purposes it is useful to know that this is logged with a \c{"Window
0x7ffc8489c3d0 is determined to have broken vsync throttling ..."} message
printed when \c{QSG_INFO} or \c{qt.scenegraph.general} is enabled. This method
has the downside of activating only after a small set of frames, given that it
first needs to collect data to evaluate, meaning that when opening a
QQuickWindow the application may still show overly fast animations for a short
period of time. Additionally, it may not capture all possible vsync-broken
situations.

\endlist

Remember however, that by design none of this helps render thread animations
(the \l Animator types). In the absence of vsync-based blocking,
\l{Animator}{animators} will advance incorrectly, faster than expected, even
when the workarounds are activated for regular \l{Animation}{animations}.

\note Be aware that the rendering loop logic and event processing on the GUI
(main) thread is not necessarily unthrottled even if waiting for vsync is
disabled: both render loops schedule updates for windows via
QWindow::requestUpdate(). This is backed by a 5 ms GUI thread timer on most
platforms, in order to give time for event processing. On some platforms, e.g.
macOS, it is using platform-specific APIs (such as, CVDisplayLink) to get
notified about the appropriate time to prepare a new frame, likely tied to the
display's vsync in some form. This can be relevant in benchmarking and similar
situations. For applications and tools attempting to perform low-level
benchmarking it may be beneficial to set the \c{QT_QPA_UPDATE_IDLE_TIME}
environment variable to \c 0 in order to potentially reduce idle time on the
GUI thread. For normal application usage the defaults should, in most cases, be
sufficient.

\note When in doubt, enable the \c {qt.scenegraph.general} and \c
{qt.scenegraph.time.renderloop} logging categories for troubleshooting, as
these may reveal some clues as to why rendering and animations are not running
at the expected pace.


\section2 Custom control over rendering with QQuickRenderControl

When using QQuickRenderControl, the responsibility for driving the
rendering loop is transferred to the application. In this case no
built-in render loop is used. Instead, it is up to the application to
invoke the polish, synchronize and rendering steps at the appropriate
time. It is possible to implement either a threaded or non-threaded
behavior similar to the ones shown above.

Additionally, applications may wish to implement and install their own
QAnimationDriver in combination with QQuickRenderControl. This gives full
control over driving Qt Quick animations, which can be particularly important
for content that is not shown on screen, bearing no relation to the
presentation rate simply because there is no presenting of the frame happening.
This is optional, by default animations will advance based on the system timer.


\section2 Mixing Scene Graph and the native graphics API

The scene graph offers two methods for integrating application-provided
graphics commands: by issuing OpenGL, Vulkan, Metal, etc. commands directly,
and by creating a textured node in the scene graph.

By connecting to the \l QQuickWindow::beforeRendering() and \l
QQuickWindow::afterRendering() signals, applications can make OpenGL calls
directly into the same context as the scene graph is rendering to. With APIs
like Vulkan or Metal, applications can query native objects, such as, the scene
graph's command buffer, via QSGRendererInterface, and record commands to it as
they see fit. As the signal names indicate, the user can then render content
either under a Qt Quick scene or over it. The benefit of integrating in this
manner is that no extra framebuffer nor memory is needed to perform the
rendering, and a possibly expensive texturing step is eliminated. The downside
is that Qt Quick decides when to call the signals and this is the only time the
OpenGL application is allowed to draw.

The \l {Scene Graph - OpenGL Under QML} example gives an example on
how to use these signals using OpenGL.

The \l {Scene Graph - Direct3D 11 Under QML} example gives an example on
how to use these signals using Direct3D.

The \l {Scene Graph - Metal Under QML} example gives an example on
how to use these signals using Metal.

The \l {Scene Graph - Vulkan Under QML} example gives an example on
how to use these signals using Vulkan.

The other alternative, only available for OpenGL currently, is to create a
QQuickFramebufferObject, render into it, and let it be displayed in the scene
graph as a texture. The \l {Scene Graph - Rendering FBOs} example shows how
this can be done.

Graphics APIs other than OpenGL can also follow this approach, even though
QQuickFramebufferObject does not currently support them. Creating and rendering
to a texture directly with the underlying API, followed by wrapping and using
this resource in a Qt Quick scene in a custom QQuickItem, is demonstrated in
the \l {Scene Graph - Metal Texture Import} example. That example uses Metal,
the concepts however apply to all other graphics APIs as well.

\warning Starting with Qt 6.0, direct usage of the underlying graphics API must
be enclosed by a call to \l QQuickWindow::beginExternalCommands() and \l
QQuickWindow::endExternalCommands(). This concept may be familiar from \l
QPainter::beginNativePainting(), and serves a similar purpose: it allows the Qt
Quick Scene Graph to recognize that any cached state and assumptions about the
state within the currently recorded render pass, if there is one, are now
invalid, because the application code may have altered it by working directly
with the underlying graphics API.

\warning When mixing OpenGL content with scene graph rendering, it is
important the application does not leave the OpenGL context in a state
with buffers bound, attributes enabled, special values in the z-buffer
or stencil-buffer or similar. Doing so can result in unpredictable
behavior.

\warning The custom rendering code must be thread aware in the sense that it
should not assume being executed on the GUI (main) thread of the application.


\section2 Custom Items using QPainter

The QQuickItem provides a subclass, QQuickPaintedItem, which allows
the users to render content using QPainter.

\warning Using QQuickPaintedItem uses an indirect 2D surface to render
its content, either using software rasterization or using an OpenGL
framebuffer object (FBO), so the rendering is a two-step
operation. First rasterize the surface, then draw the surface. Using
scene graph API directly is always significantly faster.

\section1 Logging Support

The scene graph has support for a number of logging categories. These
can be useful in tracking down both performance issues and bugs in
addition to being helpful to Qt contributors.

\list

\li \c {qt.scenegraph.time.texture} - logs the time spent doing texture uploads

\li \c {qt.scenegraph.time.compilation} - logs the time spent doing shader compilation

\li \c {qt.scenegraph.time.renderer} - logs the time spent in the various steps of the renderer

\li \c {qt.scenegraph.time.renderloop} - logs the time spent in the various
steps of the render loop. With the \c threaded render loop this gives an
insight into the time elapsed between the various frame preparation steps both
on the GUI and the render thread. It can therefore also be a useful
troubleshooting tool, for example, to confirm how vsync-based throttling and
other low-level Qt enablers, such as QWindow::requestUpdate(), affect the
rendering and presentation pipeline.

\li \c {qt.scenegraph.time.glyph} - logs the time spent preparing distance field glyphs

\li \c {qt.scenegraph.general} - logs general information about various parts of the scene graph and the graphics stack

\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.

\endlist

The legacy \c{QSG_INFO} environment variable is also available. Setting it to a
non-zero value enables the \c{qt.scenegraph.general} category.

\note When encountering graphics problems, or when in doubt which render loop
or graphics API is in use, always start the application with at least
\c{qt.scenegraph.general} and \c{qt.rhi.*} enabled, or \c{QSG_INFO=1} set. This
will then print some essential information onto the debug output during
initialization.

\section1 Scene Graph Backend

In addition to the public API, the scene graph has an adaptation layer
which opens up the implementation to do hardware specific
adaptations. This is an undocumented, internal and private plugin API,
which lets hardware adaptation teams make the most of their hardware.
It includes:

\list

\li Custom textures; specifically the implementation of
QQuickWindow::createTextureFromImage and the internal representation
of the texture used by \l Image and \l BorderImage types.

\li Custom renderer; the adaptation layer lets the plugin decide how
the scene graph is traversed and rendered, making it possible to
optimize the rendering algorithm for a specific hardware or to make
use of extensions which improve performance.

\li Custom scene graph implementation of many of the default QML
types, including its text and font rendering.

\li Custom animation driver; allows the animation system to hook
into the low-level display vertical refresh to get smooth rendering.

\li Custom render loop; allows better control over how QML deals
with multiple windows.

\endlist

*/

/*!
  \title Qt Quick Scene Graph Default Renderer
  \page qtquick-visualcanvas-scenegraph-renderer.html

  This document explains how the default scene graph renderer works internally,
  so that one can write code that uses it in an optimal fashion, both
  performance and feature-wise.

  One does not need to understand the internals of the renderer to get
  good performance.  However, it might help when integrating with the
  scene graph or to figure out why it is not possible to squeeze the
  maximum efficiency out of the graphics chip.

  \note Even in the case where every frame is unique and everything is
  uploaded from scratch, the default renderer will perform well.

  The Qt Quick items in a QML scene populate a tree of QSGNode
  instances.  Once created, this tree is a complete description of how
  a certain frame should be rendered. It does not contain any
  references back to the Qt Quick items at all and will on most
  platforms be processed and rendered in a separate thread. The
  renderer is a self contained part of the scene graph which traverses
  the QSGNode tree and uses geometry defined in QSGGeometryNode and
  shader state defined in QSGMaterial to update the graphics state and
  generate draw calls.

  If needed, the renderer can be completely replaced using the
  internal scene graph back-end API. This is mostly interesting for
  platform vendors who wish to take advantage of non-standard hardware
  features. For the majority of use cases, the default renderer will be
  sufficient.

  The default renderer focuses on two primary strategies to optimize
  the rendering: Batching of draw calls, and retention of geometry on
  the GPU.

  \section1 Batching

  Whereas a traditional 2D API, such as QPainter, Cairo or Context2D, is
  written to handle thousands of individual draw calls per frame, OpenGL and
  other hardware accelerated APIs perform best when the number of draw calls is
  very low and state changes are kept to a minimum.

  \note While \c OpenGL is used as an example in the following sections, the
  same concepts apply to other graphics APIs as well.

  Consider the following use case:

  \image visualcanvas_list.png

  The simplest way of drawing this list is on a cell-by-cell basis. First,
  the background is drawn. This is a rectangle of a specific color. In
  OpenGL terms this means selecting a shader program to do solid color
  fills, setting up the fill color, setting the transformation matrix
  containing the x and y offsets and then using for instance
  \c glDrawArrays to draw two triangles making up the rectangle. The icon
  is drawn next. In OpenGL terms this means selecting a shader program
  to draw textures, selecting the active texture to use, setting the
  transformation matrix, enabling alpha-blending and then using for
  instance \c glDrawArrays to draw the two triangles making up the
  bounding rectangle of the icon. The text and separator line between
  cells follow a similar pattern. And this process is repeated for
  every cell in the list, so for a longer list, the overhead imposed
  by OpenGL state changes and draw calls completely outweighs the
  benefit that using a hardware accelerated API could provide.

  When each primitive is large, this overhead is negligible, but in
  the case of a typical UI, there are many small items which add up to
  a considerable overhead.

  The default scene graph renderer works within these
  limitations and will try to merge individual primitives together
  into batches while preserving the exact same visual result. The
  result is fewer OpenGL state changes and a minimal amount of draw
  calls, resulting in optimal performance.

  \section2 Opaque Primitives

  The renderer separates between opaque primitives and primitives
  which require alpha blending. By using OpenGL's Z-buffer and giving
  each primitive a unique z position, the renderer can freely reorder
  opaque primitives without any regard for their location on screen
  and which other elements they overlap with. By looking at each
  primitive's material state, the renderer will create opaque
  batches. From Qt Quick core item set, this includes Rectangle items
  with opaque colors and fully opaque images, such as JPEGs or BMPs.

  Another benefit of using opaque primitives is that opaque
  primitives do not require \c GL_BLEND to be enabled, which can be
  quite costly, especially on mobile and embedded GPUs.

  Opaque primitives are rendered in a front-to-back manner with
  \c glDepthMask and \c GL_DEPTH_TEST enabled. On GPUs that internally do
  early-z checks, this means that the fragment shader does not need to
  run for pixels or blocks of pixels that are obscured. Beware that
  the renderer still needs to take these nodes into account and the
  vertex shader is still run for every vertex in these primitives, so
  if the application knows that something is fully obscured, the best
  thing to do is to explicitly hide it using Item::visible or
  Item::opacity.

  \note The Item::z is used to control an Item's stacking order
  relative to its siblings. It has no direct relation to the renderer and
  OpenGL's Z-buffer.

  \section2 Alpha Blended Primitives

  Once opaque primitives have been drawn, the renderer will disable
  \c glDepthMask, enable \c GL_BLEND and render all alpha blended primitives
  in a back-to-front manner.

  Batching of alpha blended primitives requires a bit more effort in
  the renderer as elements that are overlapping need to be rendered in
  the correct order for alpha blending to look correct. Relying on the
  Z-buffer alone is not enough. The renderer does a pass over all
  alpha blended primitives and will look at their bounding rect in
  addition to their material state to figure out which elements can be
  batched and which can not.

  \image visualcanvas_overlap.png

  In the left-most case, the blue backgrounds can be drawn in one call
  and the two text elements in another call, as the texts only overlap
  a background which they are stacked in front of. In the right-most
  case, the background of "Item 4" overlaps the text of "Item 3" so in
  this case, each of backgrounds and texts needs to be drawn using
  separate calls.

  Z-wise, the alpha primitives are interleaved with the opaque nodes
  and may trigger early-z when available, but again, setting
  Item::visible to false is always faster.

  \section2 Mixing with 3D Primitives

  The scene graph can support pseudo 3D and proper 3D primitives. For
  instance, one can implement a "page curl" effect using a
  ShaderEffect or implement a bumpmapped torus using QSGGeometry and a
  custom material. While doing so, one needs to take into account that
  the default renderer already makes use of the depth buffer.

  The renderer modifies the vertex shader returned from
  QSGMaterialShader::vertexShader() and compresses the z values of the
  vertex after the model-view and projection matrices have been applied
  and then adds a small translation on the z to position it the
  correct z position.

  The compression assumes that the z values are in the range of 0 to
  1.

  \section2 Texture Atlas

  The active texture is a unique OpenGL state, which means that
  multiple primitives using different OpenGL textures cannot be
  batched. The Qt Quick scene graph, for this reason, allows multiple
  QSGTexture instances to be allocated as smaller sub-regions of a
  larger texture; a texture atlas.

  The biggest benefit of texture atlases is that multiple QSGTexture
  instances now refer to the same OpenGL texture instance. This makes
  it possible to batch textured draw calls as well, such as Image
  items, BorderImage items, ShaderEffect items and also C++ types such
  as QSGSimpleTextureNode and custom QSGGeometryNodes using textures.

  \note Large textures do not go into the texture atlas.

  Atlas based textures are created by passing
  QQuickWindow::TextureCanUseAtlas to the
  QQuickWindow::createTextureFromImage().

  \note Atlas based textures do not have texture coordinates ranging
  from 0 to 1. Use QSGTexture::normalizedTextureSubRect() to get the
  atlas texture coordinates.

  The scene graph uses heuristics to figure out how large the atlas
  should be and what the size threshold for being entered into the
  atlas is. If different values are needed, it is possible to override
  them using the environment variables \c {QSG_ATLAS_WIDTH=[width]},
  \c {QSG_ATLAS_HEIGHT=[height]} and \c
  {QSG_ATLAS_SIZE_LIMIT=[size]}. Changing these values will mostly be
  interesting for platform vendors.

  \section1 Batch Roots

  In addition to merging compatible primitives into batches, the
  default renderer also tries to minimize the amount of data that
  needs to be sent to the GPU for every frame. The default renderer
  identifies subtrees which belong together and tries to put these
  into separate batches. Once batches are identified, they are merged,
  uploaded and stored in GPU memory, using Vertex Buffer Objects.

  \section2 Transform Nodes

  Each Qt Quick Item inserts a QSGTransformNode into the scene graph
  tree to manage its x, y, scale or rotation. Child items will be
  populated under this transform node.  The default renderer tracks
  the state of transform nodes between frames and will look at
  subtrees to decide if a transform node is a good candidate to become
  a root for a set of batches. A transform node which changes between
  frames and which has a fairly complex subtree can become a batch
  root.

  QSGGeometryNodes in the subtree of a batch root are pre-transformed
  relative to the root on the CPU. They are then uploaded and retained
  on the GPU. When the transform changes, the renderer only needs to
  update the matrix of the root, not each individual item, making list
  and grid scrolling very fast. For successive frames, as long as
  nodes are not being added or removed, rendering the list is
  effectively for free. When new content enters the subtree, the batch
  that gets it is rebuilt, but this is still relatively fast. There are
  usually several unchanging frames for every frame with added or
  removed nodes when panning through a grid or list.

  Another benefit of identifying transform nodes as batch roots is
  that it allows the renderer to retain the parts of the tree that have
  not changed. For instance, say a UI consists of a list and a button
  row. When the list is being scrolled and delegates are being added
  and removed, the rest of the UI, the button row, is unchanged and
  can be drawn using the geometry already stored on the GPU.

  The node and vertex threshold for a transform node to become a batch
  root can be overridden using the environment variables \c
  {QSG_RENDERER_BATCH_NODE_THRESHOLD=[count]} and \c
  {QSG_RENDERER_BATCH_VERTEX_THRESHOLD=[count]}. Overriding these flags
  will be mostly useful for platform vendors.

  \note Beneath a batch root, one batch is created for each unique
  set of material state and geometry type.

  \section2 Clipping

  When setting Item::clip to true, it will create a QSGClipNode with a
  rectangle in its geometry. The default renderer will apply this clip
  by using scissoring in OpenGL. If the item is rotated by a
  non-90-degree angle, the OpenGL's stencil buffer is used. Qt Quick
  Item only supports setting a rectangle as clip through QML, but the
  scene graph API and the default renderer can use any shape for
  clipping.

  When applying a clip to a subtree, that subtree needs to be rendered
  with a unique OpenGL state. This means that when Item::clip is true,
  batching of that item is limited to its children. When there are
  many children, like a ListView or GridView, or complex children,
  like a TextArea, this is fine. One should, however, use clip on
  smaller items with caution as it prevents batching. This includes
  button label, text field or list delegate and table cells.
  Clipping a Flickable (or item view) can often be avoided by arranging
  the UI so that opaque items cover areas around the Flickable, and
  otherwise relying on the window edges to clip everything else.

  Setting Item::clip to \c true also sets the \l QQuickItem::ItemIsViewport
  flag; child items with the \l QQuickItem::ItemObservesViewport flag may
  use the viewport for a rough pre-clipping step: e.g. \l Text omits
  lines of text that are completely outside the viewport. Omitting scene
  graph nodes or limiting the \l {QSGGeometry::vertexCount()}{vertices}
  is an optimization, which can be achieved by setting the
  \l {QQuickItem::flags()}{flags} in C++ rather than setting
  \l Item::clip in QML.

  When implementing QQuickItem::updatePaintNode() in a custom item,
  if it can render a lot of details over a large geometric area,
  you should think about whether it's efficient to limit the graphics
  to the viewport; if so, you can set the \l {QQuickItem::}
  {ItemObservesViewport} flag and read the currently exposed area from
  QQuickItem::clipRect(). One consequence is that updatePaintNode() will be
  called more often (typically once per frame whenever content is moving in
  the viewport).

  \section2 Vertex Buffers

  Each batch uses a vertex buffer object (VBO) to store its data on
  the GPU. This vertex buffer is retained between frames and updated
  when the part of the scene graph that it represents changes.

  By default, the renderer will upload data into the VBO using
  \c GL_STATIC_DRAW. It is possible to select different upload strategy
  by setting the environment variable \c
  {QSG_RENDERER_BUFFER_STRATEGY=[strategy]}. Valid values are \c
  stream and \c dynamic. Changing this value is mostly useful for
  platform vendors.

  \section1 Antialiasing

  The scene graph supports two types of antialiasing. By default, primitives
  such as rectangles and images will be antialiased by adding more
  vertices along the edge of the primitives so that the edges fade
  to transparent. We call this method \e {vertex antialiasing}. If the
  user requests a multisampled OpenGL context, by setting a QSurfaceFormat
  with samples greater than \c 0 using QQuickWindow::setFormat(), the
  scene graph will prefer multisample based antialiasing (MSAA).
  The two techniques will affect how the rendering happens internally
  and have different limitations.

  It is also possible to override the antialiasing method used by
  setting the environment variable \c {QSG_ANTIALIASING_METHOD}
  to either \c vertex or \c {msaa}.

  Vertex antialiasing can produce seams between edges of adjacent
  primitives, even when the two edges are mathematically the same.
  Multisample antialiasing does not.


  \section2 Vertex Antialiasing

  Vertex antialiasing can be enabled and disabled on a per-item basis
  using the Item::antialiasing property. It will work regardless of
  what the underlying hardware supports and produces higher quality
  antialiasing, both for normally rendered primitives and also for
  primitives captured into framebuffer objects, for instance using
  the ShaderEffectSource type.

  The downside to using vertex antialiasing is that each primitive
  with antialiasing enabled will have to be blended. In terms of
  batching, this means that the renderer needs to do more work to
  figure out if the primitive can be batched or not and due to overlaps
  with other elements in the scene, it may also result in less batching,
  which could impact performance.

  On low-end hardware blending can also be quite expensive so for an
  image or rounded rectangle that covers most of the screen, the amount
  of blending needed for the interior of these primitives can result
  in significant performance loss as the entire primitive must be blended.

  \section2 Multisample Antialiasing

  Multisample antialiasing is a hardware feature where the hardware
  calculates a coverage value per pixel in the primitive. Some hardware
  can multisample at a very low cost, while other hardware may
  need both more memory and more GPU cycles to render a frame.

  Using multisample antialiasing, many primitives, such as rounded
  rectangles and image elements can be antialiased and still be
  \e opaque in the scene graph. This means the renderer has an easier
  job when creating batches and can rely on early-z to avoid overdraw.

  When multisample antialiasing is used, content rendered into
  framebuffer objects need additional extensions to support multisampling
  of framebuffers. Typically \c GL_EXT_framebuffer_multisample and
  \c GL_EXT_framebuffer_blit. Most desktop chips have these extensions
  present, but they are less common in embedded chips. When framebuffer
  multisampling is not available in the hardware, content rendered into
  framebuffer objects will not be antialiased, including the content of
  a ShaderEffectSource.


  \section1 Performance

  As stated in the beginning, understanding the finer details of the
  renderer is not required to get good performance. It is written to
  optimize for common use cases and will perform quite well under
  almost any circumstances.

  \list

  \li Good performance comes from effective batching, with as little
  as possible of the geometry being uploaded again and again. By
  setting the environment variable \c {QSG_RENDERER_DEBUG=render}, the
  renderer will output statistics on how well the batching goes, how
  many batches are used, which batches are retained and which are opaque and
  not. When striving for optimal performance, uploads should happen
  only when really needed, batches should be fewer than 10 and at
  least 3-4 of them should be opaque.

  \li The default renderer does not do any CPU-side viewport clipping
  nor occlusion detection. If something is not supposed to be visible,
  it should not be shown. Use \c {Item::visible: false} for items that
  should not be drawn. The primary reason for not adding such logic is
  that it adds additional cost which would also hurt applications that
  took care in behaving well.

  \li Make sure the texture atlas is used. The Image and BorderImage
  items will use it unless the image is too large. For textures
  created in C++, pass QQuickWindow::TextureCanUseAtlas when
  calling QQuickWindow::createTexture().
  By setting the environment variable \c {QSG_ATLAS_OVERLAY} all atlas
  textures will be colorized so they are easily identifiable in the
  application.

  \li Use opaque primitives where possible. Opaque primitives are
  faster to process in the renderer and faster to draw on the GPU. For
  instance, PNG files will often have an alpha channel, even though
  each pixel is fully opaque. JPG files are always opaque. When
  providing images to a QQuickImageProvider or creating images with
  QQuickWindow::createTextureFromImage(), let the image have
  QImage::Format_RGB32, when possible.

  \li Be aware of that overlapping compound items, like in the
  illustration above, cannot be batched.

  \li Clipping breaks batching. Never use on a per-item basis, inside
  table cells, item delegates or similar. Instead of clipping text,
  use eliding. Instead of clipping an image, create a
  QQuickImageProvider that returns a cropped image.

  \li Batching only works for 16-bit indices. All built-in items use
  16-bit indices, but a custom geometry is free to also use 32-bit
  indices.

  \li Some material flags prevent batching, the most limiting one
  being QSGMaterial::RequiresFullMatrix which prevents all batching.

  \li Applications with a monochrome background should set it using
  QQuickWindow::setColor() rather than using a top-level Rectangle item.
  QQuickWindow::setColor() will be used in a call to \c glClear(),
  which is potentially faster.

  \li Mipmapped Image items are not placed in the global atlas and will
  not be batched.

  \li A bug in the OpenGL driver related to framebuffer object (FBO) readbacks
  may corrupt rendered glyphs. If you set the \c QML_USE_GLYPHCACHE_WORKAROUND
  environment variable, Qt keeps an additional copy of the glyph in RAM. This
  means that performance is slightly lower when drawing glyphs that have not
  been drawn before, as Qt accesses the extra copy via the CPU. It also means
  that the glyph cache will use twice as much memory. The quality is not
  affected by this.

  \endlist

  If an application performs poorly, make sure that rendering is
  actually the bottleneck. Use a profiler! The environment variable \c
  {QSG_RENDER_TIMING=1} will output a number of useful timing
  parameters which can be useful in pinpointing where a problem lies.

  \section1 Visualizing

  To visualize the various aspects of the scene graph's default renderer, the
  \c QSG_VISUALIZE environment variable can be set to one of the values
  detailed in each section below. We provide examples of the output of
  some of the variables using the following QML code:

  \code
  import QtQuick 2.2

  Rectangle {
      width: 200
      height: 140

      ListView {
          id: clippedList
          x: 20
          y: 20
          width: 70
          height: 100
          clip: true
          model: ["Item A", "Item B", "Item C", "Item D"]

          delegate: Rectangle {
              color: "lightblue"
              width: parent.width
              height: 25

              Text {
                  text: modelData
                  anchors.fill: parent
                  horizontalAlignment: Text.AlignHCenter
                  verticalAlignment: Text.AlignVCenter
              }
          }
      }

      ListView {
          id: clippedDelegateList
          x: clippedList.x + clippedList.width + 20
          y: 20
          width: 70
          height: 100
          clip: true
          model: ["Item A", "Item B", "Item C", "Item D"]

          delegate: Rectangle {
              color: "lightblue"
              width: parent.width
              height: 25
              clip: true

              Text {
                  text: modelData
                  anchors.fill: parent
                  horizontalAlignment: Text.AlignHCenter
                  verticalAlignment: Text.AlignVCenter
              }
          }
      }
  }
  \endcode

  For the ListView on the left, we set its \l {Item::clip}{clip} property to
  \c true. For the ListView on right, we also set each delegate's
  \l {Item::clip}{clip} property to \c true to illustrate the effects of
  clipping on batching.

  \image visualize-original.png "Original"
  Original

  \note The visualized elements do not respect clipping, and rendering order is
  arbitrary.

  \section2 Visualizing Batches

  Setting \c QSG_VISUALIZE to \c batches visualizes batches in the renderer.
  Merged batches are drawn with a solid color and unmerged batches are drawn
  with a diagonal line pattern. Few unique colors means good batching.
  Unmerged batches are bad if they contain many individual nodes.

  \image visualize-batches.png "batches"
  \c QSG_VISUALIZE=batches

  \section2 Visualizing Clipping

  Setting \c QSG_VISUALIZE to \c clip draws red areas on top of the scene
  to indicate clipping. As Qt Quick Items do not clip by default, no clipping
  is usually visualized.

  \image visualize-clip.png
  \c QSG_VISUALIZE=clip

  \section2 Visualizing Changes

  Setting \c QSG_VISUALIZE to \c changes visualizes changes in the renderer.
  Changes in the scenegraph are visualized with a flashing overlay of a random
  color. Changes on a primitive are visualized with a solid color, while
  changes in an ancestor, such as matrix or opacity changes, are visualized
  with a pattern.

  \section2 Visualizing Overdraw

  Setting \c QSG_VISUALIZE to \c overdraw visualizes overdraw in the renderer.
  Visualize all items in 3D to highlight overdraws. This mode can also be used
  to detect geometry outside the viewport to some extent. Opaque items are
  rendered with a green tint, while translucent items are rendered with a red
  tint. The bounding box for the viewport is rendered in blue. Opaque content
  is easier for the scenegraph to process and is usually faster to render.

  Note that the root rectangle in the code above is superfluous as the window
  is also white, so drawing the rectangle is a waste of resources in this case.
  Changing it to an Item can give a slight performance boost.

  \image visualize-overdraw-1.png "overdraw-1"
  \image visualize-overdraw-2.png "overdraw-2"
  \c QSG_VISUALIZE=overdraw

  \section1 Rendering via the Qt Rendering Hardware Interface

  From Qt 6.0 onwards, the default adaptation always renders via a graphics
  abstraction layer, the Qt Rendering Hardware Interface (RHI), provided by the
  \l QtGui module. This means that, unlike Qt 5, no direct OpenGL calls are made
  by the scene graph. Rather, it records resource and draw commands by using the
  RHI APIs, which then translate the command stream into OpenGL, Vulkan, Metal,
  or Direct 3D calls. Shader handling is also unified by writing shader code
  once, compiling to \l{https://www.khronos.org/spir/}{SPIR-V}, and then
  translating to the language appropriate for the various graphics APIs.

  To control the behavior, the following environment variables can be used:

  \table 100%
  \header
    \li Environment Variable
    \li Possible Values
    \li Description

  \row
   \li \c QSG_RHI_BACKEND
   \li \c vulkan, \c metal, \c opengl, \c d3d11
   \li Requests the specific RHI backend. By default the targeted graphics API
   is chosen based on the platform, unless overridden by this variable or the
   equivalent C++ APIs. The defaults are currently Direct3D 11 for Windows,
   Metal for macOS, OpenGL elsewhere.

  \row
   \li \c QSG_INFO
   \li \c 1
   \li Like with the OpenGL-based rendering path, setting this enables printing system
   information when initializing the Qt Quick scene graph. This can be very useful for
   troubleshooting.

  \row
   \li \c QSG_RHI_DEBUG_LAYER
   \li \c 1
   \li Where applicable (Vulkan, Direct3D), enables the graphics API implementation's
   debug or validation layers, if available, either on the graphics device or the instance
   object. For Metal on \macos, set the environment variable
   \c{METAL_DEVICE_WRAPPER_TYPE=1} instead.

  \row
   \li \c QSG_RHI_PREFER_SOFTWARE_RENDERER
   \li \c 1
   \li Requests choosing an adapter or physical device that uses software-based
   rasterization. Applicable only when the underlying API has support for
   enumerating adapters (for example, Direct3D or Vulkan), and is ignored
   otherwise.

  \endtable

  Applications wishing to always run with a single given graphics API, can
  request this via C++ as well. For example, the following call made early in
  main(), before constructing any QQuickWindow, forces the use of Vulkan (and
  will fail otherwise):

  \badcode
      QQuickWindow::setGraphicsApi(QSGRendererInterface::Vulkan);
  \endcode

  See QSGRendererInterface::GraphicsApi. The enum values \c OpenGL, \c Vulkan,
  \c Metal, \c Direct3D11 are equivalent in effect to running with \c
  QSG_RHI_BACKEND set to the equivalent string key.

  All QRhi backends will choose the system default GPU adapter or physical
  device, unless overridden by \c{QSG_RHI_PREFER_SOFTWARE_RENDERER} or a
  backend-specific variable, such as, \c{QT_D3D_ADAPTER_INDEX} or
  \c{QT_VK_PHYSICAL_DEVICE_INDEX}. No further adapter configurability is
  provided at this time.
 */
