Qt着色工具构建系统集成
编译着色器并将其添加到Qt资源中
简介
Qt着色工具模块提供了一个CMake宏文件,为应用提供了在他们的CMakeLists.txt
中使用的有用函数。
当使用qt6_add_shaders
函数时,构建系统会自动调用qsb工具,并将生成的.qsb
文件隐式地添加到资源系统中。
第一个示例
让我们看一个简单的示例。假设我们有一个想要通过ShaderEffect提供自己的颤动效果的Qt Quick应用。片段着色器在wobble.frag
中实现。《ShaderEffect》项的`fragmentShader`属性引用了`wobble.frag.qsb
`。我们如何确保在构建时生成此.qsb文件?
... project(exampleapp LANGUAGES CXX) ... find_package(Qt6 COMPONENTS ShaderTools) ... qt6_add_executable(exampleapp main.cpp ) ... qt6_add_resources(exampleapp "exampleapp" PREFIX "/" FILES "main.qml" ) qt6_add_shaders(exampleapp "exampleapp_shaders" PREFIX "/" FILES "wobble.frag" )
以上足以使应用在运行时访问`:/wobble.frag.qsb
`。原始的Vulkan样式的GLSL源代码(wobble.frag)不包括在应用的可执行文件中,并且不需要发货。如果有着色器代码错误,glslang编译器的消息会在构建时打印出来,并且构建失败。当更改着色器源文件时,更改将在下一次构建中自动获取,就像它们对C++和其他源文件所做的那样。
关键是qt6_add_shaders
函数,它类似于qt6_add_resources
。在不指定进一步参数的情况下,该函数会将qsb运行在默认合理的参数上,这些参数适用于针对Vulkan、Metal、Direct 3D和OpenGL或OpenGL ES的目标的片段着色器。
注意:请注意,需要包含%。它对于ShaderTools
的应用非常重要,否则qt6_add_shaders
将不可用。
注意:作为qt6_add_shaders
函数的第一个参数传递的目标必须在调用此函数之前存在。
注意:支持多个qt6_add_shaders
调用。在复杂的应用中,不同的一组着色器可能需要不同的设置。在上述示例中,项目名称(`exampleapp_shaders
`)对于每个调用必须是唯一的。
配置
默认情况下,qt6_add_shaders
以如下方式调用qsb
:
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -o <output>.qsb <input>
这意味着生成的包将包含SPIR-V(用于Vulkan 1.0)、GLSL ES 100(用于OpenGL ES 2.0及更高版本)、GLSL 120(用于非核心轮廓OpenGL上下文)、GLSL 150(用于核心轮廓OpenGL上下文)、Shader Model 5.0的HLSL源代码(用于Direct3D 11.1)以及Metal着色语言1.2源代码(用于Metal)。
这是Qt Quick的一个很好的默认值集合,可以创建在各种系统上高度可移植的应用程序。然而,这些默认值并不总是合适的。如果着色器使用了在这些目标中没有等效功能或结构,那么这个流程以及构建将会失败。如果是这种情况,需要调整目标,这也意味着应用程序的最小系统要求将会隐式调整。例如,考虑一下只适用于OpenGL ES 3.0及以上版本(意味着GLSL ES 300或更高版本)的 textureLod
GLSL函数。当请求使用 300 es
而不是 100 es
时,构建将会成功,但生成的应用程序现在将需要OpenGL ES 3.0或更高版本,并且不会与基于OpenGL ES 2.0的系统兼容。
着色器类型
着色器的类型是从文件扩展名推断出来的。因此,扩展名必须是以下之一
.vert
- 用于顶点着色器.tesc
- 用于扰动控制着色器.tese
- 用于扰动评估着色器.frag
- 用于片段(像素)着色器.comp
- 用于计算着色器
注意: 扰动控制和评估着色器当前不支持Direct 3D(HLSL)。可能的解决方案是手动创建hull和domain着色器,并使用FILES
部分的文件替换语法进行注入。
目标
以下关键字是可用的
GLSL
- 请求生成指定GLSL版本列表的源代码。请注意,列表遵循逗号分隔的qsb
语法。例如,计算着色器希望在这里指定"310 es,430"
,因为默认值不适合它。NOGLSL
- 这个无参关键字禁用生成GLSL源代码。适用于所有不希望使用OpenGL的应用程序。HLSL
- 请求生成指定HLSL(着色器模型)版本列表的源代码。qsb
工具遵循GLSL风格的版本号,因此50
对应于着色器模型5.0,51
是5.1。NOHLSL
- 这个无参关键字禁用生成HLSL源代码。适用于所有不希望使用Direct 3D的应用程序。MSL
- 请求生成指定版本的Metal着色语言(MSL)的源代码。12
对应于1.2,20
对应于2.0。NOMSL
- 这个无参关键字禁用生成MSL源代码。适用于所有不希望使用Metal的应用程序。TESSELLATION
- 这个无参关键字表示着色器用于使用扰动的管道。这仅在列出了顶点着色器并且没有禁用Metal着色器生成时相关。参见此代码片段以获取示例。此选项自Qt 6.5开始引入。
TESSELLATION_VERTEX_COUNT
- 此选项接受一个数字,表示从扰动控制阶段生成的输出顶点数。对于与Metal一起使用的扰动评估着色器,指定此选项是强制性的。默认值是3。如果与扰动控制阶段的顶点不匹配,生成的MSL代码将无法按预期工作。此选项自Qt 6.5开始引入。
TESSELLATION_MODE
- 该选项指定了细分模式。它可以取两个值之一:"triangles"(三角形)
或"quads"(四边形)
。默认值是triangles
。必须指定该选项,当细分控制着色器在FILES
列表中时。它必须匹配细分评估阶段。此选项自Qt 6.5开始引入。
VIEW_COUNT
- 该选项指定了一个顶点着色器所使用的视图数量。在处理多视图(GL_OVR_multiview2、VK_KHR_multiview、D3D12视图实例化等)时,必须为相关着色器指定正确的VIEW_COUNT,其值应大于等于2,以便生成正确的GLSL着色器代码。请注意,对于不依赖于多视图的顶点着色器,应避免设置VIEW_COUNT,因为设置该值会使生成的GLSL代码依赖于多视图。为了克服这一点,应将顶点着色器相应地分成多个qt_add_shaders()调用。设置VIEW_COUNT
会自动将一个预处理定义QSHADER_VIEW_COUNT
注入到着色器源代码中,其值与VIEW_COUNT相同。此外,当设置为2或更多时,会自动注入#extension GL_EXT_multiview : require
行。该选项是在Qt 6.7中引入的。
常用的覆写设置是GLSL
。例如,如果应用程序的着色器使用OpenGL 3.x功能,则可能希望指定比100 es
或120
更高的值。
qt_add_shaders(exampleapp "res_gl3shaders" GLSL "300es,330" PREFIX "/shaders" FILES shaders/ssao.vert shaders/ssao.frag shaders/skybox.vert shaders/skybox.frag )
注意:在es
后缀前面的空格是可选的。
Qt Quick特定内容
BATCHABLE
- 指定这个无参数关键词对于与Qt Quick一起使用的顶点着色器至关重要,无论是用于ShaderEffect还是用于QSGMaterialShader。它对片段或计算着色器没有影响,并且可以将不同类型的着色器安全地包含在同一列表中,因为只考虑.vert
文件的分配关键字。等同于qsb的-b
参数。ZORDER_LOC
- 当指定BATCHABLE
时,默认会注入一个位置为7
的额外顶点输入。此关键词用于将该位置更改为其他值。如果顶点着色器有很多输入且7已被占用,则会发生冲突。
调用外部工具
PRECOMPILE
- 与qsb的-c
或-t
选项等价,具体取决于平台。在Windows上构建时,这会导致在构建时而不是在运行时,通过Windows SDK调用fxc
来完成编译的第一阶段(HLSL源到DXBC字节码)。生成的.qsb
文件将只包含编译结果(中间着色器格式),不包括原始着色器源代码。OPTIMIZED
- 调用spirv-opt
(必须在Vulkan SDK或其他地方可用)对SPIR-V字节码进行优化。等同于qsb的-O
参数。
其他设置
DEFINES
- 定义在着色器编译过程中激活的宏。等同于qsb的-D
参数。列表的形式为"name1=value1;name2=value2"
。或者,像FILES
一样,列表可以由换行符分隔。输出
- 当生成的 .qsb 文件名需要与源文件不同时,例如由于通过定义
来区分,这使得一个着色器文件可以作为多个 .qsb 文件的源文件时,此列表可以包含文件
列表中的每个项目的条目,指定一个以.qsb
结尾的文件名。指定的名称随后传递给 qsb 的-o
参数,而不是只将.qsb
添加到源文件名中。调试信息
- 启用生成 SPIR-V 的完整调试信息,从而使工具如 RenderDoc 能够在检查管线或执行顶点或片段调试时显示完整源代码。相当于 qsb 的-g
参数。在指定了PRECOMPILE
关键字的情况下,对 Direct 3D 也有影响,这时fxc
将被指示在生成的中间字节码中包含调试信息。安静
- 抑制 qsb 的调试和警告输出。只有致命错误会被打印。输出目标
- 在使用 qt_add_shaders 与静态库一起使用时,将会生成一个或多个特殊的目标。如果您想对这些目标进行进一步处理,请将一个值传递给 OUTPUT_TARGETS 参数。
替代手动着色器
CMake 集成也支持指定 .qsb 文件中特定版本的着色器替换。实际上,这与运行 qsb 带有 -r
命令行选项的效果相同。
这是通过 FILE 列表中的以下特殊语法来启用的
FILES "shaders/externalsampler.frag@glsl,100es,shaders/externalsampler_gles.frag"
可以跟在文件名后面任意数量的以 @ 分隔的替换规范。每个规范指定了着色语言、版本以及从哪个文件中读取数据的文件,这些规范之间用逗号分隔。有关详细信息,请参阅 QSB 手册。
细分示例
考虑一个由四个阶段组成的图形管线,包括具有着色器 vertex.vert
的顶点阶段,具有着色器 tess.tesc
的细分控制阶段,具有着色器 tess.tese
的细分评估阶段,以及具有着色器 fragment.frag
的片段阶段。
为了构建一个能够与任何 Vulkan、OpenGL、Metal 和 Direct 3D 一起工作的可移植应用程序,主要有两点需要注意:必须手动创建细分着色器的高速汇编语言版本并将其注入。对于 Metal 而言,必须指定适当的关键字。
首先,列出顶点和片段着色器。为了支持 Metal,添加了 TESSELLATION
关键字。这使 vertex.vert
在生成 Metal 着色器代码时能够接受特殊处理和转换。对于 OpenGL,由于仅在新版本的 OpenGL中有细分支持,所以我们限制了 GLSL 语言版本。
qt6_add_shaders(project "shaders_tessellation_part1" PREFIX "/shaders" GLSL "410,320es" TESSELLATION FILES "vertex.vert" "fragment.frag" )
其次,细分着色器通过单独的 qt6_add_shaders() 调用来列出。这是由于 NOHLSL
关键字。虽然顶点和片段着色器应像往常一样将其转换为 HLSL,但是将所有四个着色器保持在单个 qt6_add_shaders() 调用中没有实现。对于 Metal,还需要指定一些细分设置(输出顶点数、模式),因为与 Vulkan 和 OpenGL 不同,这些需要在前期知晓。
qt6_add_shaders(project "shaders_tessellation_part2" PREFIX "/shaders" NOHLSL GLSL "410,320es" TESSELLATION_VERTEX_COUNT 3 TESSELLATION_MODE "triangles" FILES "tess.tesc@hlsl,50,tess_hull.hlsl" "tess.tese@hlsl,50,tess_domain.hlsl" )
注意:仅推荐高级用户手动编写 hull 和 domain HLSL 着色器。某些结构,例如常数缓冲区,需要特别关注,以确保所有资源接口和布局与 SPIR-V/GLSL/MSL 着色器保持兼容。
© 2024 Qt公司有限公司。本文件中包含的文档贡献作品为各自所有者的版权。本文件提供的文档受自由软件基金会发布的GNU自由文档许可证1.3版条款许可。Qt及其相关标志是芬兰及全球其他国家的The Qt Company Ltd.的商标。所有其他商标均为各自所有者的财产。