QShaderBaker Class
将 GLSL/Vulkan 着色器编译为 SPIR-V,翻译为其他着色语言,并收集反射元数据。更多
Header: | #include <QShaderBaker> |
Since: | Qt 6.6 |
公共类型
GeneratedShader | |
enum class | GlslOption { GlslEsFragDefaultFloatPrecisionMedium } |
flags | GlslOptions |
enum class | SpirvOption { GenerateFullDebugInfo, StripDebugAndVarInfo } |
flags | SpirvOptions |
公共函数
QShaderBaker() | |
~QShaderBaker() | |
QShader | bake() |
QString | errorMessage() const |
void | setBatchableVertexShaderExtraInputLocation(int location) |
void | setBreakOnShaderTranslationError(bool enable) |
void | setGeneratedShaderVariants(const QList<QShader::Variant> &v) |
void | setGeneratedShaders(const QList<QShaderBaker::GeneratedShader> &v) |
(since 6.9) void | setGlslOptions(QShaderBaker::GlslOptions options) |
(since 6.7) void | setMultiViewCount(int count) |
void | setPerTargetCompilation(bool enable) |
void | setPreamble(const QByteArray &preamble) |
void | setSourceDevice(QIODevice *device, QShader::Stage stage, const QString &fileName = QString()) |
void | setSourceFileName(const QString &fileName) |
void | setSourceFileName(const QString &fileName, QShader::Stage stage) |
void | setSourceString(const QByteArray &sourceString, QShader::Stage stage, const QString &fileName = QString()) |
void | setSpirvOptions(QShaderBaker::SpirvOptions options) |
void | setTessellationMode(QShaderDescription::TessellationMode mode) |
void | setTessellationOutputVertexCount(int count) |
详细说明
警告: QShaderBaker 与 Qt GUI 模块中的QRhi 系列类(包括QShader 和QShaderDescription )一样,提供有限的兼容性保证。这些类没有源代码或二进制兼容性保证,这意味着 API 只能保证与应用程序开发时所使用的 Qt 版本兼容。不过,源代码不兼容的更改将保持在最低水平,并且只会在次版本(6.7、6.8 等)中进行。要在应用程序中使用该类,请链接至Qt::ShaderToolsPrivate
(如果使用 CMake),并包含带有rhi
前缀的头文件,例如#include <rhi/qshaderbaker.h>
。
QShaderBaker 接收图形(顶点、片段等)或计算着色器,并生成其多个(源代码或字节码)变体以及反射信息。结果由QShader 实例表示,该实例还提供简单快速的序列化和反序列化功能。
注意: 建议应用程序和程序库避免直接使用该类。相反,我们鼓励所有 Qt 用户在构建时通过 CMake 调用qsb
命令行工具,依赖离线编译。qsb
工具使用 QShaderBaker 并将生成的QShader 序列化版本写入文件。该类的使用应仅限于无法避免运行时编译的情况,如处理用户提供或动态生成的着色器源字符串时。
目前,输入格式总是假定为 Vulkan 风格的 GLSL。有关概述,请参阅GL_KHR_vulkan_glsl 规范,请注意 QtShader Tools 模块旨在与 Qt 渲染硬件接口模块中的QRhi 类结合使用,因此一些概念和构造(推送常量、存储缓冲区、子旁路等)目前并不适用。未来可能会引入更多选项,例如,一旦HLSL到 SPIR-V 的编译被认为合适,就会启用 HLSL 作为源格式。
通过调用QShader::description() 可以从生成的QShader 中获取反射元数据。这在发现着色器所期望的顶点输入和着色器资源集以及这些资源的布局时非常重要,因为许多现代图形应用程序接口都不提供内置的着色器反射功能。
典型工作流程
假设一个应用程序有如下顶点和片段着色器:
顶点着色器
#version 440 layout(location = 0) in vec4 position; layout(location = 1) in vec3 color; layout(location = 0) out vec3 v_color; layout(std140, binding = 0) uniform buf { mat4 mvp; float opacity; }; void main() { v_color = color; gl_Position = mvp * position; }
片段着色器
#version 440 layout(location = 0) in vec3 v_color; layout(location = 0) out vec4 fragColor; layout(std140, binding = 0) uniform buf { mat4 mvp; float opacity; }; void main() { fragColor = vec4(v_color * opacity, opacity); }
要获得可原样传递给QRhiGraphicsPipeline 的QShader 实例,有两种选择:离线生成着色器包或在运行时生成着色器包。
前者需要运行qsb
工具:
qsb --glsl "100 es,120" --hlsl 50 --msl 12 color.vert -o color.vert.qsb qsb --glsl "100 es,120" --hlsl 50 --msl 12 color.frag -o color.frag.qsb
该示例使用适合QRhi 的翻译目标。这意味着 GLSL/ES 100、GLSL 120、HLSL着色器模型 5.0 和金属着色语言 1.2。
请注意命令行选项与通过setGeneratedShaders() 指定的选项的对应关系。一旦生成的文件可用,它们就可以与应用程序一起发布(通常嵌入到 Qt 资源系统的可执行文件中),并可以在运行时加载和传递给QShader::fromSerialized() 。
虽然这里没有显示,但qsb
还能做更多:它还能在 Windows 上调用fxc
或在 macOS 上调用相应的 XCode 工具,将生成的 HLSL 或 Metal Shader 代码编译成字节码,并将编译后的版本包含在QShader 中。在将已出炉的 Shader 包写入文件后,可通过运行qsb -d
来检查其内容。运行qsb
和--help
可获取更多信息。
另一种方法是在运行时执行同样的操作。这需要创建一个 QShaderBaker 实例,调用setSourceFileName() ,然后通过setGeneratedShaders() 设置翻译目标:
baker.setGeneratedShaderVariants({ QShader::StandardShader }); QList<QShaderBaker::GeneratedShader> targets; targets.append({ QShader::SpirvShader, QShaderVersion(100) }); targets.append({ QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs) }); targets.append({ QShader::SpirvShader, QShaderVersion(120) }); targets.append({ QShader::HlslShader, QShaderVersion(50) }); targets.append({ QShader::MslShader, QShaderVersion(12) }); baker.setGeneratedShaders(targets); QShader shaders = baker.bake(); if (!shaders.isValid()) qWarning() << baker.errorMessage();
另请参见 QShader 。
成员类型文档
QShaderBaker::GeneratedShader
QPair<QShader::Source,QShaderVersion> 的同义词。
枚举类 QShaderBaker::GlslOption
标志 QShaderBaker::GlslOptions
常量 | 值 | 描述 |
---|---|---|
QShaderBaker::GlslOption::GlslEsFragDefaultFloatPrecisionMedium | 0x01 | 在 GLSL ES 的片段着色器中发射precision mediump float; 。 |
GlslOptions 类型是QFlags<GlslOption> 的类型定义。它存储 GlslOption 值的 OR 组合。
枚举类 QShaderBaker::SpirvOption
标志 QShaderBaker::SpirvOptions
常量 | 值 | 描述 |
---|---|---|
QShaderBaker::SpirvOption::GenerateFullDebugInfo | 0x01 | 在 SPIR-V 二进制文件中生成并存储额外的调试信息。 |
QShaderBaker::SpirvOption::StripDebugAndVarInfo | 0x02 | 从 SPIR-V 二进制文件中删除所有调试和变量名信息。 |
SpirvOptions 类型是QFlags<SpirvOption> 的类型定义。它存储 SpirvOption 值的 OR 组合。
成员函数文档
QShaderBaker::QShaderBaker()
构造一个新的 QShaderBaker。
[noexcept]
QShaderBaker::~QShaderBaker()
毁灭者
QShader QShaderBaker::bake()
运行编译和翻译过程。
返回QShader 实例。要检查进程是否成功,请调用QShader::isValid() 。当显示false
时,调用errorMessage() 以获取日志。
这是一个昂贵的操作。在应用程序中调用此操作时,最好在单独的线程中进行。
注意: QShaderBaker 实例是可重复使用的:调用 bake() 后,同一实例可再次用于不同的输入。不过,QShaderBaker 实例在其生命周期内只能在一个线程上使用。
QString QShaderBaker::errorMessage() const
返回上次运行bake() 时的错误信息,如果没有错误,则返回空字符串。
注意: 错误包括文件读取错误、编译和翻译失败。即使生成的QShader 无效,未请求任何目标或变体也不算错误。
void QShaderBaker::setBatchableVertexShaderExtraInputLocation(int location)
生成QShader::BatchableVertexShader 变体时,location 指定插入顶点输入的输入位置。默认值为 7,只有当顶点着色器已经使用输入位置 7 时才需要重载。
void QShaderBaker::setBreakOnShaderTranslationError(bool enable)
控制着色器转换(从 SPIR-V 到 GLSL/HLSL/MSL)失败时的行为。默认情况下,此设置为 true,如果无法生成所请求的着色器,bake() 将返回错误信息。如果不希望出现这种情况,而只是想生成我们能生成的,但默默跳过其他部分,则可将enable 设置为 false。
针对多个 GLSL 版本可能会在某个功能无法翻译到指定版本时导致错误。例如,如果尝试将使用 textureSize() 的着色器翻译为 GLSL ES 100,则整个bake() 调用都会失败,并显示错误信息 "textureSize 在 ESSL 100 中不受支持"。如果可以接受结果中不包含 GLSL ES 100 着色器(即使请求了 GLSL ES 100 着色器),那么将此标记设置为 false 就能使bake() 成功。
void QShaderBaker::setGeneratedShaderVariants(const QList<QShader::Variant> &v)
指定生成的着色器变体。每个着色器版本在生成的QShader 中可以有多个变体。
大多数情况下,v 只包含一个条目,即QShader::StandardShader 。
注意: 如果未设置变体,生成的QShader 将为空,因此无效。
void QShaderBaker::setGeneratedShaders(const QList<QShaderBaker::GeneratedShader> &v)
指定要编译或翻译成哪种着色器。默认情况下不会生成任何内容,因此必须在bake() 之前调用此函数。
注意: 如果未调用此函数或v 为空或仅包含无效条目,则生成的QShader 将为空,因此无效。
例如,可能的最小烘焙目标是 SPIR-V,没有任何其他语言的翻译。请执行以下操作
baker.setGeneratedShaders({ QShader::SpirvShader, QShaderVersion(100) });
注意: QShaderBaker 只处理 SPIR-V 和人类可读源代码目标。进一步编译为特定于 API 的中间格式(如QShader::DxbcShader 或QShader::MetalLibShader )由qsb
命令行工具实现,并非QShaderBaker 运行时 API 的一部分。
[since 6.9]
void QShaderBaker::setGlslOptions(QShaderBaker::GlslOptions options)
为生成的 GLSL 和 GLSL ES 源设置额外的options 。默认情况下不设置任何标志。
此函数在 Qt 6.9 中引入。
[since 6.7]
void QShaderBaker::setMultiViewCount(int count)
在转译使用多视图的着色器时(例如,为依赖 GL_OVR_multiview2、VK_KHR_multiview 等的渲染器转译使用 gl_ViewIndex 的顶点着色器),对于某些目标,有必要在着色器中声明视图的数量。这在 Vulkan 风格的 GLSL 代码中并不存在,也与 SPIR-V 或 HLSL 等目标无关,但对于 OpenGL 和 GLSL 则是必需的,因此必须将该值作为附加元数据提供。
默认值为 0,即禁止注入num_views
语句。设置 1 并无用处,因为无论如何,这都是默认的num_views
。因此,count 应大于等于 2 才有效。例如,当设置为 2 时,生成的 GLSL 着色器将包含layout(num_views = 2) in;
语句。
将count 设置为 2 或更大时,也会注入一些预处理器语句:QSHADER_VIEW_COUNT
设置为count ,而GL_EXT_multiview
扩展会自动启用。因此,设置适当的count 也与其他类型的着色器有关,例如,当顶点着色器和片段着色器共享一个统一缓冲区时,两个着色器都必须能够写入类似#if QSHADER_VIEW_COUNT >= 2
的内容。
该功能在 Qt 6.7 中引入。
void QShaderBaker::setPerTargetCompilation(bool enable)
将 "按目标编译 "设置为enable 。默认情况下,该选项被禁用,这意味着 Vulkan/GLSL 源会按每个变体编译一次到 SPIR-V(默认情况下编译一次,如果是顶点着色器,则编译两次)。(因此,默认情况下编译一次,如果是顶点着色器和可批处理变体,则编译两次)。生成的 SPIR-V 会被翻译成各种目标语言(GLSL、HLSL、MSL)。
在按目标编译模式下,每个目标都有一个单独的 GLSL 到 SPIR-V 的编译步骤,即通过setGeneratedShaders() 请求的每个 GLSL/HLSL/MSL 版本。输入源是相同的,但插入了特定目标的预处理器定义。这种模式耗时较多,但允许应用程序提供单一着色器,并使用#ifdef
块进行区分。禁用该模式后,实现相同效果的唯一方法是提供多个版本的着色器文件,分别处理每个文件,为每个文件提供 {.qsb} 文件,并根据运行时逻辑选择正确的文件。
在此模式下,将自动定义以下宏。请注意,宏始终与着色语言而非图形 API 相关联。
QSHADER_SPIRV
- 在针对 SPIR-V 时定义的宏(通常由 Vulkan 使用)。QSHADER_SPIRV_VERSION
- 目标 SPIR-V 版本号,如 。100
QSHADER_GLSL
- 针对 GLSL 或 GLSL ES(通常由 OpenGL 或 OpenGL ES 使用)时的定义QSHADER_GLSL_VERSION
- 目标 GLSL 或 GLSL ES 版本号,如 、 或 。100
300
330
QSHADER_GLSL_ES
- 仅在针对 GLSL ES 时定义QSHADER_HLSL
- 针对 HLSL 时定义(通常由 Direct 3D 使用)QSHADER_HLSL_VERSION
- 目标 HLSL 着色器模型版本,如50
QSHADER_MSL
- 针对金属着色语言时定义(通常由 Metal 使用)QSHADER_MSL_VERSION
- 目标 MSL 版本,如 或 。12
20
这样就可以编写如下着色器代码。
#if QSHADER_HLSL || QSHADER_MSL vec2 uv = vec2(uv_coord.x, 1.0 - uv_coord.y); #else vec2 uv = uv_coord; #endif
注: 版本号采用受 GLSL 启发的QShaderVersion 语法,因此始终是一个整数。
注: 无论有多少个单独目标,每个QShader 都只有一个QShaderDescription 。因此,不得使用上述宏将统一块、顶点输入等成员设为条件。
警告 请注意图形应用程序接口和着色语言概念之间的差异。QShaderBaker 和相关工具严格按照着色语言的概念工作,而忽略了之后如何使用结果。因此,如果有一天 Qt 图形栈的高层也开始将 SPIR-V 用于 Vulkan 之外的其他 API,那么 QSHADER_SPIRV 意味着 Vulkan 的假设将不再成立。
void QShaderBaker::setPreamble(const QByteArray &preamble)
指定先于正常着色器代码处理的自定义preamble 。
这不仅仅是对源代码字符串进行预处理:GLSL 版本指令的有效性不会受到影响,该指令必须放在所有其他指令之前。报告的错误信息中的行号也保持不变,忽略preamble 中给出的内容。
序言的一个用例是透明插入动态生成的#define
语句。
void QShaderBaker::setSourceDevice(QIODevice *device, QShader::Stage stage, const QString &fileName = QString())
设置源device 。QIODevice stage 指定着色器阶段,而可选的fileName 包含错误信息中使用的文件名。
警告: 预计device 包含可信内容。建议应用程序开发人员在从不受应用程序控制的来源传递用户提供的数据之前,仔细考虑其潜在影响。
void QShaderBaker::setSourceFileName(const QString &fileName)
将着色器源文件的名称设置为fileName 。这是调用bake() 时读取的文件。着色器阶段会根据文件扩展名自动推断。如果不希望或不可能这样做,请使用带有 stage 参数的重载。
支持的文件扩展名有
.vert
- 顶点着色器.frag
- 片段(像素)着色器.tesc
- 细分控制(体)着色器.tese
- 细分评估(域)着色器.geom
- 几何着色器.comp
- 计算着色器
警告: fileName 预计包含可信内容。建议应用程序开发人员在传入用户提供的非应用程序源文件之前,仔细考虑其潜在影响。
void QShaderBaker::setSourceFileName(const QString &fileName, QShader::Stage stage)
将着色器源文件的名称设置为fileName 。这是调用bake() 时读取的文件。着色器阶段由stage 指定。
警告: fileName 预计包含可信内容。建议应用程序开发人员在传入非应用程序一部分的用户提供源文件之前,仔细考虑其潜在影响。
void QShaderBaker::setSourceString(const QByteArray &sourceString, QShader::Stage stage, const QString &fileName = QString())
设置输入着色器sourceString 。stage 指定着色器阶段,而可选的fileName 包含错误信息中使用的文件名。
警告: sourceString 预计包含可信内容。建议应用程序开发人员在从不受应用程序控制的来源传递用户提供的数据之前,仔细考虑潜在的影响。
void QShaderBaker::setSpirvOptions(QShaderBaker::SpirvOptions options)
为生成的 SPIR-V 二进制文件设置附加options 。默认情况下不设置任何标记。
void QShaderBaker::setTessellationMode(QShaderDescription::TessellationMode mode)
为细分控制着色器生成 MSL 着色器代码时,必须预先知道细分mode (三角形或四边形)。在 GLSL 中,这通常在细分评估着色器中声明,但对于 Metal 来说,从细分控制着色器生成计算着色器时也必须知道这一点。
未设置时,默认值为三角形。
void QShaderBaker::setTessellationOutputVertexCount(int count)
在为细分曲面评估着色器生成 MSL 着色器代码时,必须预先知道细分曲面控制着色器的输出顶点count 。在 GLSL 中,这通常在细分曲面控制着色器中声明,但对于 Metal 来说,从细分曲面评估着色器生成顶点着色器时也必须知道。
未设置时,默认值为 3。
© 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.