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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/quick/items/qquickgraphicsconfiguration.cpp