QSB 用户手册
qsb
是由 Qt Shader Tools 模块提供的命令行工具。它集成了第三方库,例如 glslang 和 SPIRV-Cross,可选择调用外部工具,如 fxc
或 spirv-opt
,并生成 .qsb
文件。此外,它可以用来检查 .qsb
包的内容。
Usage: qsb [options] file Qt Shader Baker (using QShader from Qt 6.7.0) Options: -?, -h, --help Displays help on commandline options. --help-all Displays help, including generic Qt options. -v, --version Displays version information. -b, --batchable Also generates rewritten vertex shader for Qt Quick scene graph batching. --zorder-loc <location> The extra vertex input location when rewriting for batching. Defaults to 7. --glsl <versions> Comma separated list of GLSL versions to generate. (for example, "100 es,120,330") --hlsl <versions> Comma separated list of HLSL (Shader Model) versions to generate. F.ex. 50 is 5.0, 51 is 5.1. --msl <versions> Comma separated list of Metal Shading Language versions to generate. F.ex. 12 is 1.2, 20 is 2.0. --qt6 Equivalent to --glsl "100 es,120,150" --hlsl 50 --msl 12. This set is commonly used with shaders for Qt Quick materials and effects. --msltess Indicates that a vertex shader is going to be used in a pipeline with tessellation. Mandatory for vertex shaders planned to be used with tessellation when targeting Metal (--msl). --tess-vertex-count <count> The output vertex count from the tessellation control stage. Mandatory for tessellation evaluation shaders planned to be used with Metal. The default value is 3. If it does not match the tess.control stage, the generated MSL code will not function as expected. --tess-mode <mode> The tessellation mode: triangles or quads. Mandatory for tessellation control shaders planned to be used with Metal. The default value is triangles. Isolines are not supported with Metal. If it does not match the tess.evaluation stage, the generated MSL code will not function as expected. --view-count <num_views> The number of views the vertex shader is used with. Relevant for GL_OVR_multiview. Ignored for non-vertex. num_views should be >= 2. Set only for vertex shaders that do rely on multiview. -g Generate full debug info for SPIR-V and DXBC -O Invoke spirv-opt (external tool) to optimize SPIR-V for performance. -o, --output <filename> Output file for the shader pack. --qsbversion <version> QSB version to use for the output file. By default the latest version is automatically used, use only to bake compatibility versions. F.ex. 64 is Qt 6.4. -c, --fxc In combination with --hlsl invokes fxc to store DXBC instead of HLSL. -t, --metallib In combination with --msl builds a Metal library with xcrun metal(lib) and stores that instead of the source. Suitable only when targeting macOS, not iOS. -T, --metallib-ios In combination with --msl builds a Metal library with xcrun metal(lib) and stores that instead of the source. Suitable only when targeting iOS, not macOS. -D, --define <name[=value]> Define macro. This argument can be specified multiple times. -p, --per-target Enable per-target compilation. (instead of source->SPIRV->targets, do source->SPIRV->target separately for each target) -d, --dump Switches to dump mode. Input file is expected to be a shader pack. -x, --extract <what> Switches to extract mode. Input file is expected to be a shader pack. Result is written to the output specified by -o. Pass -b to choose the batchable variant. <what>=reflect|spirv,<version>|glsl,<version>|... -r, --replace <what> Switches to replace mode. Replaces the specified shader in the shader pack with the contents of a file. This argument can be specified multiple times. Pass -b to choose the batchable variant. Also supports adding a shader for a target/variant that was not present before. <what>=<target>,<filename> where <target>=spirv,<version>|glsl,<version>|... -e, --erase <what> Switches to erase mode. Removes the specified shader from the shader pack. Pass -b to choose the batchable variant. <what>=spirv,<version>|glsl,<version>|... -s, --silent Enables silent mode. Only fatal errors will be printed. Arguments: file Vulkan GLSL source file to compile. The file extension determines the shader stage, and can be one of .vert, .tesc, .tese, .frag, .comp. Note: Tessellation control/evaluation is not supported with HLSL, instead use -r to inject handcrafted hull/domain shaders. Some targets may need special arguments to be set, e.g. MSL tessellation will likely need --msltess, --tess-vertex-count, --tess-mode, depending on the stage.
操作模式
有五种主要操作模式
.qsb
文件生成。.qsb
文件检查。例如,使用qsb -d myshader.frag.qsb
将打印反射元数据(以 JSON 格式)和包含的着色器。- 提取模式。这允许将给定着色器从现有的
.qsb
文件写入单独的文件。例如,使用qsb -x spirv,100 -o myshader.spv myshader.frag.qsb
将 SPIR-V 二进制写入myshader.spv
。 - 替换模式。这允许用从指定文件读取的内容替换
.qsb
文件中一个或多个着色器的内容。通过这种方式,可以将手工制作的着色器代码注入到.qsb
包中。 - 删除模式。这将从
.qsb
文件中删除指定的着色器变体。
示例
以下是一个片段着色器
#version 440 layout(location = 0) in vec2 v_texcoord; layout(location = 0) out vec4 fragColor; layout(binding = 1) uniform sampler2D tex; layout(std140, binding = 0) uniform buf { float uAlpha; }; void main() { vec4 c = texture(tex, v_texcoord); fragColor = vec4(c.rgb, uAlpha); }
执行 qsb -o shader.frag.qsb shader.frag
会在结果中生成了 shader.frag.qsb
。使用 qsb -d shader.frag.qsb
检查该文件会给出
Stage: Fragment QSB_VERSION: 5 Has 1 shaders: Shader 0: SPIR-V 100 [Standard] Reflection info: { "combinedImageSamplers": [ { "binding": 1, "name": "tex", "set": 0, "type": "sampler2D" } ], "inputs": [ { "location": 0, "name": "v_texcoord", "type": "vec2" } ], "localSize": [ 0, 0, 0 ], "outputs": [ { "location": 0, "name": "fragColor", "type": "vec4" } ], "uniformBlocks": [ { "binding": 0, "blockName": "buf", "members": [ { "name": "uAlpha", "offset": 0, "size": 4, "type": "float" } ], "set": 0, "size": 4, "structName": "_27" } ] } Shader 0: SPIR-V 100 [Standard] Entry point: main Contents: Binary of 864 bytes
默认情况下只生成 SPIR-V,所以使用这个着色器包的应用程序仅能与 Vulkan 兼容。让我们使其更实用
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -o shader.frag.qsb shader.frag
这会生成一个适合 OpenGL、Direct 3D 和 Metal 的着色器包。此着色器使用的功能是基本的,甚至 GLSL ES 100(OpenGL ES 2.0 的着色语言)也适用。
检查结果会显示
Stage: Fragment QSB_VERSION: 5 Has 6 shaders: Shader 0: GLSL 120 [Standard] Shader 1: HLSL 50 [Standard] Shader 2: GLSL 100 es [Standard] Shader 3: MSL 12 [Standard] Shader 4: SPIR-V 100 [Standard] Shader 5: GLSL 150 [Standard] Reflection info: { ... <same as above> } Shader 0: GLSL 120 [Standard] Entry point: main Contents: #version 120 struct buf { float uAlpha; }; uniform buf _27; uniform sampler2D tex; varying vec2 v_texcoord; void main() { vec4 c = texture2D(tex, v_texcoord); gl_FragData[0] = vec4(c.xyz, _27.uAlpha); } ************************************ Shader 1: HLSL 50 [Standard] Entry point: main Native resource binding map: 0 -> [0, -1] 1 -> [0, 0] Contents: cbuffer buf : register(b0) { float _27_uAlpha : packoffset(c0); }; Texture2D<float4> tex : register(t0); SamplerState _tex_sampler : register(s0); static float2 v_texcoord; static float4 fragColor; struct SPIRV_Cross_Input { float2 v_texcoord : TEXCOORD0; }; struct SPIRV_Cross_Output { float4 fragColor : SV_Target0; }; void frag_main() { float4 c = tex.Sample(_tex_sampler, v_texcoord); fragColor = float4(c.xyz, _27_uAlpha); } SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) { v_texcoord = stage_input.v_texcoord; frag_main(); SPIRV_Cross_Output stage_output; stage_output.fragColor = fragColor; return stage_output; } ************************************ ... Shader 3: MSL 12 [Standard] Entry point: main0 Native resource binding map: 0 -> [0, -1] 1 -> [0, 0] Contents: #include <metal_stdlib> #include <simd/simd.h> using namespace metal; struct buf { float uAlpha; }; struct main0_out { float4 fragColor [[color(0)]]; }; struct main0_in { float2 v_texcoord [[user(locn0)]]; }; fragment main0_out main0(main0_in in [[stage_in]], constant buf& _27 [[buffer(0)]], texture2d<float> tex [[texture(0)]], sampler texSmplr [[sampler(0)]]) { main0_out out = {}; float4 c = tex.sample(texSmplr, in.v_texcoord); out.fragColor = float4(c.xyz, _27.uAlpha); return out; } ************************************ ...
此包现在可以用 Qt Quick 与所有支持的图形 API:Vulkan、Direct 3D、Metal、OpenGL 和 OpenGL ES。在运行时,Qt 快速渲染硬件界面自动选择合适的着色器,它位于 Qt Quick 和 Qt Quick 3D 之下。
除了将 SPIR-V 字节码翻译回高级源代码外,系统还处理其他问题,例如确保正确地将 SPIR-V 绑定号映射到本地资源。例如,使用 HLSL 我们看到上面的部分
Native resource binding map: 0 -> [0, -1] 1 -> [0, 0]
内部,这允许将 SPIR-V 样式的绑定点 0
映射到 HLSL 寄存器 b0
,并将 1
绑定到 t0
和 s0
。这有助于使用渲染硬件接口的用户对各种着色语言之间的资源绑定差异透明化,并允许 Qt 中的所有内容以它们在原始 Vulkan-style GLSL 源代码中指定的方式使用 Vulkan/SPIR-V 样式绑定点。
着色器类型
着色器类型从输入文件的扩展名推断得出。因此,扩展名必须是以下之一
.vert
- 用于顶点着色器.tesc
- 用于细分控制着色器.tese
- 用于细分评估着色器.frag
- 用于片段(像素)着色器.comp
- 用于计算着色器
注意:当前不支持使用Direct 3D (HLSL)的细分控制和平滑评估着色器。
着色器语言和版本
SPIR-V 1.0始终生成。此外生成的内容取决于命令行参数--glsl
、--hlsl
和--msl
。
这些参数后跟一个用逗号分隔的列表。列表必须包括具有可选后缀(表示GLSL ES的es
)的GLSL风格版本号。后缀和版本号之间的空格是可选的(没有空格可以帮助避免需要引号)。
例如,Qt Quick的内置材质(支持项目的着色器,如Image、Text、Rectangle)都使用--glsl "100 es,120,150" --hlsl 50 --msl 12
准备它们的着色器。这使得它们与OpenGL ES 2.0及更高版本、OpenGL 2.1及更高版本以及版本3.2及更高版本的OpenGL核心配置上下文兼容。
如果着色器使用了指定目标中不具有等价功能的函数或构造,qsb
将失败。如果情况如此,则需要调整目标,这也意味着应用程序的最低系统要求会隐式调整。例如,考虑仅适用于OpenGL ES 3.0及更高版本的textureLod
GLSL函数(意味着GLSL ES 300或更高)。当请求300 es
而不是100 es
时,qsb
将成功,但使用该.qsb
文件的应用程序现在需要OpenGL ES 3.0或更高版本,并且不支持基于OpenGL ES 2.0的系统。
另一个明显例子是计算着色器:需要指定--glsl 310es,430
,因为计算着色器仅在OpenGL ES 3.1或更新版和OpenGL 4.3或更新版可用。
对于HLSL,或Metal着色器语言的版本,预计很少需要调整着色器模型版本。通常足够的是着色器模型5.0(--hlsl 50
)和MSL 1.2(--msl 12
)。
Qt Quick场景图批处理
Qt Quick场景图的渲染器支持几何形状的批量处理以减少绘制调用次数。有关详细信息,请参阅场景图页面。这依赖于向顶点着色器的main()函数注入代码。在Qt 5.x中,这是通过修改提供的GLSL顶点着色器代码在运行时发生的。在Qt 6中,这不是一个选项。相反,可以使用qsb
工具构建可批量处理的顶点着色器变体。这是通过-b
参数请求的。当输入不是具有.vert
扩展的顶点着色器时,它没有效果。但是,对于顶点着色器,它将为每个目标生成两个版本。然后Qt Quick将在运行时自动选择正确的变体(标准或可批量处理)。
注意:应用程序无需担心批处理细节。它们只需确保在处理顶点着色器时指定-b
(或使用CMake集成时使用的等效BATCHABLE
关键字)。这对于与ShaderEffect或QSGMaterialShader一起使用的Qt Quick着色器是相关的。
以下是一个示例顶点着色器的例子:
#version 440 layout(location = 0) in vec4 position; layout(location = 1) in vec2 texcoord; layout(location = 0) out vec2 v_texcoord; layout(std140, binding = 0) uniform buf { mat4 mvp; } ubuf; void main() { v_texcoord = texcoord; gl_Position = ubuf.mvp * position; }
运行以下命令 qsb -b --glsl 330 -o example.vert.qsb example.vert
会得到:
Stage: Vertex QSB_VERSION: 5 Has 4 shaders: Shader 0: GLSL 330 [Standard] Shader 1: GLSL 330 [Batchable] Shader 2: SPIR-V 100 [Standard] Shader 3: SPIR-V 100 [Batchable] Reflection info: { ...
注意,所有目标语言和版本现在都存在两种变体:标准版本和略微修改过的可批处理版本。
调用外部工具
qsb
可以调用某些外部工具。这些工具分为两类:一类是对着色器字节码(SPIR-V)进行优化的工具,另一类是针对特定平台执行着色器编译第一阶段(从源代码到某些中间字节码格式)的工具。
以下命令行选项可以启用这些工具:
-O
- 将spirv-opt
作为对 SPIR-V 二进制文件的后期处理步骤调用。此.qsb
文件将包含优化后的版本。这假定spirv-opt
在系统上可用(例如,来自 Vulkan SDK)并准备好调用。-c
或--fxc
- 调用 Direct 3D 着色器编译器fxc.exe
。生成的DXBC
(DirectX 字节码)数据将存储在.qsb
文件中,而不是 HLSL。Qt 会自动在运行时选择它,所以.qsb
文件创建者需要决定包含什么,是 HLSL 源代码还是中间格式。当可能时,更喜欢后者,因为它消除了在运行时解析 HLSL 源代码的需求,从而在创建图形管道时可能实现显著的性能提升。缺点是,此参数只能在qsb
在 Windows 上运行时使用。-t
或--metallib
- 调用适当的 XCode Metal 工具以生成 .metallib 文件,并将其包含在.qsb
包中,而不是 MSL 源代码。此选项仅在qsb
在 macOS 上运行时可用。
其他选项
-D
- 定义一个宏。这允许在 GLSL 源代码中使用 #ifdef 和类似的宏。-g
- 为 SPIR-V 生成完整的调试信息,从而启用像 RenderDoc 这样的工具在检查管道或执行顶点或片段调试时显示完整的源代码。当指定-c
时,对于 Direct 3D 也会有影响,因为此时fxc
被指示在生成的中间字节码中包含调试信息。
修片
--msltess
- 表示顶点着色器在包含修片阶段的管道中使用。对于其他类型的着色器没有影响,当没有启用 MSL 着色器生成时也没有效果。如果没有指定,则顶点着色器与修片结合使用在 Metal 上将不起作用。--tess-vertex-count <count>
- 指定从修片控制阶段输出的顶点数量。对于与 Metal 一起使用的修片评估着色器,指定这是必要的。默认值为 3。如果它与修片控制阶段不匹配,生成的 MSL 代码将无法按预期工作。--tess-mode <mode>
- 此选项指定修片模式。它可以取两个值之一:triangles
或quads
。默认值为triangles
。对于与 Metal 一起使用的修片控制着色器,指定这是必要的。值必须与修片评估阶段匹配,否则生成的 MSL 代码将不会按预期工作。
多视图
以下是一个顶点着色器示例。它以与Vulkan兼容的GLSL编写,启用了GL_EXT_multiview
扩展,使使用gl_ViewIndex
合法。
#version 440 #extension GL_EXT_multiview : require layout(location = 0) in vec4 pos; layout(std140, binding = 0) uniform buf { mat4 mvp[2]; }; void main() { gl_Position = mvp[gl_ViewIndex] * pos; }
注意:在实际应用中,在将源代码传递到qsb
时,通常不需要在源代码中包含#extension GL_EXT_multiview行,因为以下描述的--view-count
参数会在编译到SPIR-V之前自动将此行注入到着色器源代码中。
对于Vulkan,只要支持运行时Vulkan 1.1,它就可以按原样工作。有关详细信息,请参阅<(face href="https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_multiview.html" translate="no">VK_KHR_multiview。
为了从上述代码生成用于Direct 3D 12(有关详细信息,请参阅--hlsl 50
时,qsb
将失败。处理多视图顶点着色器时,至少使用--hlsl 61
。Direct 3D 11不支持多视图。
对于OpenGL,需要额外的元数据
--view-count
- 在将上述着色器(在编译到SPIR-V之后)转换为兼容OpenGL的GLSL源代码时,仅将gl_ViewIndex
映射到gl_ViewID_OVR
是不够的,还需要在着色器中声明视图的数量。将2传递给--view-count
参数会在生成的GLSL源代码中注入一个layout(num_views = 2) in;
语句,从而使其成为一个有效的(OpenGL)GLSL着色器。有关详细信息,请参阅GL_OVR_multiview,并请注意,生成的GLSL着色器也要求在运行时支持GL_OVR_multiview2,因为生成的着色器源代码中将需要该指令。
当针对此类顶点着色器的OpenGL(ES)时,生成的GLSL版本(--glsl
)必须至少为330
或300 es
。前一个版本不是由qsb
或QShaderBaker强制执行的,但在实践中,如果GLSL版本为150或更小,OpenGL实现会拒绝此类着色器。因此,建议在启用GL_EXT_multiview的顶点着色器时使用--glsl 330,300es
。
指定--view-count
将自动生成并注入一个预处理定义:#define QSHADER_VIEW_COUNT n
,其中n
是视图数。如果没有提供视图数,则不会设置此定义。这允许编写以下代码,并允许使用相同的源文件为着色器的所有视图数特定变体。
layout(std140, binding = 0) uniform buf { #if QSHADER_VIEW_COUNT >= 2 mat4 matrix[QSHADER_VIEW_COUNT]; #else mat4 matrix; #endif float opacity; };
此外,当设置2或更多视图数时,会自动生成#extension GL_EXT_multiview : require
行。这减少了在顶点着色器中为多视图支持添加额外行的数量。
设置视图数也可以与其他类型的着色器相关。例如,在顶点和片段着色器之间共享统一缓冲区,并确保两者有相同的缓冲区布局时,能够在两个源文件中编写#if QSHADER_VIEW_COUNT >= 2
将是有用的。这可以通过在调用qsb
时为两者指定--view-count
来确保。
与OpenGL特定于GLSL的功能一起工作
有时可能需要使用特定于OpenGL和GLSL的着色语言构造,而不适用于其他着色语言、中间格式和图形API。
OpenGL ES的典型示例是其外部的纹理和采样器。实现视频播放或显示摄像头取景器可能涉及,具体取决于平台,使用OpenGL纹理对象,这些纹理对象不是为了作为常规2D纹理而设计的,而是可以通过OpenGL API中的GL_TEXTURE_EXTERNAL_OES绑定点以及着色器中的samplerExternalOES
采样器类型在有限的特性集下使用。后者在使用基于SPIR-V的Qt着色器管道时可能是一个潜在的故障点:通过qsb运行这样一个着色器将导致失败,因为samplerExternalOES
没有被接受为有效的类型,因为它不能映射到SPIR-V和其他目标着色语言。
为了克服这个问题,qsb提供了一种选项,可以将任何给定的shader variant在.qsb文件中的内容替换为从文件中读取的用户提供的数据,完全替换原始qsb生成的着色器源代码或字节码。
以下是一个片段着色器的例子。注意tex
的类型。如果在OpenGL ES中运行时类型需要是samplerExternalOES
呢?
#version 440 layout(location = 0) in vec2 texCoord; layout(location = 0) out vec4 fragColor; layout(std140, binding = 0) uniform buf { float opacity; } ubuf; layout(binding = 1) uniform sampler2D tex; void main() { fragColor = texture(tex, texCoord).rgba * ubuf.opacity; }
仅仅更改samplerExternalOES的类型是不可行的。这会立即导致编译错误。
然而,有一个简单的解决方案:编写一个针对OpenGL ES的独立版本,并将其注入到.qsb文件中。以下着色器仅与GLSL ES兼容,不能通过qsb运行。然而,我们知道它在运行时可以被OpenGL ES处理。
precision highp float; #extension GL_OES_EGL_image_external : require varying vec2 texCoord; struct buf { float opacity; }; uniform buf ubuf; uniform samplerExternalOES tex; void main() { gl_FragColor = texture2D(tex, texCoord).rgba * ubuf.opacity; }
让我们将其称为shader_gles.frag
。一旦qsb --glsl 100es -o shader.frag.qsb shader.frag
完成,给我们一个(半完成了的).qsb文件,我们可以做qsb -r glsl,100es,shader_gles.frag shader.frag.qsb
来更新shader.frag.qsb
,通过替换指定文件(shader_gles.frag
)中的GLSL 100 es着色器的内容。现在shader.frag.qsb
就准备好在运行时与OpenGL ES一起使用了。
注意: 请注意保持着色器和应用程序之间的接口不变。始终首先检查qsb生成的GLSL代码,可以通过-d
选项打印.qsb文件的内容,或者通过运行qsb -x glsl,100es -o gles_shader.frag shader.frag.qsb
提取GLSL ES 100着色器。手动注入的版本中结构体、结构体成员和uniform名称也不能不同。
注意: 将数据从任意文件放入.qsb包的能力还可以用来注入手制的域HLSL着色器,以便使基于纹理的图形管线与Direct 3D兼容。
© 2024 Qt公司有限公司。此处包含的文档贡献版权属于各自的拥有者。此处提供的文档是根据Free Software Foundation发布的