aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickgraphicsconfiguration.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickgraphicsconfiguration.cpp')
-rw-r--r--src/quick/items/qquickgraphicsconfiguration.cpp743
1 files changed, 680 insertions, 63 deletions
diff --git a/src/quick/items/qquickgraphicsconfiguration.cpp b/src/quick/items/qquickgraphicsconfiguration.cpp
index 3e499ff12d..1cfa160e18 100644
--- a/src/quick/items/qquickgraphicsconfiguration.cpp
+++ b/src/quick/items/qquickgraphicsconfiguration.cpp
@@ -1,47 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquickgraphicsconfiguration_p.h"
-
-#if QT_CONFIG(vulkan)
-#include <QtGui/private/qrhivulkan_p.h>
-#endif
+#include <QCoreApplication>
+#include <rhi/qrhi.h>
QT_BEGIN_NAMESPACE
@@ -50,10 +12,22 @@ QT_BEGIN_NAMESPACE
\since 6.0
\inmodule QtQuick
- \brief The QQuickGraphicsConfiguration class is a container for low-level
- graphics settings that can affect how the underlying graphics API, such as
- Vulkan, is initialized by the Qt Quick scene graph. It can also control
- certain aspects of the scene graph renderer.
+ \brief QQuickGraphicsConfiguration controls lower level graphics settings
+ for the QQuickWindow.
+
+ The QQuickGraphicsConfiguration class is a container for low-level graphics
+ settings that can affect how the underlying graphics API, such as Vulkan,
+ is initialized by the Qt Quick scene graph. It can also control certain
+ aspects of the scene graph renderer.
+
+ \note Setting a QQuickGraphicsConfiguration on a QQuickWindow must happen
+ early enough, before the scene graph is initialized for the first time for
+ that window. With on-screen windows this means the call must be done before
+ invoking show() on the QQuickWindow or QQuickView. With QQuickRenderControl
+ the configuration must be finalized before calling
+ \l{QQuickRenderControl::initialize()}{initialize()}.
+
+ \section1 Configuration for External Rendering Engines or XR APIs
When constructing and showing a QQuickWindow that uses Vulkan to render, a
Vulkan instance (\c VkInstance), a physical device (\c VkPhysicalDevice), a
@@ -80,6 +54,13 @@ QT_BEGIN_NAMESPACE
Vulkan, or graphics APIs where the concept is applicable. Where some
concepts are not applicable, the related settings are simply ignored.
+ Examples of functions in this category are setDeviceExtensions() and
+ preferredInstanceExtensions(). The latter is useful when the application
+ manages its own \l QVulkanInstance which is then associated with the
+ QQuickWindow via \l QWindow::setVulkanInstance().
+
+ \section1 Qt Quick Scene Graph Renderer Configuration
+
Another class of settings are related to the scene graph's renderer. In
some cases applications may want to control certain behavior,such as using
the depth buffer when rendering 2D content. In Qt 5 such settings were
@@ -88,12 +69,253 @@ QT_BEGIN_NAMESPACE
these settings, while keeping support for the legacy environment variables,
where applicable.
- \note Setting a QQuickGraphicsConfiguration on a QQuickWindow must happen
- early enough, before the scene graph is initialized for the first time for
- that window. With on-screen windows this means the call must be done before
- invoking show() on the QQuickWindow or QQuickView. With QQuickRenderControl
- the configuration must be finalized before calling
- \l{QQuickRenderControl::initialize()}{initialize()}.
+ An example in this category is setDepthBufferFor2D().
+
+ \section1 Graphics Device Configuration
+
+ When the graphics instance and device objects (for example, the VkInstance
+ and VkDevice with Vulkan, the ID3D11Device with Direct 3D, etc.) are
+ created by Qt when initializing a QQuickWindow, there are settings which
+ applications or libraries will want to control under certain circumstances.
+
+ Before Qt 6.5, some of such settings were available to control via
+ environment variables. For example, \c QSG_RHI_DEBUG_LAYER or \c
+ QSG_RHI_PREFER_SOFTWARE_RENDERER. These are still available and continue to
+ function as before. QQuickGraphicsConfiguration provides C++ setters in
+ addition.
+
+ For example, the following main() function opens a QQuickView while
+ specifying that the Vulkan validation or Direct3D debug layer should be
+ enabled:
+
+ \code
+ int main(int argc, char *argv[])
+ {
+ QGuiApplication app(argc, argv);
+
+ QQuickGraphicsConfiguration config;
+ config.setDebugLayer(true);
+
+ QQuickView *view = new QQuickView;
+ view->setGraphicsConfiguration(config);
+
+ view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
+ view->show();
+ return app.exec();
+ }
+ \endcode
+
+ \section1 Pipeline Cache Save and Load
+
+ Qt Quick supports storing the graphics/compute pipeline cache to disk, and
+ reloading it in subsequent runs of an application. What exactly the
+ pipeline cache contains, how lookups work, and what exactly gets
+ accelerated all depend on the Qt RHI backend and the underlying native
+ graphics API that is used at run time. Different 3D APIs have different
+ concepts when it comes to shaders, programs, and pipeline state objects,
+ and corresponding cache mechanisms. The high level pipeline cache concept
+ here abstracts all this to storing and retrieving a single binary blob to
+ and from a file.
+
+ \note Storing the cache on disk can lead to improvements, sometimes
+ significant, in subsequent runs of the application.
+
+ When the same shader program and/or pipeline state is encountered as in a
+ previous run, a number of operations are likely skipped, leading to faster
+ shader and material initialization times, which means startup may become
+ faster and lags and "janks" during rendering may be reduced or avoided.
+
+ When running with a graphics API where retrieving and reloading the
+ pipeline cache (or shader/program binaries) is not applicable or not
+ supported, attempting to use a file to save and load the cache has no
+ effect.
+
+ \note In many cases the retrieved data is dependent on and tied to the
+ graphics driver (and possibly the exact version of it). Qt performs the
+ necessary checks automatically, by storing additional metadata in the
+ pipeline cache file. If the data in the file does not match the graphics
+ device and driver version at run time, the contents will be ignored
+ transparently to the application. It is therefore safe to reference a cache
+ that was generated on another device or driver.
+
+ There are exceptions to the driver dependency problem, most notably Direct
+ 3D 11, where the "pipeline cache" is used only to store the results of
+ runtime HLSL->DXBC compilation and is therefore device and vendor
+ independent.
+
+ In some cases it may be desirable to improve the very first run of the
+ application, by "pre-seeding" the cache. This is possible by shipping the
+ cache file saved from a previous run, and referencing it on another machine
+ or device. This way, the application or device has the shader
+ programs/pipelines that have been encountered before in the run that saved
+ the cache file available already during its first run. Shipping and
+ deploying the cache file only makes sense if the device and graphics
+ drivers are the same on the target system, otherwise the cache file is
+ ignored if the device or driver version does not match (with the exception
+ of D3D11), as described above.
+
+ Once the cache contents is loaded, there is still a chance that the
+ application builds graphics and compute pipelines that have not been
+ encountered in previous runs. In this cases the cache is grown, with the
+ pipelines / shader programs added to it. If the application also chooses to
+ save the contents (perhaps to the same file even), then both the old and
+ new pipelines will get stored. Loading from and saving to the same file in
+ every run allows an ever growing cache that stores all encountered
+ pipelines and shader programs.
+
+ In practice the Qt pipeline cache can be expected to map to the following
+ native graphics API features:
+
+ \list
+
+ \li Vulkan -
+ \l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineCache.html}{VkPipelineCache}
+ - Saving the pipeline cache effectively stores the blob retrieved from
+ \l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetPipelineCacheData.html}{vkGetPipelineCacheData},
+ with additional metadata to safely identify the device and the driver
+ since the pipeline cache blob is dependent on the exact driver.
+
+ \li Metal -
+ \l{https://developer.apple.com/documentation/metal/mtlbinaryarchive?language=objc}{MTLBinaryArchive}
+ - With pipeline cache saving enabled, Qt stores all render and compute
+ pipelines encountered into an MTLBinaryArchive. Saving the pipeline cache
+ stores the blob retrieved from the archive, with additional metadata to
+ identify the device. \b{Note:} currently MTLBinaryArchive usage is disabled
+ on macOS and iOS due to various issues on some hardware and OS versions.
+
+ \li OpenGL - There is no native concept of pipelines, the "pipeline cache"
+ stores a collection of program binaries retrieved via
+ \l{https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetProgramBinary.xhtml}{glGetProgramBinary}.
+ The program binaries are packaged into a single blob, with additional
+ metadata to identify the device, driver, and its version that the binaries
+ were retrieved from. Persistent caching of program binaries is not new in
+ Qt: Qt 5 already had similar functionality in QOpenGLShaderProgram, see
+ \l{QOpenGLShaderProgram::}{addCacheableShaderFromSourceCode()}
+ for example. In fact that mechanism is always active in Qt 6 as well when
+ using Qt Quick with OpenGL. However, when using the new, graphics API
+ independent pipeline cache abstraction provided here, the Qt 5 era program
+ binary cache gets automatically disabled, since the same content is
+ packaged in the "pipeline cache" now.
+
+ \li Direct 3D 11 - There is no native concept of pipelines or retrieving
+ binaries for the second phase compilation (where the vendor independent,
+ intermediate bytecode is compiled into the device specific instruction
+ set). Drivers will typically employ their own caching system on that level.
+ Instead, the Qt Quick "pipeline cache" is used to speed up cases where the
+ shaders contain HLSL source code that needs to be compiled into the
+ intermediate bytecode format first. This can present significant
+ performance improvements in application and libraries that compose shader
+ code at run time, because in subsequent runs the potentially expensive,
+ uncached calls to
+ \l{https://docs.microsoft.com/en-us/windows/win32/api/d3dcompiler/nf-d3dcompiler-d3dcompile}{D3DCompile()}
+ can be avoided if the bytecode is already available for the encountered
+ HLSL shader. A good example is Qt Quick 3D, where the runtime-generated
+ shaders for materials imply having to deal with HLSL source code. Saving
+ and reloading the Qt Quick pipeline cache can therefore bring considerable
+ improvements in scenes with one or more \l{View3D} items in
+ them. A counterexample may be Qt Quick itself: as most built-in shaders for
+ 2D content ship with DirectX bytecode generated at build time, the cache is
+ not going to present any significant improvements.
+
+ \endlist
+
+ All this is independent from the shader processing performed by the
+ \l [QtShaderTools]{Qt Shader Tools} module and its command-line tools such
+ as \c qsb. As an example, take Vulkan. Having the Vulkan-compatible GLSL
+ source code compiled to SPIR-V either at offline or build time (directly
+ via qsb or CMake) is good, because the expensive compilation from source
+ form is avoided at run time. SPIR-V is however a vendor-independent
+ intermediate format. At runtime, when constructing graphics or compute
+ pipelines, there is likely another round of compilation happening, this
+ time from the intermediate format to the vendor-specific instruction set of
+ the GPU (and this may be dependent on certain state in the graphics
+ pipeline and the render targets as well). The pipeline cache helps with
+ this latter phase.
+
+ \note Many graphics API implementation employ their own persistent disk
+ cache transparently to the applications. Using the pipeline cache feature
+ of Qt Quick will likely provide improvements in this case, but the gains
+ might be smaller.
+
+ Call setPipelineCacheSaveFile() and setPipelineCacheLoadFile() to control
+ which files a QQuickWindow or QQuickView saves and loads the pipeline cache
+ to/from.
+
+ To get an idea of the effects of enabling disk storage of the pipeline
+ cache, enable the most important scenegraph and graphics logs either via
+ the environment variable \c{QSG_INFO=1}, or both the
+ \c{qt.scenegraph.general} and \c{qt.rhi.general} logging categories. When
+ closing the QQuickWindow, there is log message like the following:
+
+ \badcode
+ Total time spent on pipeline creation during the lifetime of the QRhi was 123 ms
+ \endcode
+
+ This gives an approximate idea of how much time was spent in graphics and
+ compute pipeline creation (which may include various stages of shader
+ compilation) during the lifetime of the window.
+
+ When loading from a pipeline cache file is enabled, this is confirmed with
+ a message:
+
+ \badcode
+ Attempting to seed pipeline cache from 'filename'
+ \endcode
+
+ Similarly, to check if saving of the cache is successfully enabled, look
+ for a message such as this:
+
+ \badcode
+ Writing pipeline cache contents to 'filename'
+ \endcode
+
+ \section1 The Automatic Pipeline Cache
+
+ When no filename is provided for save and load, the automatic pipeline
+ caching strategy is used. This involves storing data to the
+ application-specific cache location of the system (\l
+ QStandardPaths::CacheLocation).
+
+ This can be disabled by one of the following means:
+
+ \list
+
+ \li Set the application attribute Qt::AA_DisableShaderDiskCache.
+ (completely disables the automatic storage)
+
+ \li Set the environment variable QT_DISABLE_SHADER_DISK_CACHE to a non-zero
+ value. (completely disables the automatic storage)
+
+ \li Set the environment variable QSG_RHI_DISABLE_SHADER_DISK_CACHE to a
+ non-zero value. (completely disables the automatic storage)
+
+ \li Call setAutomaticPiplineCache() with the enable argument set to false.
+ (completely disables the automatic storage)
+
+ \li Set a filename by calling setPipelineCacheLoadFile(). (only disables
+ loading from the automatic storage, prefering the specified file instead)
+
+ \li Set a filename by calling setPipelineCacheSaveFile(). (only disables
+ writing to the automatic storage, prefering the specified file instead)
+
+ \endlist
+
+ The first two are existing mechanisms that are used since Qt 5.9 to control
+ the OpenGL program binary cache. For compatibility and familiarity the same
+ attribute and environment variable are supported for Qt 6's enhanced
+ pipeline cache.
+
+ The automatic pipeline cache uses a single file per application, but a
+ different one for each RHI backend (graphics API). This means that changing
+ to another graphics API in the next run of the application will not lead to
+ losing the pipeline cache generated in the previous run. Applications with
+ multiple QQuickWindow instances shown simultaneously may however not
+ benefit 100% since the automatic cache can only store the data collected
+ from one RHI object at a time. (and with the default \c threaded render
+ loop each window has its own RHI as rendering operates independently on
+ dedicated threads). To fully benefit from the disk cache in application
+ with multiple windows, prefer setting the filename explicitly, per-window
+ via setPipelineCacheSaveFile().
\sa QQuickWindow::setGraphicsConfiguration(), QQuickWindow, QQuickRenderControl
*/
@@ -185,6 +407,14 @@ void QQuickGraphicsConfiguration::setDeviceExtensions(const QByteArrayList &exte
}
/*!
+ \return the list of the requested additional device extensions.
+ */
+QByteArrayList QQuickGraphicsConfiguration::deviceExtensions() const
+{
+ return d->deviceExtensions;
+}
+
+/*!
Sets the usage of depth buffer for 2D content to \a enable. When disabled,
the Qt Quick scene graph never writes into the depth buffer.
@@ -220,9 +450,9 @@ void QQuickGraphicsConfiguration::setDeviceExtensions(const QByteArrayList &exte
*/
void QQuickGraphicsConfiguration::setDepthBufferFor2D(bool enable)
{
- if (d->useDepthBufferFor2D != enable) {
+ if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::UseDepthBufferFor2D) != enable) {
detach();
- d->useDepthBufferFor2D = enable;
+ d->flags.setFlag(QQuickGraphicsConfigurationPrivate::UseDepthBufferFor2D, enable);
}
}
@@ -234,29 +464,416 @@ void QQuickGraphicsConfiguration::setDepthBufferFor2D(bool enable)
*/
bool QQuickGraphicsConfiguration::isDepthBufferEnabledFor2D() const
{
- return d->useDepthBufferFor2D;
+ return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::UseDepthBufferFor2D);
}
/*!
- \return the list of the requested additional device extensions.
+ Enables the graphics API implementation's debug or validation layers, if
+ available.
+
+ In practice this is supported with Vulkan and Direct 3D 11, assuming the
+ necessary support (validation layers, Windows SDK) is installed and
+ available at runtime. When \a enable is true, Qt will attempt to enable the
+ standard validation layer on the VkInstance, or set
+ \c{D3D11_CREATE_DEVICE_DEBUG} on the graphics device.
+
+ For Metal on \macos, set the environment variable
+ \c{METAL_DEVICE_WRAPPER_TYPE=1} instead before launching the application.
+
+ Calling this function with \a enable set to true is equivalent to setting
+ the environment variable \c{QSG_RHI_DEBUG_LAYER} to a non-zero value.
+
+ The default value is false.
+
+ \note Enabling debug or validation layers may have a non-insignificant
+ performance impact. Shipping applications to production with the flag
+ enabled is strongly discouraged.
+
+ \note Be aware that due to differences in the design of the underlying
+ graphics APIs, this setting cannot always be a per-QQuickWindow setting,
+ even though each QQuickWindow has their own QQuickGraphicsConfiguration.
+ With Vulkan in particular, the instance object (VkInstance) is only created
+ once and then used by all windows in the application. Therefore, enabling
+ the validation layer is something that affects all windows. This also means
+ that attempting to enable validation via a window that only gets shown after
+ some other windows have already started rendering has no effect with Vulkan.
+ Other APIs, such as D3D11, expose the debug layer concept as a per-device
+ (ID3D11Device) setting, and so it is controlled on a true per-window basis
+ (assuming the scenegraph render loop uses a dedicated graphics
+ device/context for each QQuickWindow).
+
+ \since 6.5
+
+ \sa isDebugLayerEnabled()
*/
-QByteArrayList QQuickGraphicsConfiguration::deviceExtensions() const
+void QQuickGraphicsConfiguration::setDebugLayer(bool enable)
{
- return d->deviceExtensions;
+ if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableDebugLayer) != enable) {
+ detach();
+ d->flags.setFlag(QQuickGraphicsConfigurationPrivate::EnableDebugLayer, enable);
+ }
+}
+
+/*!
+ \return true if the debug/validation layers are to be enabled.
+
+ By default the value is false.
+
+ \sa setDebugLayer()
+ */
+bool QQuickGraphicsConfiguration::isDebugLayerEnabled() const
+{
+ return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableDebugLayer);
+}
+
+/*!
+ Where applicable, \a enable controls inserting debug markers and object
+ names into the graphics command stream.
+
+ Some frameworks, such as Qt Quick 3D, have the ability to annotate the
+ graphics objects they create (buffers, textures) with names and also
+ indicate the beginning and end of render passes in the command buffer. These
+ are then visible in frame captures made with tools like
+ \l{https://renderdoc.org/}{RenderDoc} or XCode.
+
+ Graphics APIs where this can be expected to be supported are Vulkan (if
+ VK_EXT_debug_utils is available), Direct 3D 11, and Metal.
+
+ Calling this function with \a enable set to true is equivalent to setting
+ the environment variable \c{QSG_RHI_PROFILE} to a non-zero
+ value.
+
+ The default value is false.
+
+ \note Enabling debug markers may have a performance impact. Shipping
+ applications to production with the flag enabled is not recommended.
+
+ \since 6.5
+
+ \sa isDebugMarkersEnabled()
+ */
+void QQuickGraphicsConfiguration::setDebugMarkers(bool enable)
+{
+ if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableDebugMarkers) != enable) {
+ detach();
+ d->flags.setFlag(QQuickGraphicsConfigurationPrivate::EnableDebugMarkers, enable);
+ }
+}
+
+/*!
+ \return true if debug markers are enabled.
+
+ By default the value is false.
+
+ \sa setDebugMarkers()
+ */
+bool QQuickGraphicsConfiguration::isDebugMarkersEnabled() const
+{
+ return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableDebugMarkers);
+}
+
+/*!
+ When enabled, GPU timing data is collected from command buffers on
+ platforms and 3D APIs where this is supported. This data is then printed in
+ the renderer logs that can be enabled via \c{QSG_RENDER_TIMING} environment
+ variable or logging categories such as \c{qt.scenegraph.time.renderloop},
+ and may also be made visible to other modules, such as Qt Quick 3D's
+ \l DebugView item.
+
+ By default this is disabled, because collecting the data may involve
+ additional work, such as inserting timestamp queries in the command stream,
+ depending on the underlying graphics API. To enable, either call this
+ function with \a enable set to true, or set the \c{QSG_RHI_PROFILE}
+ environment variable to a non-zero value.
+
+ Graphics APIs where this can be expected to be supported are Direct 3D 11,
+ Direct 3D 12, Vulkan (as long as the underlying Vulkan implementation
+ supports timestamp queries), Metal, and OpenGL with a core or compatibility
+ profile context for version 3.3 or newer. Timestamps are not supported with
+ OpenGL ES.
+
+ \since 6.6
+
+ \sa timestampsEnabled(), setDebugMarkers()
+ */
+void QQuickGraphicsConfiguration::setTimestamps(bool enable)
+{
+ if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableTimestamps) != enable) {
+ detach();
+ d->flags.setFlag(QQuickGraphicsConfigurationPrivate::EnableTimestamps, enable);
+ }
+}
+
+/*!
+ \return true if GPU timing collection is enabled.
+
+ By default the value is false.
+
+ \since 6.6
+ \sa setTimestamps()
+ */
+bool QQuickGraphicsConfiguration::timestampsEnabled() const
+{
+ return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::EnableTimestamps);
+}
+
+/*!
+ Requests choosing an adapter or physical device that uses software-based
+ rasterization. Applicable only when the underlying API has support for
+ enumerating adapters (for example, Direct 3D or Vulkan), and is ignored
+ otherwise.
+
+ If the graphics API implementation has no such graphics adapter or physical
+ device available, the request is ignored. With Direct 3D it can be expected
+ that a
+ \l{https://docs.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp}{WARP}-based
+ rasterizer is always available. With Vulkan, the flag only has an effect if
+ Mesa's \c lavapipe, or some other physical device reporting
+ \c{VK_PHYSICAL_DEVICE_TYPE_CPU} is available.
+
+ Calling this function with \a enable set to true is equivalent to setting
+ the environment variable \c{QSG_RHI_PREFER_SOFTWARE_RENDERER} to a non-zero
+ value.
+
+ The default value is false.
+
+ \since 6.5
+
+ \sa prefersSoftwareDevice()
+ */
+void QQuickGraphicsConfiguration::setPreferSoftwareDevice(bool enable)
+{
+ if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::PreferSoftwareDevice) != enable) {
+ detach();
+ d->flags.setFlag(QQuickGraphicsConfigurationPrivate::PreferSoftwareDevice, enable);
+ }
+}
+
+/*!
+ \return true if a software rasterizer-based graphics device is prioritized.
+
+ By default the value is false.
+
+ \sa setPreferSoftwareDevice()
+ */
+bool QQuickGraphicsConfiguration::prefersSoftwareDevice() const
+{
+ return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::PreferSoftwareDevice);
+}
+
+/*!
+ Changes the usage of the automatic pipeline cache based on \a enable.
+
+ The default value is true, unless certain application attributes or
+ environment variables are set. See \l{The Automatic Pipeline Cache} for
+ more information.
+
+ \since 6.5
+
+ \sa isAutomaticPipelineCacheEnabled()
+ */
+void QQuickGraphicsConfiguration::setAutomaticPipelineCache(bool enable)
+{
+ if (d->flags.testFlag(QQuickGraphicsConfigurationPrivate::AutoPipelineCache) != enable) {
+ detach();
+ d->flags.setFlag(QQuickGraphicsConfigurationPrivate::AutoPipelineCache, enable);
+ }
+}
+
+/*!
+ \return true if the automatic pipeline cache is enabled.
+
+ By default this is true, unless certain application attributes or
+ environment variables are set. See \l{The Automatic Pipeline Cache} for
+ more information.
+
+ \since 6.5
+
+ \sa setAutomaticPipelineCache()
+ */
+bool QQuickGraphicsConfiguration::isAutomaticPipelineCacheEnabled() const
+{
+ return d->flags.testFlag(QQuickGraphicsConfigurationPrivate::AutoPipelineCache);
+}
+
+/*!
+ Sets the \a filename where the QQuickWindow is expected to store its
+ graphics/compute pipeline cache contents. The default value is empty, which
+ means pipeline cache loading is disabled.
+
+ See \l{Pipeline Cache Save and Load} for a discussion on pipeline caches.
+
+ Persistently storing the pipeline cache can lead to performance
+ improvements in future runs of the application since expensive shader
+ compilation and pipeline construction steps may be avoided.
+
+ If and when the writing of the file happens is not defined. It will likely
+ happen at some point when tearing down the scenegraph due to closing the
+ window. Therefore, applications should not assume availability of the file
+ until the QQuickWindow is fully destructed. QQuickGraphicsConfiguration
+ only stores the filename, it does not perform any actual I/O and graphics
+ operations on its own.
+
+ When running with a graphics API where retrieving the pipeline cache (or
+ shader/program binaries) is not applicable or not supported, calling this
+ function has no effect.
+
+ Calling this function is mostly equivalent to setting the environment
+ variable \c{QSG_RHI_PIPELINE_CACHE_SAVE} to \a filename, with one important
+ difference: this function controls the pipeline cache storage for the
+ associated QQuickWindow only. Applications with multiple QQuickWindow or
+ QQuickView instances can therefore store and later reload the cache contents
+ via files dedicated to each window. The environment variable does not allow
+ this.
+
+ \since 6.5
+
+ \sa pipelineCacheLoadFile(), setPipelineCacheSaveFile()
+ */
+void QQuickGraphicsConfiguration::setPipelineCacheSaveFile(const QString &filename)
+{
+ if (d->pipelineCacheSaveFile != filename) {
+ detach();
+ d->pipelineCacheSaveFile = filename;
+ }
+}
+
+/*!
+ \return the currently set filename for storing the pipeline cache.
+
+ By default the value is an empty string.
+ */
+QString QQuickGraphicsConfiguration::pipelineCacheSaveFile() const
+{
+ return d->pipelineCacheSaveFile;
+}
+
+/*!
+ Sets the \a filename where the QQuickWindow is expected to load the initial
+ contents of its graphics/compute pipeline cache from. The default value is
+ empty, which means pipeline cache loading is disabled.
+
+ See \l{Pipeline Cache Save and Load} for a discussion on pipeline caches.
+
+ Persistently storing the pipeline cache can lead to performance
+ improvements in future runs of the application since expensive shader
+ compilation and pipeline construction steps may be avoided.
+
+ If and when the loading of the file's contents happens is not defined, apart
+ from that it will happen at some point during the initialization of the
+ scenegraph of the QQuickWindow. Therefore, the file must continue to exist
+ after calling this function. QQuickGraphicsConfiguration only stores the
+ filename, it cannot perform any actual I/O and graphics operations on its
+ own. The real work is going to happen later on, possibly on another thread.
+
+ When running with a graphics API where retrieving and reloading the
+ pipeline cache (or shader/program binaries) is not applicable or not
+ supported, calling this function has no effect.
+
+ Calling this function is mostly equivalent to setting the environment
+ variable \c{QSG_RHI_PIPELINE_CACHE_LOAD} to \a filename, with one important
+ difference: this function controls the pipeline cache storage for the
+ associated QQuickWindow only. Applications with multiple QQuickWindow or
+ QQuickView instances can therefore store and later reload the cache contents
+ via files dedicated to each window. The environment variable does not allow
+ this.
+
+ \note If the data in the file does not match the graphics device and driver
+ version at run time, the contents will be ignored, transparently to the
+ application. This applies to a number of graphics APIs, and the necessary
+ checks are taken care of by Qt. There are exceptions, most notably Direct
+ 3D 11, where the "pipeline cache" is used only to store the results of
+ runtime HLSL->DXBC compilation and is therefore device and vendor
+ independent.
+
+ \since 6.5
+
+ \sa pipelineCacheLoadFile(), setPipelineCacheSaveFile()
+ */
+void QQuickGraphicsConfiguration::setPipelineCacheLoadFile(const QString &filename)
+{
+ if (d->pipelineCacheLoadFile != filename) {
+ detach();
+ d->pipelineCacheLoadFile = filename;
+ }
+}
+
+/*!
+ \return the currently set filename for loading the pipeline cache.
+
+ By default the value is an empty string.
+ */
+QString QQuickGraphicsConfiguration::pipelineCacheLoadFile() const
+{
+ return d->pipelineCacheLoadFile;
}
QQuickGraphicsConfigurationPrivate::QQuickGraphicsConfigurationPrivate()
: ref(1)
{
- static const bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
- useDepthBufferFor2D = useDepth;
+ // Defaults based on env.vars. NB! many of these variables are documented
+ // and should be considered (semi-)public API. Changing the env.var. names
+ // is therefore not allowed.
+
+ flags = {};
+
+ static const bool useDepthBufferFor2D = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
+ if (useDepthBufferFor2D)
+ flags |= UseDepthBufferFor2D;
+
+ static const bool enableDebugLayer = qEnvironmentVariableIntValue("QSG_RHI_DEBUG_LAYER");
+ if (enableDebugLayer)
+ flags |= EnableDebugLayer;
+
+ static const bool enableProfilingRelated = qEnvironmentVariableIntValue("QSG_RHI_PROFILE");
+ if (enableProfilingRelated)
+ flags |= EnableDebugMarkers | EnableTimestamps;
+
+ static const bool preferSoftwareDevice = qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER");
+ if (preferSoftwareDevice)
+ flags |= PreferSoftwareDevice;
+
+ // here take the existing QOpenGL disk cache attribute and env.var. into account as well
+ static const bool autoPipelineCache = !QCoreApplication::instance()->testAttribute(Qt::AA_DisableShaderDiskCache)
+ && !qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")
+ && !qEnvironmentVariableIntValue("QSG_RHI_DISABLE_DISK_CACHE");
+ if (autoPipelineCache)
+ flags |= AutoPipelineCache;
+
+ static const QString pipelineCacheSaveFileEnv = qEnvironmentVariable("QSG_RHI_PIPELINE_CACHE_SAVE");
+ pipelineCacheSaveFile = pipelineCacheSaveFileEnv;
+
+ static const QString pipelineCacheLoadFileEnv = qEnvironmentVariable("QSG_RHI_PIPELINE_CACHE_LOAD");
+ pipelineCacheLoadFile = pipelineCacheLoadFileEnv;
}
-QQuickGraphicsConfigurationPrivate::QQuickGraphicsConfigurationPrivate(const QQuickGraphicsConfigurationPrivate *other)
+QQuickGraphicsConfigurationPrivate::QQuickGraphicsConfigurationPrivate(const QQuickGraphicsConfigurationPrivate &other)
: ref(1),
- deviceExtensions(other->deviceExtensions),
- useDepthBufferFor2D(other->useDepthBufferFor2D)
+ deviceExtensions(other.deviceExtensions),
+ flags(other.flags),
+ pipelineCacheSaveFile(other.pipelineCacheSaveFile),
+ pipelineCacheLoadFile(other.pipelineCacheLoadFile)
+{
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QQuickGraphicsConfiguration &config)
{
+ QDebugStateSaver saver(dbg);
+ const QQuickGraphicsConfigurationPrivate *cd = QQuickGraphicsConfigurationPrivate::get(&config);
+ dbg.nospace() << "QQuickGraphicsConfiguration("
+ << "flags=0x" << Qt::hex << cd->flags << Qt::dec
+ << " flag-isDepthBufferEnabledFor2D=" << config.isDepthBufferEnabledFor2D()
+ << " flag-isDebugLayerEnabled=" << config.isDebugLayerEnabled()
+ << " flag-isDebugMarkersEnabled=" << config.isDebugMarkersEnabled()
+ << " flag-prefersSoftwareDevice=" << config.prefersSoftwareDevice()
+ << " flag-isAutomaticPipelineCacheEnabled=" << config.isAutomaticPipelineCacheEnabled()
+ << " pipelineCacheSaveFile=" << cd->pipelineCacheSaveFile
+ << " piplineCacheLoadFile=" << cd->pipelineCacheLoadFile
+ << " extra-device-extension-requests=" << cd->deviceExtensions
+ << ')';
+ return dbg;
}
+#endif // QT_NO_DEBUG_STREAM
QT_END_NAMESPACE