Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickgraphicsconfiguration.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6#include <QCoreApplication>
7#include <rhi/qrhi.h>
8
10
11/*!
12 \class QQuickGraphicsConfiguration
13 \since 6.0
14 \inmodule QtQuick
15
16 \brief QQuickGraphicsConfiguration controls lower level graphics settings
17 for the QQuickWindow.
18
19 The QQuickGraphicsConfiguration class is a container for low-level graphics
20 settings that can affect how the underlying graphics API, such as Vulkan,
21 is initialized by the Qt Quick scene graph. It can also control certain
22 aspects of the scene graph renderer.
23
24 \note Setting a QQuickGraphicsConfiguration on a QQuickWindow must happen
25 early enough, before the scene graph is initialized for the first time for
26 that window. With on-screen windows this means the call must be done before
27 invoking show() on the QQuickWindow or QQuickView. With QQuickRenderControl
28 the configuration must be finalized before calling
29 \l{QQuickRenderControl::initialize()}{initialize()}.
30
31 \section1 Configuration for External Rendering Engines or XR APIs
32
33 When constructing and showing a QQuickWindow that uses Vulkan to render, a
34 Vulkan instance (\c VkInstance), a physical device (\c VkPhysicalDevice), a
35 device (\c VkDevice) and associated objects (queues, pools) are initialized
36 through the Vulkan API. The same is mostly true when using
37 QQuickRenderControl to redirect the rendering into a custom render target,
38 such as a texture. While QVulkanInstance construction is under the
39 application's control then, the initialization of other graphics objects
40 happen the same way in QQuickRenderControl::initialize() as with an
41 on-screen QQuickWindow.
42
43 For the majority of applications no additional configuration is needed
44 because Qt Quick provides reasonable defaults for many low-level graphics
45 settings, for example which device extensions to enable.
46
47 This will not alway be sufficient, however. In advanced use cases, when
48 integrating direct Vulkan or other graphics API content, or when
49 integrating with an external 3D or VR engine, such as, OpenXR, the
50 application will want to specify its own set of settings when it comes to
51 details, such as which device extensions to enable.
52
53 That is what this class enables. It allows specifying, for example, a list
54 of device extensions that is then picked up by the scene graph when using
55 Vulkan, or graphics APIs where the concept is applicable. Where some
56 concepts are not applicable, the related settings are simply ignored.
57
58 Examples of functions in this category are setDeviceExtensions() and
59 preferredInstanceExtensions(). The latter is useful when the application
60 manages its own \l QVulkanInstance which is then associated with the
61 QQuickWindow via \l QWindow::setVulkanInstance().
62
63 \section1 Qt Quick Scene Graph Renderer Configuration
64
65 Another class of settings are related to the scene graph's renderer. In
66 some cases applications may want to control certain behavior,such as using
67 the depth buffer when rendering 2D content. In Qt 5 such settings were
68 either not controllable at all, or were managed through environment
69 variables. In Qt 6, QQuickGraphicsConfiguration provides a new home for
70 these settings, while keeping support for the legacy environment variables,
71 where applicable.
72
73 An example in this category is setDepthBufferFor2D().
74
75 \section1 Graphics Device Configuration
76
77 When the graphics instance and device objects (for example, the VkInstance
78 and VkDevice with Vulkan, the ID3D11Device with Direct 3D, etc.) are
79 created by Qt when initializing a QQuickWindow, there are settings which
80 applications or libraries will want to control under certain circumstances.
81
82 Before Qt 6.5, some of such settings were available to control via
83 environment variables. For example, \c QSG_RHI_DEBUG_LAYER or \c
84 QSG_RHI_PREFER_SOFTWARE_RENDERER. These are still available and continue to
85 function as before. QQuickGraphicsConfiguration provides C++ setters in
86 addition.
87
88 For example, the following main() function opens a QQuickView while
89 specifying that the Vulkan validation or Direct3D debug layer should be
90 enabled:
91
92 \code
93 int main(int argc, char *argv[])
94 {
95 QGuiApplication app(argc, argv);
96
97 QQuickGraphicsConfiguration config;
98 config.setDebugLayer(true);
99
100 QQuickView *view = new QQuickView;
101 view->setGraphicsConfiguration(config);
102
103 view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
104 view->show();
105 return app.exec();
106 }
107 \endcode
108
109 \section1 Pipeline Cache Save and Load
110
111 Qt Quick supports storing the graphics/compute pipeline cache to disk, and
112 reloading it in subsequent runs of an application. What exactly the
113 pipeline cache contains, how lookups work, and what exactly gets
114 accelerated all depend on the Qt RHI backend and the underlying native
115 graphics API that is used at run time. Different 3D APIs have different
116 concepts when it comes to shaders, programs, and pipeline state objects,
117 and corresponding cache mechanisms. The high level pipeline cache concept
118 here abstracts all this to storing and retrieving a single binary blob to
119 and from a file.
120
121 \note Storing the cache on disk can lead to improvements, sometimes
122 significant, in subsequent runs of the application.
123
124 When the same shader program and/or pipeline state is encountered as in a
125 previous run, a number of operations are likely skipped, leading to faster
126 shader and material initialization times, which means startup may become
127 faster and lags and "janks" during rendering may be reduced or avoided.
128
129 When running with a graphics API where retrieving and reloading the
130 pipeline cache (or shader/program binaries) is not applicable or not
131 supported, attempting to use a file to save and load the cache has no
132 effect.
133
134 \note In many cases the retrieved data is dependent on and tied to the
135 graphics driver (and possibly the exact version of it). Qt performs the
136 necessary checks automatically, by storing additional metadata in the
137 pipeline cache file. If the data in the file does not match the graphics
138 device and driver version at run time, the contents will be ignored
139 transparently to the application. It is therefore safe to reference a cache
140 that was generated on another device or driver.
141
142 There are exceptions to the driver dependency problem, most notably Direct
143 3D 11, where the "pipeline cache" is used only to store the results of
144 runtime HLSL->DXBC compilation and is therefore device and vendor
145 independent.
146
147 In some cases it may be desirable to improve the very first run of the
148 application, by "pre-seeding" the cache. This is possible by shipping the
149 cache file saved from a previous run, and referencing it on another machine
150 or device. This way, the application or device has the shader
151 programs/pipelines that have been encountered before in the run that saved
152 the cache file available already during its first run. Shipping and
153 deploying the cache file only makes sense if the device and graphics
154 drivers are the same on the target system, otherwise the cache file is
155 ignored if the device or driver version does not match (with the exception
156 of D3D11), as described above.
157
158 Once the cache contents is loaded, there is still a chance that the
159 application builds graphics and compute pipelines that have not been
160 encountered in previous runs. In this cases the cache is grown, with the
161 pipelines / shader programs added to it. If the application also chooses to
162 save the contents (perhaps to the same file even), then both the old and
163 new pipelines will get stored. Loading from and saving to the same file in
164 every run allows an ever growing cache that stores all encountered
165 pipelines and shader programs.
166
167 In practice the Qt pipeline cache can be expected to map to the following
168 native graphics API features:
169
170 \list
171
172 \li Vulkan -
173 \l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineCache.html}{VkPipelineCache}
174 - Saving the pipeline cache effectively stores the blob retrieved from
175 \l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetPipelineCacheData.html}{vkGetPipelineCacheData},
176 with additional metadata to safely identify the device and the driver
177 since the pipeline cache blob is dependent on the exact driver.
178
179 \li Metal -
180 \l{https://developer.apple.com/documentation/metal/mtlbinaryarchive?language=objc}{MTLBinaryArchive}
181 - With pipeline cache saving enabled, Qt stores all render and compute
182 pipelines encountered into an MTLBinaryArchive. Saving the pipeline cache
183 stores the blob retrieved from the archive, with additional metadata to
184 identify the device. \b{Note:} currently MTLBinaryArchive usage is disabled
185 on macOS and iOS due to various issues on some hardware and OS versions.
186
187 \li OpenGL - There is no native concept of pipelines, the "pipeline cache"
188 stores a collection of program binaries retrieved via
189 \l{https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetProgramBinary.xhtml}{glGetProgramBinary}.
190 The program binaries are packaged into a single blob, with additional
191 metadata to identify the device, driver, and its version that the binaries
192 were retrieved from. Persistent caching of program binaries is not new in
193 Qt: Qt 5 already had similar functionality in QOpenGLShaderProgram, see
194 \l{QOpenGLShaderProgram::}{addCacheableShaderFromSourceCode()}
195 for example. In fact that mechanism is always active in Qt 6 as well when
196 using Qt Quick with OpenGL. However, when using the new, graphics API
197 independent pipeline cache abstraction provided here, the Qt 5 era program
198 binary cache gets automatically disabled, since the same content is
199 packaged in the "pipeline cache" now.
200
201 \li Direct 3D 11 - There is no native concept of pipelines or retrieving
202 binaries for the second phase compilation (where the vendor independent,
203 intermediate bytecode is compiled into the device specific instruction
204 set). Drivers will typically employ their own caching system on that level.
205 Instead, the Qt Quick "pipeline cache" is used to speed up cases where the
206 shaders contain HLSL source code that needs to be compiled into the
207 intermediate bytecode format first. This can present significant
208 performance improvements in application and libraries that compose shader
209 code at run time, because in subsequent runs the potentially expensive,
210 uncached calls to
211 \l{https://docs.microsoft.com/en-us/windows/win32/api/d3dcompiler/nf-d3dcompiler-d3dcompile}{D3DCompile()}
212 can be avoided if the bytecode is already available for the encountered
213 HLSL shader. A good example is Qt Quick 3D, where the runtime-generated
214 shaders for materials imply having to deal with HLSL source code. Saving
215 and reloading the Qt Quick pipeline cache can therefore bring considerable
216 improvements in scenes with one or more \l{View3D} items in
217 them. A counterexample may be Qt Quick itself: as most built-in shaders for
218 2D content ship with DirectX bytecode generated at build time, the cache is
219 not going to present any significant improvements.
220
221 \endlist
222
223 All this is independent from the shader processing performed by the
224 \l [QtShaderTools]{Qt Shader Tools} module and its command-line tools such
225 as \c qsb. As an example, take Vulkan. Having the Vulkan-compatible GLSL
226 source code compiled to SPIR-V either at offline or build time (directly
227 via qsb or CMake) is good, because the expensive compilation from source
228 form is avoided at run time. SPIR-V is however a vendor-independent
229 intermediate format. At runtime, when constructing graphics or compute
230 pipelines, there is likely another round of compilation happening, this
231 time from the intermediate format to the vendor-specific instruction set of
232 the GPU (and this may be dependent on certain state in the graphics
233 pipeline and the render targets as well). The pipeline cache helps with
234 this latter phase.
235
236 \note Many graphics API implementation employ their own persistent disk
237 cache transparently to the applications. Using the pipeline cache feature
238 of Qt Quick will likely provide improvements in this case, but the gains
239 might be smaller.
240
241 Call setPipelineCacheSaveFile() and setPipelineCacheLoadFile() to control
242 which files a QQuickWindow or QQuickView saves and loads the pipeline cache
243 to/from.
244
245 To get an idea of the effects of enabling disk storage of the pipeline
246 cache, enable the most important scenegraph and graphics logs either via
247 the environment variable \c{QSG_INFO=1}, or both the
248 \c{qt.scenegraph.general} and \c{qt.rhi.general} logging categories. When
249 closing the QQuickWindow, there is log message like the following:
250
251 \badcode
252 Total time spent on pipeline creation during the lifetime of the QRhi was 123 ms
253 \endcode
254
255 This gives an approximate idea of how much time was spent in graphics and
256 compute pipeline creation (which may include various stages of shader
257 compilation) during the lifetime of the window.
258
259 When loading from a pipeline cache file is enabled, this is confirmed with
260 a message:
261
262 \badcode
263 Attempting to seed pipeline cache from 'filename'
264 \endcode
265
266 Similarly, to check if saving of the cache is successfully enabled, look
267 for a message such as this:
268
269 \badcode
270 Writing pipeline cache contents to 'filename'
271 \endcode
272
273 \section1 The Automatic Pipeline Cache
274
275 When no filename is provided for save and load, the automatic pipeline
276 caching strategy is used. This involves storing data to the
277 application-specific cache location of the system (\l
278 QStandardPaths::CacheLocation).
279
280 This can be disabled by one of the following means:
281
282 \list
283
284 \li Set the application attribute Qt::AA_DisableShaderDiskCache.
285 (completely disables the automatic storage)
286
287 \li Set the environment variable QT_DISABLE_SHADER_DISK_CACHE to a non-zero
288 value. (completely disables the automatic storage)
289
290 \li Set the environment variable QSG_RHI_DISABLE_SHADER_DISK_CACHE to a
291 non-zero value. (completely disables the automatic storage)
292
293 \li Call setAutomaticPiplineCache() with the enable argument set to false.
294 (completely disables the automatic storage)
295
296 \li Set a filename by calling setPipelineCacheLoadFile(). (only disables
297 loading from the automatic storage, prefering the specified file instead)
298
299 \li Set a filename by calling setPipelineCacheSaveFile(). (only disables
300 writing to the automatic storage, prefering the specified file instead)
301
302 \endlist
303
304 The first two are existing mechanisms that are used since Qt 5.9 to control
305 the OpenGL program binary cache. For compatibility and familiarity the same
306 attribute and environment variable are supported for Qt 6's enhanced
307 pipeline cache.
308
309 The automatic pipeline cache uses a single file per application, but a
310 different one for each RHI backend (graphics API). This means that changing
311 to another graphics API in the next run of the application will not lead to
312 losing the pipeline cache generated in the previous run. Applications with
313 multiple QQuickWindow instances shown simultaneously may however not
314 benefit 100% since the automatic cache can only store the data collected
315 from one RHI object at a time. (and with the default \c threaded render
316 loop each window has its own RHI as rendering operates independently on
317 dedicated threads). To fully benefit from the disk cache in application
318 with multiple windows, prefer setting the filename explicitly, per-window
319 via setPipelineCacheSaveFile().
320
321 \sa QQuickWindow::setGraphicsConfiguration(), QQuickWindow, QQuickRenderControl
322*/
323
324/*!
325 Constructs a default QQuickGraphicsConfiguration that does not specify any
326 additional settings for the scene graph to take into account.
327 */
328QQuickGraphicsConfiguration::QQuickGraphicsConfiguration()
329 : d(new QQuickGraphicsConfigurationPrivate)
330{
331}
332
333/*!
334 \internal
335 */
336void QQuickGraphicsConfiguration::detach()
337{
338 qAtomicDetach(d);
339}
340
341/*!
342 \internal
343 */
344QQuickGraphicsConfiguration::QQuickGraphicsConfiguration(const QQuickGraphicsConfiguration &other)
345 : d(other.d)
346{
347 d->ref.ref();
348}
349
350/*!
351 \internal
352 */
353QQuickGraphicsConfiguration &QQuickGraphicsConfiguration::operator=(const QQuickGraphicsConfiguration &other)
354{
355 qAtomicAssign(d, other.d);
356 return *this;
357}
358
359/*!
360 Destructor.
361 */
362QQuickGraphicsConfiguration::~QQuickGraphicsConfiguration()
363{
364 if (!d->ref.deref())
365 delete d;
366}
367
368/*!
369 \return the list of Vulkan instance extensions Qt Quick prefers to
370 have enabled on the VkInstance.
371
372 In most cases Qt Quick is responsible for creating a QVulkanInstance. This
373 function is not relevant then. On the other hand, when using
374 QQuickRenderControl in combination with Vulkan-based rendering, it is the
375 application's responsibility to create a QVulkanInstance and associate it
376 with the (offscreen) QQuickWindow. In this case, it is expected that the
377 application queries the list of instance extensions to enable, and passes
378 them to QVulkanInstance::setExtensions() before calling
379 QVulkanInstance::create().
380
381 \since 6.1
382 */
383QByteArrayList QQuickGraphicsConfiguration::preferredInstanceExtensions()
384{
385#if QT_CONFIG(vulkan)
386 return QRhiVulkanInitParams::preferredInstanceExtensions();
387#else
388 return {};
389#endif
390}
391
392/*!
393 Sets the list of additional \a extensions to enable on the graphics device
394 (such as, the \c VkDevice).
395
396 When rendering with a graphics API where the concept is not applicable, \a
397 extensions will be ignored.
398
399 \note The list specifies additional, extra extensions. Qt Quick always
400 enables extensions that are required by the scene graph.
401 */
402void QQuickGraphicsConfiguration::setDeviceExtensions(const QByteArrayList &extensions)
403{
404 if (d->deviceExtensions != extensions) {
405 detach();
406 d->deviceExtensions = extensions;
407 }
408}
409
410/*!
411 \return the list of the requested additional device extensions.
412 */
413QByteArrayList QQuickGraphicsConfiguration::deviceExtensions() const
414{
415 return d->deviceExtensions;
416}
417
418/*!
419 Sets the usage of depth buffer for 2D content to \a enable. When disabled,
420 the Qt Quick scene graph never writes into the depth buffer.
421
422 By default the value is true, unless the \c{QSG_NO_DEPTH_BUFFER}
423 environment variable is set.
424
425 The default value of true is the most optimal setting for the vast majority
426 of scenes. Disabling depth buffer usage reduces the efficiency of the scene
427 graph's batching.
428
429 There are cases however, when allowing the 2D content write to the depth
430 buffer is not ideal. Consider a 3D scene as an "overlay" on top the 2D
431 scene, rendered via Qt Quick 3D using a \l View3D with
432 \l{View3D::renderMode}{renderMode} set to \c Overlay. In this case, having
433 the depth buffer filled by 2D content can cause unexpected results. This is
434 because the way the 2D scene graph renderer generates and handles depth
435 values is not necessarily compatible with how a 3D scene works. This may end
436 up in depth value clashes, collisions, and unexpected depth test
437 failures. Therefore, the robust approach here is to call this function with
438 \a enable set to false, and disable depth buffer writes for the 2D content
439 in the QQuickWindow.
440
441 \note This flag is not fully identical to setting the
442 \c{QSG_NO_DEPTH_BUFFER} environment variable. This flag does not control the
443 depth-stencil buffers' presence. It is rather relevant for the rendering
444 pipeline. To force not having depth/stencil attachments at all, set
445 \c{QSG_NO_DEPTH_BUFFER} and \c{QSG_NO_STENCIL_BUFFER}. Be aware however
446 that such a QQuickWindow, and any Item layers in it, may then become
447 incompatible with items, such as View3D with certain operating modes,
448 because 3D content requires a depth buffer. Calling this function is always
449 safe, but can mean that resources, such as depth buffers, are created even
450 though they are not actively used.
451 */
452void QQuickGraphicsConfiguration::setDepthBufferFor2D(bool enable)
453{
454 if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::UseDepthBufferFor2D) != enable) {
455 detach();
456 d->flags.setFlag(QQuickGraphicsConfigurationPrivate::UseDepthBufferFor2D, enable);
457 }
458}
459
460/*!
461 \return true if depth buffer usage is enabled for 2D content.
462
463 By default the value is true, unless the \c{QSG_NO_DEPTH_BUFFER}
464 environment variable is set.
465 */
466bool QQuickGraphicsConfiguration::isDepthBufferEnabledFor2D() const
467{
468 return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::UseDepthBufferFor2D);
469}
470
471/*!
472 Enables the graphics API implementation's debug or validation layers, if
473 available.
474
475 In practice this is supported with Vulkan and Direct 3D 11, assuming the
476 necessary support (validation layers, Windows SDK) is installed and
477 available at runtime. When \a enable is true, Qt will attempt to enable the
478 standard validation layer on the VkInstance, or set
479 \c{D3D11_CREATE_DEVICE_DEBUG} on the graphics device.
480
481 For Metal on \macos, set the environment variable
482 \c{METAL_DEVICE_WRAPPER_TYPE=1} instead before launching the application.
483
484 Calling this function with \a enable set to true is equivalent to setting
485 the environment variable \c{QSG_RHI_DEBUG_LAYER} to a non-zero value.
486
487 The default value is false.
488
489 \note Enabling debug or validation layers may have a non-insignificant
490 performance impact. Shipping applications to production with the flag
491 enabled is strongly discouraged.
492
493 \note Be aware that due to differences in the design of the underlying
494 graphics APIs, this setting cannot always be a per-QQuickWindow setting,
495 even though each QQuickWindow has their own QQuickGraphicsConfiguration.
496 With Vulkan in particular, the instance object (VkInstance) is only created
497 once and then used by all windows in the application. Therefore, enabling
498 the validation layer is something that affects all windows. This also means
499 that attempting to enable validation via a window that only gets shown after
500 some other windows have already started rendering has no effect with Vulkan.
501 Other APIs, such as D3D11, expose the debug layer concept as a per-device
502 (ID3D11Device) setting, and so it is controlled on a true per-window basis
503 (assuming the scenegraph render loop uses a dedicated graphics
504 device/context for each QQuickWindow).
505
506 \since 6.5
507
508 \sa isDebugLayerEnabled()
509 */
510void QQuickGraphicsConfiguration::setDebugLayer(bool enable)
511{
512 if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableDebugLayer) != enable) {
513 detach();
514 d->flags.setFlag(QQuickGraphicsConfigurationPrivate::EnableDebugLayer, enable);
515 }
516}
517
518/*!
519 \return true if the debug/validation layers are to be enabled.
520
521 By default the value is false.
522
523 \sa setDebugLayer()
524 */
525bool QQuickGraphicsConfiguration::isDebugLayerEnabled() const
526{
527 return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableDebugLayer);
528}
529
530/*!
531 Where applicable, \a enable controls inserting debug markers and object
532 names into the graphics command stream.
533
534 Some frameworks, such as Qt Quick 3D, have the ability to annotate the
535 graphics objects they create (buffers, textures) with names and also
536 indicate the beginning and end of render passes in the command buffer. These
537 are then visible in frame captures made with tools like
538 \l{https://renderdoc.org/}{RenderDoc} or XCode.
539
540 Graphics APIs where this can be expected to be supported are Vulkan (if
541 VK_EXT_debug_utils is available), Direct 3D 11, and Metal.
542
543 Calling this function with \a enable set to true is equivalent to setting
544 the environment variable \c{QSG_RHI_PROFILE} to a non-zero
545 value.
546
547 The default value is false.
548
549 \note Enabling debug markers may have a performance impact. Shipping
550 applications to production with the flag enabled is not recommended.
551
552 \since 6.5
553
554 \sa isDebugMarkersEnabled()
555 */
556void QQuickGraphicsConfiguration::setDebugMarkers(bool enable)
557{
558 if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableDebugMarkers) != enable) {
559 detach();
560 d->flags.setFlag(QQuickGraphicsConfigurationPrivate::EnableDebugMarkers, enable);
561 }
562}
563
564/*!
565 \return true if debug markers are enabled.
566
567 By default the value is false.
568
569 \sa setDebugMarkers()
570 */
571bool QQuickGraphicsConfiguration::isDebugMarkersEnabled() const
572{
573 return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableDebugMarkers);
574}
575
576/*!
577 When enabled, GPU timing data is collected from command buffers on
578 platforms and 3D APIs where this is supported. This data is then printed in
579 the renderer logs that can be enabled via \c{QSG_RENDER_TIMING} environment
580 variable or logging categories such as \c{qt.scenegraph.time.renderloop},
581 and may also be made visible to other modules, such as Qt Quick 3D's
582 \l DebugView item.
583
584 By default this is disabled, because collecting the data may involve
585 additional work, such as inserting timestamp queries in the command stream,
586 depending on the underlying graphics API. To enable, either call this
587 function with \a enable set to true, or set the \c{QSG_RHI_PROFILE}
588 environment variable to a non-zero value.
589
590 Graphics APIs where this can be expected to be supported are Direct 3D 11,
591 Direct 3D 12, Vulkan (as long as the underlying Vulkan implementation
592 supports timestamp queries), Metal, and OpenGL with a core or compatibility
593 profile context for version 3.3 or newer. Timestamps are not supported with
594 OpenGL ES.
595
596 \since 6.6
597
598 \sa timestampsEnabled(), setDebugMarkers()
599 */
600void QQuickGraphicsConfiguration::setTimestamps(bool enable)
601{
602 if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableTimestamps) != enable) {
603 detach();
604 d->flags.setFlag(QQuickGraphicsConfigurationPrivate::EnableTimestamps, enable);
605 }
606}
607
608/*!
609 \return true if GPU timing collection is enabled.
610
611 By default the value is false.
612
613 \since 6.6
614 \sa setTimestamps()
615 */
616bool QQuickGraphicsConfiguration::timestampsEnabled() const
617{
618 return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableTimestamps);
619}
620
621/*!
622 Requests choosing an adapter or physical device that uses software-based
623 rasterization. Applicable only when the underlying API has support for
624 enumerating adapters (for example, Direct 3D or Vulkan), and is ignored
625 otherwise.
626
627 If the graphics API implementation has no such graphics adapter or physical
628 device available, the request is ignored. With Direct 3D it can be expected
629 that a
630 \l{https://docs.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp}{WARP}-based
631 rasterizer is always available. With Vulkan, the flag only has an effect if
632 Mesa's \c lavapipe, or some other physical device reporting
633 \c{VK_PHYSICAL_DEVICE_TYPE_CPU} is available.
634
635 Calling this function with \a enable set to true is equivalent to setting
636 the environment variable \c{QSG_RHI_PREFER_SOFTWARE_RENDERER} to a non-zero
637 value.
638
639 The default value is false.
640
641 \since 6.5
642
643 \sa prefersSoftwareDevice()
644 */
645void QQuickGraphicsConfiguration::setPreferSoftwareDevice(bool enable)
646{
647 if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::PreferSoftwareDevice) != enable) {
648 detach();
649 d->flags.setFlag(QQuickGraphicsConfigurationPrivate::PreferSoftwareDevice, enable);
650 }
651}
652
653/*!
654 \return true if a software rasterizer-based graphics device is prioritized.
655
656 By default the value is false.
657
658 \sa setPreferSoftwareDevice()
659 */
660bool QQuickGraphicsConfiguration::prefersSoftwareDevice() const
661{
662 return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::PreferSoftwareDevice);
663}
664
665/*!
666 Changes the usage of the automatic pipeline cache based on \a enable.
667
668 The default value is true, unless certain application attributes or
669 environment variables are set. See \l{The Automatic Pipeline Cache} for
670 more information.
671
672 \since 6.5
673
674 \sa isAutomaticPipelineCacheEnabled()
675 */
676void QQuickGraphicsConfiguration::setAutomaticPipelineCache(bool enable)
677{
678 if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::AutoPipelineCache) != enable) {
679 detach();
680 d->flags.setFlag(QQuickGraphicsConfigurationPrivate::AutoPipelineCache, enable);
681 }
682}
683
684/*!
685 \return true if the automatic pipeline cache is enabled.
686
687 By default this is true, unless certain application attributes or
688 environment variables are set. See \l{The Automatic Pipeline Cache} for
689 more information.
690
691 \since 6.5
692
693 \sa setAutomaticPipelineCache()
694 */
695bool QQuickGraphicsConfiguration::isAutomaticPipelineCacheEnabled() const
696{
697 return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::AutoPipelineCache);
698}
699
700/*!
701 Sets the \a filename where the QQuickWindow is expected to store its
702 graphics/compute pipeline cache contents. The default value is empty, which
703 means pipeline cache loading is disabled.
704
705 See \l{Pipeline Cache Save and Load} for a discussion on pipeline caches.
706
707 Persistently storing the pipeline cache can lead to performance
708 improvements in future runs of the application since expensive shader
709 compilation and pipeline construction steps may be avoided.
710
711 If and when the writing of the file happens is not defined. It will likely
712 happen at some point when tearing down the scenegraph due to closing the
713 window. Therefore, applications should not assume availability of the file
714 until the QQuickWindow is fully destructed. QQuickGraphicsConfiguration
715 only stores the filename, it does not perform any actual I/O and graphics
716 operations on its own.
717
718 When running with a graphics API where retrieving the pipeline cache (or
719 shader/program binaries) is not applicable or not supported, calling this
720 function has no effect.
721
722 Calling this function is mostly equivalent to setting the environment
723 variable \c{QSG_RHI_PIPELINE_CACHE_SAVE} to \a filename, with one important
724 difference: this function controls the pipeline cache storage for the
725 associated QQuickWindow only. Applications with multiple QQuickWindow or
726 QQuickView instances can therefore store and later reload the cache contents
727 via files dedicated to each window. The environment variable does not allow
728 this.
729
730 \since 6.5
731
732 \sa pipelineCacheLoadFile(), pipelineCacheSaveFile()
733 */
734void QQuickGraphicsConfiguration::setPipelineCacheSaveFile(const QString &filename)
735{
736 if (d->pipelineCacheSaveFile != filename) {
737 detach();
738 d->pipelineCacheSaveFile = filename;
739 }
740}
741
742/*!
743 \return the currently set filename for storing the pipeline cache.
744
745 By default the value is an empty string.
746 */
747QString QQuickGraphicsConfiguration::pipelineCacheSaveFile() const
748{
749 return d->pipelineCacheSaveFile;
750}
751
752/*!
753 Sets the \a filename where the QQuickWindow is expected to load the initial
754 contents of its graphics/compute pipeline cache from. The default value is
755 empty, which means pipeline cache loading is disabled.
756
757 See \l{Pipeline Cache Save and Load} for a discussion on pipeline caches.
758
759 Persistently storing the pipeline cache can lead to performance
760 improvements in future runs of the application since expensive shader
761 compilation and pipeline construction steps may be avoided.
762
763 If and when the loading of the file's contents happens is not defined, apart
764 from that it will happen at some point during the initialization of the
765 scenegraph of the QQuickWindow. Therefore, the file must continue to exist
766 after calling this function. QQuickGraphicsConfiguration only stores the
767 filename, it cannot perform any actual I/O and graphics operations on its
768 own. The real work is going to happen later on, possibly on another thread.
769
770 When running with a graphics API where retrieving and reloading the
771 pipeline cache (or shader/program binaries) is not applicable or not
772 supported, calling this function has no effect.
773
774 Calling this function is mostly equivalent to setting the environment
775 variable \c{QSG_RHI_PIPELINE_CACHE_LOAD} to \a filename, with one important
776 difference: this function controls the pipeline cache storage for the
777 associated QQuickWindow only. Applications with multiple QQuickWindow or
778 QQuickView instances can therefore store and later reload the cache contents
779 via files dedicated to each window. The environment variable does not allow
780 this.
781
782 \note If the data in the file does not match the graphics device and driver
783 version at run time, the contents will be ignored, transparently to the
784 application. This applies to a number of graphics APIs, and the necessary
785 checks are taken care of by Qt. There are exceptions, most notably Direct
786 3D 11, where the "pipeline cache" is used only to store the results of
787 runtime HLSL->DXBC compilation and is therefore device and vendor
788 independent.
789
790 \warning The serialized pipeline cache data is assumed to be trusted
791 content. Application developers are advised to never pass in data from
792 untrusted sources.
793
794 \since 6.5
795
796 \sa pipelineCacheLoadFile(), setPipelineCacheSaveFile()
797 */
798void QQuickGraphicsConfiguration::setPipelineCacheLoadFile(const QString &filename)
799{
800 if (d->pipelineCacheLoadFile != filename) {
801 detach();
802 d->pipelineCacheLoadFile = filename;
803 }
804}
805
806/*!
807 \return the currently set filename for loading the pipeline cache.
808
809 By default the value is an empty string.
810 */
811QString QQuickGraphicsConfiguration::pipelineCacheLoadFile() const
812{
813 return d->pipelineCacheLoadFile;
814}
815
816QQuickGraphicsConfigurationPrivate::QQuickGraphicsConfigurationPrivate()
817 : ref(1)
818{
819 // Defaults based on env.vars. NB! many of these variables are documented
820 // and should be considered (semi-)public API. Changing the env.var. names
821 // is therefore not allowed.
822
823 flags = {};
824
825 static const bool useDepthBufferFor2D = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
826 if (useDepthBufferFor2D)
827 flags |= UseDepthBufferFor2D;
828
829 static const bool enableDebugLayer = qEnvironmentVariableIntValue("QSG_RHI_DEBUG_LAYER");
830 if (enableDebugLayer)
831 flags |= EnableDebugLayer;
832
833 static const bool enableProfilingRelated = qEnvironmentVariableIntValue("QSG_RHI_PROFILE");
834 if (enableProfilingRelated)
835 flags |= EnableDebugMarkers | EnableTimestamps;
836
837 static const bool preferSoftwareDevice = qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER");
838 if (preferSoftwareDevice)
839 flags |= PreferSoftwareDevice;
840
841 // here take the existing QOpenGL disk cache attribute and env.var. into account as well
842 static const bool autoPipelineCache = !QCoreApplication::instance()->testAttribute(Qt::AA_DisableShaderDiskCache)
843 && !qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")
844 && !qEnvironmentVariableIntValue("QSG_RHI_DISABLE_DISK_CACHE");
845 if (autoPipelineCache)
846 flags |= AutoPipelineCache;
847
848 static const QString pipelineCacheSaveFileEnv = qEnvironmentVariable("QSG_RHI_PIPELINE_CACHE_SAVE");
849 pipelineCacheSaveFile = pipelineCacheSaveFileEnv;
850
851 static const QString pipelineCacheLoadFileEnv = qEnvironmentVariable("QSG_RHI_PIPELINE_CACHE_LOAD");
852 pipelineCacheLoadFile = pipelineCacheLoadFileEnv;
853}
854
855QQuickGraphicsConfigurationPrivate::QQuickGraphicsConfigurationPrivate(const QQuickGraphicsConfigurationPrivate &other)
856 : ref(1),
857 deviceExtensions(other.deviceExtensions),
858 flags(other.flags),
859 pipelineCacheSaveFile(other.pipelineCacheSaveFile),
860 pipelineCacheLoadFile(other.pipelineCacheLoadFile)
861{
862}
863
864#ifndef QT_NO_DEBUG_STREAM
865QDebug operator<<(QDebug dbg, const QQuickGraphicsConfiguration &config)
866{
867 QDebugStateSaver saver(dbg);
868 const QQuickGraphicsConfigurationPrivate *cd = QQuickGraphicsConfigurationPrivate::get(&config);
869 dbg.nospace() << "QQuickGraphicsConfiguration("
870 << "flags=0x" << Qt::hex << cd->flags << Qt::dec
871 << " flag-isDepthBufferEnabledFor2D=" << config.isDepthBufferEnabledFor2D()
872 << " flag-isDebugLayerEnabled=" << config.isDebugLayerEnabled()
873 << " flag-isDebugMarkersEnabled=" << config.isDebugMarkersEnabled()
874 << " flag-prefersSoftwareDevice=" << config.prefersSoftwareDevice()
875 << " flag-isAutomaticPipelineCacheEnabled=" << config.isAutomaticPipelineCacheEnabled()
876 << " pipelineCacheSaveFile=" << cd->pipelineCacheSaveFile
877 << " piplineCacheLoadFile=" << cd->pipelineCacheLoadFile
878 << " extra-device-extension-requests=" << cd->deviceExtensions
879 << ')';
880 return dbg;
881}
882#endif // QT_NO_DEBUG_STREAM
883
884QT_END_NAMESPACE
QDebug operator<<(QDebug dbg, const QFileInfo &fi)