class QQuickGraphicsConfiguration#

QQuickGraphicsConfiguration 用于控制 QQuickWindow 的底层图形设置。更多...

概要#

方法#

静态函数#

注意

本文档可能包含从 C++ 自动翻译到 Python 的代码片段。我们始终欢迎人们对代码片段翻译的贡献。如果您发现翻译存在问题,您也可以通过在 https:/bugreports.qt.io/projects/PYSIDE 上创建故障报告来告知我们

详细说明#

QQuickGraphicsConfiguration 类是一个容器,用于低级图形设置,这些设置可以影响 Qt Quick 场景图如何初始化底层的图形 API(如 Vulkan)。它还可以控制场景图渲染器的某些方面。

注意

必须在场景图首次初始化该窗口之前对 QQuickGraphicsConfiguration 进行设置。在有屏幕窗口的情况下,这意味着调用必须在该窗口的 QQuickWindowQQuickView 调用 show() 之前进行。使用 QQuickRenderControl 时,必须在调用 initialize() 之前最终确定配置。

外部渲染引擎或 XR API 的配置#

当构建并显示使用 Vulkan 进行渲染的 QQuickWindow 时,会通过 Vulkan API 初始化一个 Vulkan 实例(VkInstance)、物理设备(VkPhysicalDevice)、设备(VkDevice)和相关的对象(队列、池)。在ertas 使用 QQuickRenderControl 将渲染重定向到自定义渲染目标(如纹理)时,也大多如此。虽然 QVulkanInstance 的构建在应用控制之下,但其他图形对象的初始化方式在 initialize() 方法中以及屏幕 QQuickWindow 中是相同的。

对于大多数应用程序,无需额外配置,因为 Qt Quick 为许多底层图形设置提供了合理的默认值,例如要启用的设备扩展。

然而,这并不总是足够的。在高级用例中,当集成直接 Vulkan 或其他图形 API 内容,或与外部 3D 或 VR 引擎集成(例如,OpenXR)时,应用程序将需要在详细信息方面指定自己的设置集,例如要启用的哪些设备扩展。

这正是此类所提供的。它允许指定一个设备扩展列表,然后在使用 Vulkan 或相关图形 API(概念适用时)时该场景图将拾取此列表,或者在概念不适用的情况下简单地忽略相关的设置。

此类别中的函数示例包括 setDeviceExtensions()preferredInstanceExtensions() 。后者在应用程序管理自己的 QVulkanInstance,并通过 QWindow::setVulkanInstance() 与 QQuickWindow 关联时很有用。

Qt Quick 场景图渲染器配置#

另一类与场景图的渲染器相关的设置。在某些情况下,应用程序可能希望控制某些行为,例如在渲染 2D 内容时使用深度缓冲区。在 Qt 5 中,此类设置要么根本无法控制,要么通过环境变量进行管理。在 Qt 6 中,QQuickGraphicsConfiguration 为这些设置提供了一个新的家,同时保留了适用于这些设置的旧环境变量。

此类别中的示例之一是 setDepthBufferFor2D()

图形设备配置#

当Qt在初始化一个QQuickWindow时创建图形实例和设备对象(例如,Vulkan的VkInstance和VkDevice,Direct 3D的ID3D11Device等)时,在某些情况下,应用程序或库会想要控制一些设置。

在Qt 6.5之前,一些这样的设置可以通过环境变量来控制。例如,QSG_RHI_DEBUG_LAYERQSG_RHI_PREFER_SOFTWARE_RENDERER。这些设置仍然可用,并且继续按以前的方式工作。QQuickGraphicsConfiguration还提供了额外的C++设置器。

例如,以下main()函数在打开QQuickView时,指定启用Vulkan验证或Direct3D调试层。

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();
}

管道缓存保存和加载#

Qt Quick支持将图形/计算管道缓存保存在磁盘上,并在应用程序的后续运行中重新加载。管道缓存具体包含什么,查询是如何工作的,以及具体有哪些内容得到加速,这些都取决于Qt RHI后端和运行时使用的底层本地图形API。不同的3D API在着色器、程序和管道状态对象方面有不同的概念,以及相应的缓存机制。这里的管道缓存高级概念抽象化所有这些,将它们存储和检索为单个二进制blob。

注意

将缓存存储在磁盘上可能会在应用程序的后续运行中得到改进,有时甚至是显著的。

当遇到之前运行中遇到的相同的着色程序和/或管道状态时,很可能会跳过一些操作,从而加快着色器和材料的初始化时间,这意味着启动速度可能会更快,渲染过程中的延迟和“卡顿”可能会减少或避免。

当使用不适用或不受支持的图形API进行管道缓存(或着色器/程序二进制文件)检索和重新加载时,尝试使用文件保存和加载缓存没有任何效果。

注意

在许多情况下,检索到的数据依赖于并且绑定到图形驱动程序(以及可能的具体版本)。Qt通过在管道缓存文件中存储额外的元数据来自动执行必要的检查。如果文件中的数据与运行时的图形设备和驱动程序版本不匹配,则内容将被透明地忽略。因此,引用在另一台设备或驱动程序上生成的缓存是安全的。

存在一些驱动程序依赖问题的例外,最显著的是Direct 3D 11,其中“管道缓存”仅用于存储运行时HLSL->DXBC编译的结果,因此与设备和供应商无关。

在某些情况下,可能希望通过“预先填充”缓存来改进应用程序的第一次运行。这可以通过提供从前一次运行中保存的缓存文件,并在另一台机器或设备上引用它来完成。这样,应用程序或设备在其第一次运行时就已具备了在上次运行中遇到的着色程序/管道。只有在目标系统上设备和图形驱动程序相同的情况下,提供和部署缓存文件才有意义,否则如果设备或驱动程序版本不匹配,将忽略缓存文件(D3D11除外),如上所述。

一旦缓存内容加载完成,应用程序构建的图形和计算管线仍有可能在之前的运行中未曾遇到。在这种情况下,缓存会增长,并将添加管线/着色器程序。如果应用程序还选择保存内容(也许保存到同一文件),则旧的和新的管线都会被存储。每次运行时从同一文件加载和保存允许缓存不断增长,存储所有遇到过的管线和着色器程序。

实际上,可以期望Qt管线缓存对应以下原生图形API特性

  • Vulkan - VkPipelineCache - 将管线缓存保存下来实际上存储了从 vkGetPipelineCacheData 获取的blob,其中包含附加元数据以安全地识别设备和驱动程序,因为管线缓存blob依赖于特定的驱动程序。

  • Metal - MTLBinaryArchive - 启用管线缓存保存功能后,Qt将遇到的全部渲染和计算管线存储到MTLBinaryArchive中。保存管线缓存存储从存档中检索到的blob,包含识别设备的附加元数据。注意:目前由于某些硬件和操作系统版本中的各种问题,在macOS和iOS上禁用了MTLBinaryArchive的使用。

  • OpenGL - 没有原生的管线概念,“管线缓存”存储的是通过 glGetProgramBinary 获取的程序二进制文件集合。程序二进制文件被打包成一个单一的blob,包含识别设备、驱动程序以及二进制文件从中检索出的版本的附加元数据。在Qt中,程序二进制文件的持久性缓存并不是新特性:Qt 5已经在QOpenGLShaderProgram中有了类似的功能,例如查看addCacheableShaderFromSourceCode()。实际上,当使用Qt Quick以及OpenGL时,这个机制在Qt 6中始终激活。但是,当使用这里提供的新、与图形API无关的管线缓存抽象时,Qt 5时代的程序二进制缓存会被自动禁用,因为相同的内容现在被包装在“管线缓存”中。

  • Direct 3D 11 - 没有原始的管线概念或为第二阶段编译(其中无厂商依赖的中间字节码被编译成设备的特定指令集)检索二进制文件的概念。驱动程序通常在该级别上使用自己的缓存系统。相反,Qt Quick “管线缓存”用于加快需要先编译成中间字节码格式再存储HLSL源代码的着色器的情况。这可以在应用程序和库中提供显著的性能改进,因为这些应用程序和库在运行时合成着色器代码,因为如果在随后的运行中已存在所遇到HLSL着色器的字节码,则可以避免调用 D3DCompile() 的潜在昂贵的未缓存调用。Qt Quick 3D是一个很好的例子,其运行时生成的用于材质的着色器意味着需要处理HLSL源代码。因此,保存和重新加载Qt Quick管线缓存可以在包含一个或多个View3D项的场景中带来很大的改进。反例可能是Qt Quick本身:因为大多数内置的2D着色器在构建时已经与DirectX字节码一起提供,缓存不会带来显著的改进。

所有这些都独立于由 Qt Shader Tools 模块及其命令行工具(如 qsb)执行的着色器处理。以 Vulkan 为例,将 Vulkan 兼容的 GLSL 源代码编译成 SPIR-V,无论是在离线时还是在构建时(直接通过 qsb 或 CMake),都是好的,因为它可以避免运行时从源代码进行昂贵的编译。然而,SPIR-V 是一种制造商独立的中间格式。在运行时构建图形或计算管道时,很可能会进行另一轮编译,这次是从中间格式编译到 GPU 的特定制造商指令集(这可能也依赖于图形管道中的某些状态以及渲染目标)。管道缓存有助于这一后阶段。

注意

许多图形 API 实现都使用它们自己的持久磁盘缓存,对应用程序是透明的。使用 Qt Quick 的管道缓存功能可能会在这方面提供改进,但收益可能较小。

通过调用 setPipelineCacheSaveFile()setPipelineCacheLoadFile() 来控制 QQuickWindowQQuickView 保存和加载管道缓存到/自哪些文件。

要了解启用磁盘存储管道缓存的效果,可以通过环境变量 QSG_INFO=1 启用最重要场景图和图形日志,或者同时启用 qt.scenegraph.generalqt.rhi.general 日志类别。当关闭 QQuickWindow 时,将出现类似于以下的消息

Total time spent on pipeline creation during the lifetime of the QRhi was 123 ms

这给出了一个大致的了解,在整个窗口生命周期中,在图形和计算管道创建上花费了多长时间(这可能包括着色器编译的各个阶段)。

当启用从管道缓存文件加载时,会通过一条消息得到确认

Attempting to seed pipeline cache from 'filename'

同样,为了检查是否成功启用了缓存的保存,寻找类似以下的消息

Writing pipeline cache contents to 'filename'

自动管道缓存#

如果没有提供保存和加载的文件名,则使用自动管道缓存策略。这涉及到将数据存储到系统应用程序特定缓存位置(QStandardPaths::CacheLocation)。

可以通过以下任一方式禁用此功能

  • 设置应用程序属性 Qt::AA_DisableShaderDiskCache。(完全禁用自动存储)

  • 将环境变量 QT_DISABLE_SHADER_DISK_CACHE 设置为一个非零值。(完全禁用自动存储)

  • 将环境变量 QSG_RHI_DISABLE_SHADER_DISK_CACHE 设置为一个非零值。(完全禁用自动存储)

  • 调用 setPipelineCacheSaveFile() 并设置启用参数为 false。(完全禁用自动存储)

  • 通过调用 setPipelineCacheLoadFile() 设置一个文件名。(仅禁用从自动存储加载,更喜欢指定的文件)

  • 通过调用 setPipelineCacheSaveFile() 来设置文件名。(仅禁用自动存储写入,优先使用指定的文件)

前两项是自Qt 5.9以来使用的现有机制,用于控制OpenGL程序二进制缓存。为了兼容性和熟悉度,Qt 6增强的管道缓存也支持相同的属性和环境变量。

自动管道缓存使用每个应用程序的单个文件,但对于每个RHI后端(图形API)使用不同的文件。这意味着在应用程序下一次运行时,更改到另一个图形API不会导致之前运行的管道缓存丢失。但是,对于同时显示多个 QQuickWindow 实例的应用程序可能不会获得100%的益处,因为自动缓存只能存储从一次RHI对象收集的数据。(并且默认的 threaded 渲染循环中,每个窗口都有它自己的RHI,因为渲染在专门的线程上独立运行)。为了在具有多个窗口的应用程序中充分利用磁盘缓存,请通过 setPipelineCacheSaveFile() 显式地设置每个窗口的文件名。

__init__(other)#
参数:

otherQQuickGraphicsConfiguration

__init__()

构造一个默认的 QQuickGraphicsConfiguration 对象,该对象不指定任何额外的设置以供场景图考虑。

deviceExtensions()#
返回类型:

QByteArray 列表

返回请求的附加设备扩展列表。

另请参阅

setDeviceExtensions()

isAutomaticPipelineCacheEnabled()#
返回类型:

布尔值

如果已启用自动管道缓存,则返回 true。

默认情况下为 true,除非已设置某些应用程序属性或环境变量。有关更多信息,请参阅 自动管道缓存

isDebugLayerEnabled()#
返回类型:

布尔值

如果需要启用调试/验证层,则返回 true。

默认值为 false。

另请参阅

setDebugLayer()

isDebugMarkersEnabled()#
返回类型:

布尔值

如果启用了调试标记,则返回 true。

默认值为 false。

另请参阅

setDebugMarkers()

isDepthBufferEnabledFor2D()#
返回类型:

布尔值

如果为 2D 内容启用了深度缓冲区使用,则返回 true。

默认值为 true,除非设置了环境变量 QSG_NO_DEPTH_BUFFER

pipelineCacheLoadFile()#
返回类型:

str

返回用于加载管道缓存 currently set 的当前文件名。

默认值为空字符串。

pipelineCacheSaveFile()#
返回类型:

str

返回用于存储管道缓存的 currently set 当前文件名。

默认值为空字符串。

static preferredInstanceExtensions()#
返回类型:

QByteArray 列表

返回 Qt Quick 在 VkInstance 上希望启用的 Vulkan 实例扩展列表。

在大多数情况下,Qt Quick 负责创建 QVulkanInstance。这个函数在这种情况下是不相关的。另一方面,当与基于 Vulkan 的渲染一起使用 QQuickRenderControl 时,应用程序负责创建一个 QVulkanInstance 并将其与(离屏) QQuickWindow 关联。在这种情况下,预期应用程序将查询要启用的实例扩展列表,并在调用 QVulkanInstance::create() 之前将它们传递给 QVulkanInstance::setExtensions()。

prefersSoftwareDevice()#
返回类型:

布尔值

如果优先考虑基于软件光栅化器的图形设备,则返回 true。

默认值为 false。

setAutomaticPipelineCache(enable)#
参数:

enable – bool

根据 enable 更改自动管道缓存的用法。

默认值为 true,除非设置了某些应用程序属性或环境变量。有关更多信息,请参阅 The Automatic Pipeline Cache

setDebugLayer(enable)#
参数:

enable – bool

启用图形API实现的可选调试或验证层。

在实践中,此功能需要Vulkan和Direct 3D 11的支持(验证层、Windows SDK),且必须在运行时可用。当enable设置为true时,Qt将尝试在VkInstance上启用标准验证层,或在图形设备上设置D3D11_CREATE_DEVICE_DEBUG

对于macOS上的Metal,在启动应用程序之前,请将环境变量METAL_DEVICE_WRAPPER_TYPE=1设置。

将此函数的enable参数设置为true与设置环境变量QSG_RHI_DEBUG_LAYER为非零值等效。

默认值为false。

注意

启用调试或验证层可能会对性能产生显著影响。强烈不建议在生产应用程序中启用此标志。

注意

请注意,由于底层图形API的设计差异,此设置不能总是一个针对QQuickWindow的设置,尽管每个QQuickWindow都有自己的QQuickGraphicsConfiguration。特别是对于Vulkan,实例对象(VkInstance)仅创建一次,然后由应用程序中的所有窗口使用。因此,启用验证层会影响所有窗口。这也意味着,当通过仅显示在开始渲染其他窗口之后的窗口尝试启用验证时,对Vulkan无效。其他API,如D3D11,将调试层概念作为针对设备的(ID3D11Device)设置公开,因此它可以在真正的逐窗口基础上进行控制(假设场景图渲染循环为每个QQuickWindow使用专用的图形设备/上下文)。

另请参阅

isDebugLayerEnabled()

setDebugMarkers(enable)#
参数:

enable – bool

当适用时,enable参数控制是否在图形命令流中插入调试标记和对象名称。

某些框架,例如Qt Quick 3D,具有在它们创建的图形对象(缓冲区、纹理)上添加名称并指示命令缓冲区中渲染传递的开始和结束的能力。这些随后在工具,如RenderDoc或XCode生成的帧捕获中可见。

可能支持此功能的图形API包括Vulkan(如果VK_EXT_debug_utils可用)、Direct 3D 11和Metal。

将此函数的enable参数设置为true与设置环境变量QSG_RHI_PROFILE为非零值等效。

默认值为false。

注意

启用调试标记可能会对性能产生影响。不建议在生产应用程序中启用此标志。

setDepthBufferFor2D(enable)#
参数:

enable – bool

将2D内容的深度缓冲区使用设置为启用。当禁用时,Qt Quick场景图从不写入深度缓冲区。

默认值为 true,除非设置了环境变量 QSG_NO_DEPTH_BUFFER

默认值为true,对于绝大多数场景来说,这是最佳设置。禁用深度缓冲区使用会降低场景图的批处理效率。

然而,在某些情况下,允许2D内容写入深度缓冲区并不是一个好的选择。考虑一个3D场景作为“覆盖”在2D场景之上,通过Qt Quick 3D使用View3D并设置renderMode为Overlay进行渲染。在这种情况下,如果2D内容填充深度缓冲区可能导致意外的结果。这是因为2D场景图渲染器生成和处理深度值的方式可能与3D场景的工作方式不兼容。这可能会导致深度值冲突、碰撞和意外的深度测试失败。因此,稳健的做法是将此函数的enable设置为false,并在QQuickWindow中禁用2D内容的深度缓冲区写入。

注意

此标志与设置QSG_NO_DEPTH_BUFFER环境变量并不完全相同。该标志不控制深度/Stencil缓冲区的存在。它更与渲染管线相关。要强制不使用深度/Stencil附着,请设置QSG_NO_DEPTH_BUFFERQSG_NO_STENCIL_BUFFER。但是请注意,这样一个QQuickWindow以及其中的任何Item层可能会变得与具有某些操作模式的项(例如View3D)不兼容,因为3D内容需要一个深度缓冲区。调用此函数总是安全的,但它意味着即使没有活跃使用,也会创建资源,例如深度缓冲区。

setDeviceExtensions(extensions)#
参数:

extensions – .QByteArray列表

设置要在图形设备上(例如,VkDevice)启用的附加扩展列表。

当使用不适用此概念的高性能API进行渲染时,extensions将被忽略。

注意

列表指定了额外的扩展。Qt Quick始终启用场景图所需的扩展。

另请参阅

deviceExtensions()

setPipelineCacheLoadFile(filename)#
参数:

filename – 字符串

设置QQuickWindow从其中加载其图形/计算管线缓存初始内容的filename。默认值为空,表示禁用管线缓存加载。

有关管线缓存的信息,请参见Pipeline Cache Save and Load

持续存储管线缓存可以在应用程序的后续运行中提高性能,因为可以避免昂贵的着色器编译和管线构建步骤。

如果对文件内容加载发生的时间没有定义,除了该操作将在QQuickWindow 初始化场景图时发生的某个时刻之外。因此,在调用此函数后,文件必须继续存在。`QQuickGraphicsConfiguration` 只存储文件名,它本身不能执行任何实际的 I/O 和图形操作。实际的工作将在以后进行,可能在另一个线程上。

当运行不适用或不受支持的图形 API 以获取和重新加载管道缓存(或着色器/程序二进制文件)时,调用此函数没有任何效果。

调用此函数基本上等效于将环境变量 `QSG_RHI_PIPELINE_CACHE_LOAD` 设置为 `filename`,但有一个重要的区别:此函数仅控制相关 QQuickWindow 的管道缓存存储。具有多个 QQuickWindowQQuickView 实例的应用程序可以通过为每个窗口指定的文件存储和稍后重新加载缓存内容。环境变量不允许这样做。

注意

如果文件中的数据与运行时的图形设备和驱动程序版本不匹配,则会忽略内容,对应用程序来说是透明的。这适用于许多图形 API,必要的检查由 Qt 进行处理。存在例外,最著名的是 Direct3D 11,其中“管道缓存”仅用于存储运行时 HLSL->DXBC 编译的结果,因此与设备和供应商无关。

setPipelineCacheSaveFile(filename)#
参数:

filename – 字符串

设置保存 QQuickWindow 图形/计算管道缓存内容的文件名。默认值为空,表示禁用管道缓存加载。

有关管线缓存的信息,请参见Pipeline Cache Save and Load

持续存储管线缓存可以在应用程序的后续运行中提高性能,因为可以避免昂贵的着色器编译和管线构建步骤。

如果文件写入时间没有定义,它可能发生在拆解场景图时,由于关闭窗口而触发。因此,在 `QQuickWindow` 完全销毁之前,应用程序不应假设文件可用。`QQuickGraphicsConfiguration` 只存储文件名,它本身不执行任何实际的 I/O 和图形操作。

当在一个不支持获取管线缓存(或着色器/程序二进制文件)的图形API中运行时,调用此函数没有效果。

调用此函数基本上等同于将环境变量 QSG_RHI_PIPELINE_CACHE_SAVE 设置为 filename,但有一个重要的区别:此函数仅控制相关 QQuickWindow 的管线缓存存储。因此,具有多个 QQuickWindowQQuickView 实例的应用程序可以存储并稍后通过每个窗口的专用文件重新加载缓存内容。环境变量不允许这样做。

setPreferSoftwareDevice(enable)#
参数:

enable – bool

请求选择使用基于软件光栅化的适配器或物理设备。仅在底层API支持枚举适配器(例如,Direct 3D或Vulkan)的情况下适用,否则将忽略。

如果图形API实现没有此类图形适配器或可用物理设备,则请求将被忽略。在Direct 3D中,可以预期基于WARP的栅梳器始终可用。在Vulkan中,只有当Mesa的lavapipe 或其他报告VK_PHYSICAL_DEVICE_TYPE_CPU的物理设备可用时,该标志才有效。

enable设置为true调用此函数相当于将环境变量QSG_RHI_PREFER_SOFTWARE_RENDERER设置为一个非零值。

默认值为false。

setTimestamps(enable)#
参数:

enable – bool

当启用时,将从支持此功能的平台和3D API上的命令缓冲区收集GPU计时数据。然后,这些数据将在通过QSG_RENDER_TIMING环境变量或类似qt.scenegraph.time.renderloop的日志类别启用的渲染器日志中打印,并且还可以将这些数据显示给其他模块,如Qt Quick 3D的DebugView项。

默认情况下,此功能是禁用的,因为收集数据可能涉及额外的工作,例如在命令流中插入时间戳查询,这取决于底层图形API。要启用,请将此函数中的 enable 设置为 true,或将 QSG_RHI_PROFILE 环境变量设置为非零值。

支持此功能的图形API包括Direct 3D 11、Direct 3D 12、Vulkan(只要底层Vulkan实现支持时间戳查询)、Metal和具有核心或兼容性配置文件上下文、版本3.3或更新的OpenGL。OpenGL ES不支持时间戳。

timestampsEnabled()#
返回类型:

布尔值

如果启用GPU计时收集,则返回 true。

默认值为 false。

另请参阅

setTimestamps()