QtShader Tools 构建系统集成
编译着色器并将其添加到 Qt 资源中
简介
QtShader Tools模块提供了一个 CMake 宏文件,它提供了有用的函数,应用程序可以在其CMakeLists.txt
中使用这些函数。
使用qt6_add_shaders
函数时,编译系统会自动调用qsb工具,并将生成的.qsb
文件隐式添加到资源系统中。
第一个例子
我们来看一个简单的例子。假设我们有一个Qt Quick 应用程序,它希望通过ShaderEffect 提供自己的摇摆效果。片段着色器在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 的片段着色器。
注意: 请注意find_package
行。find_package
对于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 上下文)、着色器模型 5.0 的 HLSL 源(用于 Direct3D 11.1)和 Metal 着色语言 1.2 源(用于 Metal)。
对于Qt Quick 而言,这是一套很好的默认设置,可以创建高度可移植到各种系统的应用程序。不过,这些默认设置并不总是合适的。如果着色器使用的函数或构造在这些目标中没有对应的函数或构造,那么编译过程就会失败。如果是这种情况,就需要调整目标,这也意味着应用程序的最低系统要求会被隐式调整。以textureLod
GLSL 函数为例,该函数仅适用于 OpenGL ES 3.0 及以上版本(即 GLSL ES 300 或更高版本)。当请求 GLSL300 es
而不是100 es
时,构建会成功,但生成的应用程序现在需要 OpenGL ES 3.0 或更高版本,与基于 OpenGL ES 2.0 的系统不兼容。
着色器类型
着色器类型由文件扩展名推断。因此,扩展名必须是以下其中之一:
.vert
- 顶点着色器.tesc
- 用于细分控制着色器.tese
- 用于细分评估着色器.frag
- 片段(像素)着色器.comp
- 计算着色器
注意: Direct 3D (HLSL) 目前不支持细分控制和评估着色器。一种可行的解决方法是手动创建 "艇体 "和 "域 "着色器,并通过FILES
部分中的文件置换语法注入它们。
目标
可使用以下关键字:
GLSL
- 请求为给定的 GLSL 版本列表生成源代码。请注意,该列表应遵循以逗号分隔的 语法。例如,计算着色器需要在此处指定 ,因为默认值不适合它。qsb
"310 es,430"
NOGLSL
- 无参数关键字禁止生成 GLSL 源代码。适用于完全不想使用 OpenGL 的应用程序。HLSL
- 要求为给定的 HLSL(着色器模型)版本列表生成源代码。 工具遵循 GLSL 风格的版本号,因此 对应 Shader Model 5.0, 是 5.1。qsb
50
51
NOHLSL
- 无参数关键字禁止生成 HLSL 源代码。适用于完全不希望使用 Direct 3D 的应用程序。MSL
- 要求为指定版本的金属着色语言生成源代码。 对应 1.2, 对应 2.0。12
20
NOMSL
- 这个无参数关键字禁止生成 MSL 源代码。适用于完全不想使用 Metal 的应用程序。
最常用的覆盖设置是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
后缀前的空格为可选项。
细分
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() 调用中。设置 会自动在着色器源代码中注入具有相同值的预处理器定义 。此外,当视图数设置为 2 或更大时, 行会自动注入顶点着色器。请注意,对于多视图,GLSL 的最小版本为 和 。对于 HLSL,最低版本为 。建议应用程序相应设置语言目标(或更新版本)。VIEW_COUNT
QSHADER_VIEW_COUNT
#extension GL_EXT_multiview : require
330
300 es
61
此选项在 Qt 6.7 中引入。
MULTIVIEW
- 要求同时生成一组非多视图和视图数 2 的着色器。这实际上是为了方便手动创建两个带有相应 GLSL/HLSL/MSL/VIEW_COUNT 参数的 qt_add_shaders() 调用。该选项主要供 Qt 自用,但只要多视图变量的隐式设置足以满足应用程序着色器的需要,应用程序也可以使用它:GLSL 330,300es HLSL 61 MSL 12。多视图变量的 VIEW_COUNT 设置为 2。多视图变量存储在带有 后缀的文件中(除了 )。.mv2qsb
.qsb
该选项在 Qt 6.8 中引入。
Qt Quick 具体内容
BATCHABLE
- 对于与 一起使用的顶点着色器,无论是在 还是在 中,指定这个单一的、无参数的关键字都是必要的。它对片段着色器或计算着色器没有影响,不同类型的着色器可以安全地包含在同一个列表中,因为关键字只在 文件中被考虑。等同于Qt Quick ShaderEffect QSGMaterialShader.vert
qsb 的 参数。-b
ZORDER_LOC
- 指定 时,默认情况下会在 位置注入额外的顶点输入。该关键字用于将该位置更改为其他值。如果顶点着色器有多个输入,而其中 7 个正在使用,则会发生冲突,这时就需要使用此关键字。BATCHABLE
7
调用外部工具
PRECOMPILE
- 相当于qsb 的 或 选项(取决于平台)。在 Windows 平台上构建时,这将导致在构建时而不是运行时调用 Windows SDK 中的 来完成编译的第一阶段(将 HLSL 源代码编译为 DXBC 字节码)。生成的 文件将只包含编译结果(中间着色器格式),而不包含原始着色器源代码。-c
-t
fxc
.qsb
OPTIMIZED
- 调用 (必须可从 Vulkan SDK 或其他地方获取)对 SPIR-V 字节码进行优化。相当于spirv-opt
qsb 的 参数。-O
其他设置
DEFINES
- 定义在着色器编译过程中激活的宏。等同于qsb 的 参数。该列表的形式与 相同。或者,与 一样,该列表也可以用换行分隔。-D
"name1=value1;name2=value2"
FILES
OUTPUTS
- 当生成的 .qsb 文件的名称需要与源文件不同时(例如,由于通过 进行区分,一个着色器文件可以作为多个 .qsb 文件的源文件),该列表可以包含 中每项的一个条目,指定一个通常以 结尾的文件名。指定的名称会在 参数中传递给 qsb,而不是直接将 附加到源文件名称中。DEFINES
FILES
.qsb
-o
.qsb
DEBUGINFO
- 为 SPIR-V 生成完整的调试信息,从而使RenderDoc等工具能够在检查管道或执行顶点或片段调试时显示完整的源文件。相当于qsb 的 参数。如果指定了 关键字,对 Direct 3D 也有影响,因为 会被指示在生成的中间字节码中包含调试信息。-g
PRECOMPILE
fxc
QUIET
- 禁止 qsb 的调试和警告输出。只打印致命错误。OUTPUT_TARGETS
- 在静态库中使用 qt_add_shaders 时,会生成一个或多个特殊目标。如果希望对这些目标值进行额外处理,请向 OUTPUT_TARGETS 参数传递一个值。MEDIUMP
- 请求将 GLSL ES 片段着色器中的浮点默认为中等精度。忽略其他目标,包括(非 ES)GLSL。
替换手工制作的着色器
CMake 集成还支持在生成的 .qsb 文件中指定着色器特定版本的替换。这实际上等同于使用-r
命令行选项运行qsb。
这可以通过 FILES 列表中的以下特殊语法实现:
FILES "shaders/externalsampler.frag@glsl,100es,shaders/externalsampler_gles.frag"
文件名后面可以是任意多个@分隔的替换规范。每个替换规范都指定了着色语言、版本和要读取数据的文件,并用逗号分隔。详情请参见《QSB 手册》。
细分示例
图形流水线由四个阶段组成:顶点阶段(着色器vertex.vert
)、细分控制阶段(着色器tess.tesc
)、细分评估阶段(着色器tess.tese
)和片段阶段(着色器fragment.frag
)。
要构建一个能够在 Vulkan、OpenGL、Metal 和 Direct 3D 中运行的完全可移植的应用程序,有两件主要的事情需要注意:HLSL 版本的细分着色器必须手动创建,然后注入。而对于 Metal,则必须指定相应的关键字。
首先,列出顶点着色器和片段着色器。为了支持 Metal,添加了TESSELLATION
关键字。这样,在生成 Metal 着色器代码时,就可以对vertex.vert
进行特殊处理和转换。对于 OpenGL,我们限制使用 GLSL 语言版本,因为只有较新的 OpenGL 版本才支持细分。
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() 调用中保留所有四个着色器是不可行的。与 Vulkan 和 OpenGL 不同,Metal 会指定一些细分设置(输出顶点数、模式),因为这些设置需要预先知道。
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" )
注意: 仅建议高级用户手动编写船体和域 HLSL 着色器。某些构造(如常量缓冲区)需要特别注意,以便所有资源接口和布局与 SPIR-V/GLSL/MSL 着色器保持兼容。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.