aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
blob: 8edc5cb0b66b4a7354ed459d1e8301c6f63cb122 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
\title Scene Graph Adaptations
\page qtquick-visualcanvas-adaptations.html

\section1 Scene Graph Adaptations in Qt Quick

Originally, Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) to parse the scene graph
and render the results to a render target. From Qt 5.8 onwards, Qt Quick also supports rendering in
software and with Direct3D 12.

\target Switching Between the Adaptation Used by the Application
\section1 Switch Between Adaptations in Your Application

The default rendering backend is still OpenGL, but in Qt builds with OpenGL support disabled, the
default is the software renderer. You can override this in one of two ways:

\list
    \li Use an environment variable - Set the \c{QT_QUICK_BACKEND} or the legacy
        \c{QMLSCENE_DEVICE} environment variable before launching applications.
    \li Use a C++ API - Call QQuickWindow::setSceneGraphBackend() early on in the application's
        main() function.
\endlist

The following backends are supported:

\list
    \li OpenGL - Request with the \c{""} string or the QSGRendererInterface::OpenGL enum value.
    \li Software - Request with the \c{"software"} string or the QSGRendererInterface::Software
        enum value.
    \li Direct3D 12 - Request with the \c{"d3d12"} string or the QSGRendererInterface::Direct3D12
        enum value.
    \li OpenVG - Request with the \c{"openvg"} string or the QSGRendererInterface::OpenVG enum
        value.
\endlist

To find out which backend is in use, you can enable basic scene graph information logging via the
\c{QSG_INFO} environment variable or the \c{qt.scenegraph.general} logging category. This results
in some information being printed onto the debug output, during application startup.

\note Typically, adaptations other than OpenGL come with a set of limitations as they are unlikely
      to provide a feature set that's 100% compatible with OpenGL. However, these adaptations may
      provide their own specific advantages in certain areas. For more information on the various
      adaptations, refer to the sections below.

\section1 OpenGL ES 2.0 and OpenGL 2.0 Adaptation

The OpenGL adaptation is the default adaptation, which is capable of providing the full Qt Quick 2
feature set. For more details, see
\l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation}.

\section1 Software Adaptation

The Software adaptation is an alternative renderer for \l{Qt Quick} 2 that uses the raster paint
engine to render the contents of the scene graph. For more details, see
\l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation}.

\section1 Direct3D 12 (experimental)

The Direct3D 12 adaptation is an alternative renderer for \l{Qt Quick} 2 when running on Windows
10, both for Win32 and UWP applications. For more details, see
\l{qtquick-visualcanvas-adaptations-d3d12.html}{Direct3D 12 Adaptation}.

\section1 OpenVG

The OpenVG adaptation is an alternative renderer for \l{Qt Quick} 2 that renders the contents of
the scene graph using OpenVG commands to provide hardware-accelerated 2D vector and raster
graphics. For more details, see
\l{qtquick-visualcanvas-adaptations-openvg.html}{OpenVG Adaptation}.
*/


/*!
\title Qt Quick Software Adaptation
\page qtquick-visualcanvas-adaptations-software.html

The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that uses the Raster paint
engine to render the contents of the scene graph, instead of OpenGL. Consequently, some features
and optimizations are not available. Most Qt Quick 2 applications can run without any modification,
but any attempts to use unsupported features are ignored. By using the Software adaptation, it is
possible to run Qt Quick 2 applications on hardware and platforms that do not have OpenGL support.

The Software adaptation was previously known as the Qt Quick 2D Renderer. However, unlike the 2D
Renderer, this new, integrated version supports partial updates. This means that a full update
of the window or screen contents is now avoided; only the changed areas are flushed. Partial
updates can significantly improve performance for many applications.

\section2 Shader Effects

ShaderEffect components in QtQuick 2 cannot be rendered by the Software adaptation.

\section2 Qt Graphical Effects Module

\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use graphical effects
from this module, then you should not hide the source item so that the original item can still be
rendered.

\section2 Particle Effects

It is not possible to render particle effects with the Software adaptation. Whenever possible,
remove particles completely from the scene. Otherwise, they will still require some processing,
even though they are not visible.

\section2 Rendering Text

The text rendering with the Software adaptation is based on software rasterization and does not
respond as well to transformations such as scaling, compared to when using OpenGL. The quality is
similar to choosing \l [QML] {Text::renderType}{Text.NativeRendering} with \l [QML] {Text} items.

\section2 Qt Multimedia VideoOutput

The Qt Multimedia module's VideoOutput item is not supported with the Software adaptation. This
is because VideoOutput uses the QVideoRendererControl item which requires custom QSGGeometryNode
behavior, which is only present in the default OpenGL adaptation.
*/


/*!
\title Qt Quick Direct3D 12 Adaptation
\page qtquick-visualcanvas-adaptations-d3d12.html

The Direct3D 12 adaptation for Windows 10, both in Win32 (\c windows platform plugin) and in UWP
(\c winrt platform plugin), is shipped as a dynamically loaded plugin. This adaptation doesn't work
on earlier Windows versions. Building this plugin is enabled automatically, whenever the necessary
D3D and DXGI develpoment files are present. In practice, this currently means Visual Studio 2015
and newer.

The adaptation is available both in normal, OpenGL-enabled Qt builds, and also when Qt is
configured with \c{-no-opengl}. However, it's never the default, meaning that the user or the
application has to explicitly request it by setting the \c{QT_QUICK_BACKEND} environment variable
to \c{d3d12} or by calling QQuickWindow::setSceneGraphBackend().

\section2 Motivation

This experimental adaptation is the first Qt Quick backend that focuses on a modern, lower-level
graphics API in combination with a windowing system interface that's different from the traditional
approaches used in combination with OpenGL.

This adaptation also allows better integration with Windows, as Direct3D is the primary
vendor-supported solution. Consequently, there are fewer problems anticipated with drivers,
operations like window resizes, and special events like graphics device loss caused by device
resets or graphics driver updates.

Performance-wise, the general expectation is a somewhat lower CPU usage compared to OpenGL, due to
lower driver overhead, and a higher GPU utilization with less idle time wastage. The backend
doesn't heavily utilize threads yet, which means there are opportunities for further improvements
in the future, for example to further optimize image loading.

The D3D12 backend also introduces support for pre-compiled shaders. All the backend's own shaders
(used by the built-in materials on which the Rectangle, Image, Text, and other QML types are built
with) are compiled to D3D shader bytecode when you compile Qt. Applications using ShaderEffect
items can choose to ship bytecode either in regular files, via the Qt resource system, or use
High Level Shading Language for DirectX (HLSL) source strings. Unlike OpenGL, the compilation for
HLSL is properly threaded, meaning shader compilation won't block the application and its user
interface.

\section2 Graphics Adapters

The plugin does not necessarily require hardware acceleration. You can also use WARP, the Direct3D
software rasterizer. By default, the first adapter providing hardware acceleration is chosen. To
override this and use another graphics adapter or to force the use of the software rasterizer, set
the \c{QT_D3D_ADAPTER_INDEX} environment variable to the index of the adapter. The adapters
discovered are printed at startup when \c{QSG_INFO} or the \c{qt.scenegraph.general} logging
category is enabled.

\section2 Troubleshooting

If you encounter issues, always set the \c{QSG_INFO} and \c{QT_D3D_DEBUG} environment variables
to \c 1, to get debug and warning messages printed on the debug output. \c{QT_D3D_DEBUG} enables
the Direct3D debug layer.

\note The debug layer shouldn't be enabled in production use, since it can significantly impact
performance (CPU load) due to increased API overhead.

\section2 Render Loops

By default, the D3D12 adaptation uses a single-threaded render loop similar to OpenGL's \c windows
render loop. A threaded variant is also available, that you can request by setting the
\c{QSG_RENDER_LOOP} environment variable to \c threaded. However, due to conceptual limitations in
DXGI, the windowing system interface, the threaded loop is prone to deadlocks when multiple
QQuickWindow or QQuickView instances are shown. Consequently, for the time being, the default is
the single-threaded loop. This means that with the D3D12 backend, applications are expected to move
their work from the main (GUI) thread out to worker threads, instead of expecting Qt to keep the
GUI thread responsive and suitable for heavy, blocking operations.

For more information see \l{qtquick-visualcanvas-scenegraph.html}{Qt Quick Scene Graph} for
details on render loops and
\l{https://docs.microsoft.com/en-us/windows/desktop/direct3darticles/dxgi-best-practices#multithreading-and-dxgi}{Multithreading and DXGI}
regarding the issues with multithreading.

\section2 Renderer

The scene graph renderer in the D3D12 adaptation currently doesn't perform any batching. This is
less of an issue, unlike OpenGL, because state changes don't present any problems in the first
place. The simpler renderer logic can also lead to lower CPU overhead in some cases. The trade-offs
between the various approaches are currently under research.

\section2 Shader Effects

The ShaderEffect QML type is fully functional with the D3D12 adaptation as well. However, the
interpretation of the fragmentShader and vertexShader properties is different than with OpenGL.

With D3D12, these strings can either be a URL for a local file, a file in the resource system,
or an HLSL source string. Using a URL for a local file or a file in the resource system
indicates that the file in question contains pre-compiled D3D shader bytecode generated by the
\c fxc tool, or, alternatively, HLSL source code. The type of file is detected automatically.
This means that the D3D12 backend supports all options from GraphicsInfo.shaderCompilationType
and GraphicsInfo.shaderSourceType.

Unlike OpenGL, whenever you open a file, there is a QFileSelector with the extra \c hlsl selector
used. This provides easy creation of ShaderEffect items that are functional across both backends,
for example by placing the GLSL source code into \c{shaders/effect.frag}, the HLSL source code or
- preferably - pre-compiled bytecode into \c{shaders/+hlsl/effect.frag}, while simply writing
\c{fragmentShader: "qrc:shaders/effect.frag"} in QML. For more details, see ShaderEffect.

\section2 Multisample Render Targets

The Direct3D 12 adaptation ignores the QSurfaceFormat set on the QQuickWindow or QQuickView, or
set via QSurfaceFormat::setDefaultFormat(), with two exceptions: QSurfaceFormat::samples() and
QSurfaceFormat::alphaBufferSize() are still taken into account. When the sample value is greater
than 1, multisample offscreen render targets will be created with the specified sample count at
the maximum supported quality level. The backend automatically performs resolving into the
non-multisample swapchain buffers after each frame.

\section2 Semi-transparent Windows

When the alpha channel is enabled either via QQuickWindow::setDefaultAlphaBuffer() or by setting
alphaBufferSize to a non-zero value in the window's QSurfaceFormat or in the global format managed
by QSurfaceFormat::setDefaultFormat(), the D3D12 backend will create a swapchain for composition
and go through DirectComposition. This is necessary, because the mandatory flip model swapchain
wouldn't support transparency otherwise.

Therefore, it's important not to unneccessarily request an alpha channel. When the alphaBufferSize
is 0 or the default -1, all these extra steps can be avoided and the traditional window-based
swapchain is sufficient.

On WinRT, this isn't relevant because the backend there always uses a composition swapchain which
is associated with the ISwapChainPanel that backs QWindow on that platform.

\section2 Mipmaps

Mipmap generation is supported and handled transparently to the applications via a built-in compute
shader. However, at the moment, this feature is experimental and only supports power-of-two images.
Textures of other size will work too, but this involves a QImage-based scaling on the CPU first.
Therefore, avoid enabling mipmapping for Non-Power-Of-Two (NPOT) images whenever possible.

\section2 Image Formats

When creating textures via C++ scene graph APIs like QQuickWindow::createTextureFromImage(), 32-bit
formats won't involve any conversion, they'll map directly to the corresponding \c{R8G8B8A8_UNORM}
or \c{B8G8R8A8_UNORM} format. Everything else will trigger a QImage-based format conversion on the
CPU first.

\section2 Unsupported Features

Particles and some other OpenGL-dependent utilities, like QQuickFramebufferObject, are currently
not supported.

Like with \l{qtquick-visualcanvas-adaptations-software.html}{Software adaptation}, text is always
rendered using the native method. Distance field-based text rendering is currently not implemented.

The shader sources in the \l {Qt Graphical Effects} module have not been ported to any format other
than the OpenGL 2.0 compatible one, meaning that the QML types provided by that module are currently
not functional with the D3D12 backend.

Texture atlases are currently not in use.

The renderer may lack support for certain minor features, such as drawing points and lines with a
width other than 1.

Custom Qt Quick items using custom scene graph nodes can be problematic because materials are
inherently tied to the graphics API. Therefore, only items that use the utility rectangle and image
nodes are functional across all adaptations.

QQuickWidget and its underlying OpenGL-based compositing architecture is not supported. If you need
to mix with QWidget-based user interfaces, use QWidget::createWindowContainer() to embed the native
window of the QQuickWindow or QQuickView.

Finally, rendering via QSGEngine and QSGAbstractRenderer is not feasible with the D3D12 adaptation
at the moment.

\section2 Related APIs

To integrate custom Direct3D 12 rendering, use QSGRenderNode in combination with
QSGRendererInterface. This approach doesn't rely on OpenGL contexts or API specifics like
framebuffers, and allows exposing the graphics device and command buffer from the adaptation. It's
not necessarily suitable for easy integration of all types of content, in particular true 3D, so
it'll likely get complemented by an alternative to QQuickFramebufferObject in future releases.

To perform runtime decisions based on the adaptation, use QSGRendererInterface from C++ and
GraphicsInfo from QML. They can also be used to check the level of shader support: shading
language, compilation approach, and so on.

When creating custom items, use the new QSGRectangleNode and QSGImageNode classes. These replace
the now deprecated QSGSimpleRectNode and QSGSimpleTextureNode. Unlike their predecessors, these new
classes are interfaces, and implementations are created via the QQuickWindow::createRectangleNode()
and QQuickWindow::createImageNode() factory functions.

\section2 Advanced Configuration

The D3D12 adaptation can keep multiple frames in flight, similar to modern game engines. This is
somewhat different from the traditional "render - swap - wait for vsync" model and allows for
better GPU utilization at the expense of higher resource use. This means that the renderer will
be a number of frames ahead of what is displayed on the screen.

For a discussion of flip model swap chains and the typical configuration parameters, refer to
\l{https://software.intel.com/en-us/articles/sample-application-for-direct3d-12-flip-model-swap-chains}
{Sample Application for Direct3D 12 Flip Model Swap Chains}.

Vertical synchronization is always enabled, meaning Present() is invoked with an interval of 1.

The configuration can be changed by setting the following environment variables:

\table
    \header
        \li Environment variable
        \li Description
    \row
        \li \c{QT_D3D_BUFFER_COUNT}
        \li The number of swap chain buffers in range 2 - 4. The default value is 3.
    \row
        \li \c{QT_D3D_FRAME_COUNT}
        \li The number of frames prepared without blocking in range 1 - 4. The default value is 2.
            Present() starts blocking after queuing 3 frames (regardless of
            \c{QT_D3D_BUFFER_COUNT}), unless the waitable object is in use. Every additional frame
            increases GPU resource usage since geometry and constant buffer data needs to be
            duplicated, and involves more bookkeeping on the CPU side.
    \row
        \li \c{QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY}
        \li The frame latency in range 1 - 16. The default value is 0 (disabled).
            Changes the limit for Present() and triggers a wait for an available swap chain buffer
            when beginning each frame. For a detailed discussion, see the article linked above.
            \note Currently, this behavior is experimental.
    \row
        \li \c{QT_D3D_BLOCKING_PRESENT}
        \li The time the CPU should wait, a non-zero value, for the GPU to finish its work after
            each call to Present(). The default value is 0 (disabled). This behavior effectively
            kills all parallelism but makes the behavior resemble the traditional
            swap-blocks-for-vsync model, which can be useful in some special cases. However, this
            behavior is not the same as setting the frame count to 1 because that still avoids
            blocking after Present(), and may only block when starting to prepare the next frame
            (or may not block at all depending on the time gap between the frames).
\endtable

*/

/*!
\title Qt Quick OpenVG Adaptation
\page qtquick-visualcanvas-adaptations-openvg.html

The OpenVG adaptation is an alternative renderer for \l{Qt Quick} 2 that renders the contents of
the scene graph using OpenVG commands to provide hardware accelerated 2D vector and raster
graphics. Much like the \l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation},
some features and optimizations are no longer available. Most Qt Quick 2 applications will run
without modification though any attempts to use unsupported features will be ignored.

\section2 EGL Requirement

Unlike the default OpenGL Renderer, there is no built-in support to acquire an OpenVG context.
This means that the renderer is responsible for requesting and managing the the current context.
To do this, you use EGL directly in the OpenVG renderer. Consequently, the OpenVG renderer can only
be used with platform plugins that support creating QWindows with support for
QSurfaceFormat::OpenVG. From this window, the renderer can get an EGLSurface which can then be used
with an EGLContext to render OpenVG content.

\section2 Renderer

The OpenVG Renderer uses the OpenVG API to send commands and data to a Vector GPU that renders the
scene graph in an accelerated manner, offloading graphics rendering from the CPU. Many operations
like the rendering of rectangles and font glyphs are ideal for OpenVG because they can be
represented as paths which are stroked and filled. Rendering scene graph items that would typically
involve textures are handled in the OpenVG renderer using VGImage. Additionally, when you render
to offscreen surfaces (like with Layers), the scene subtree is rendered to a VGImage which can be
reused in the scene.

\section2 Render Loop

The OpenVG Renderer mirrors the behavior of the Basic render loop and it runs all OpenVG commands
in a single thread.

For more information on render loops, see
\l{qtquick-visualcanvas-scenegraph.html}{Qt Quick Scene Graph}.

\section2 Shader Effects

ShaderEffect components in QtQuick 2 can't be rendered by the OpenVG adaptation. While it's
possible to use ShaderEffectSource and QML Item Layers (which are both offscreen surfaces), it's
not possible to apply shader effects to them via the ShaderEffect item. This is because OpenVG
lacks an API for applying per vertex and per fragment shader operations. However, you may be able
to take advantage of Image Filter operations in the OpenVG API to get effects that are similar to
what ShaderEffects provides in custom items. To integrate custom OpenVG rendering, use
QSGRenderNode in combination with QSGRendererInterface.

\section2 Qt Graphical Effects Module

\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use graphical effects
from this module, then you shouldn't hide the source item so that the original item can still be
rendered.

\section2 Particle Effects

It's not possible to render particle effects with the OpenVG adaptation. Whenever possible, remove
particles completely from the scene. Otherwise they'll still require some processing, even though
they are not visible.

\section2 Rendering Text

Text rendering with the OpenVG adaptation is based on rendering the glyph paths, and doesn't use
the distance fields technique, unlike with the OpenGL backend.

\section2 Perspective Transforms

The OpenVG API doesn't allow paths to be transformed with non-affine transforms, but it's
possible with Qt Quick. Consquently, when you render components using paths like Rectangles and
Text while applying perspective transforms, the OpenVG backend first renders to a VGImage before
applying transformations. This behavior uses more memory at runtime and takes more time; avoid it
if possible.

*/