Compiles a GLSL/Vulkan shader into SPIR-V, translates into other shading languages, and gathers reflection metadata. 更多...
头: | #include <QShaderBaker> |
Since: | Qt 6.6 |
GeneratedShader | |
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 ) |
(从 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 | setTessellationMode (QShaderDescription::TessellationMode mode ) |
void | setTessellationOutputVertexCount (int count ) |
警告:
QShaderBaker, just like the
QRhi
family of classes in the Qt Gui module, including
QShader
and
QShaderDescription
, offers limited compatibility guarantees. There are no source or binary compatibility guarantees for these classes, meaning the API is only guaranteed to work with the Qt version the application was developed against. Source incompatible changes are however aimed to be kept at a minimum and will only be made in minor releases (6.7, 6.8, and so on). To use this class in an application, link to
Qt::ShaderToolsPrivate
(if using CMake), and include the headers with the
rhi
prefix, for example
#include <rhi/qshaderbaker.h>
.
QShaderBaker takes a graphics (vertex, fragment, etc.) or compute shader, and produces multiple - either source or bytecode - variants of it, together with reflection information. The results are represented by a QShader instance, which also provides simple and fast serialization and deserialization.
注意:
Applications and libraries are recommended to avoid using this class directly. Rather, all Qt users are encouraged to rely on offline compilation by invoking the
qsb
command-line tool at build time via CMake. The
qsb
tool uses QShaderBaker and writes the serialized version of the generated
QShader
into a file. The usage of this class should be restricted to cases where run time compilation cannot be avoided, such as when working with user-provided or dynamically generated shader source strings.
The input format is always assumed to be Vulkan-flavored GLSL at the moment. See the GL_KHR_vulkan_glsl specification for an overview, keeping in mind that the Qt Shader Tools module is meant to be used in combination with the QRhi classes from Qt Rendering Hardware Interface module, and therefore a number of concepts and constructs (push constants, storage buffers, subpasses, etc.) are not applicable at the moment. Additional options may be introduced in the future, for example, by enabling HLSL as a source format, once HLSL to SPIR-V compilation is deemed suitable.
The reflection metadata is retrievable from the resulting QShader 通过调用 QShader::description (). This is essential when having to discover what set of vertex inputs and shader resources a shader expects, and what the layouts of those are, as many modern graphics APIs offer no built-in shader reflection capabilities.
Let's assume an application has a vertex and fragment shader like the following:
Vertex shader:
#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; }
Fragment shader:
#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); }
To get QShader instances that can be passed as-is to a QRhiGraphicsPipeline , there are two options: doing the shader pack generation off line, or at run time.
The former involves running the
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
The example uses the translation targets as appropriate for QRhi . This means GLSL/ES 100, GLSL 120, HLSL Shader Model 5.0, and Metal Shading Language 1.2.
Note how the command line options correspond to what can be specified via setGeneratedShaders (). Once the resulting files are available, they can be shipped with the application (typically embedded into the executable the the Qt Resource System), and can be loaded and passed to QShader::fromSerialized () at run time.
While not shown here,
qsb
can do more: it is also able to invoke
fxc
on Windows or the appropriate XCode tools on macOS to compile the generated HLSL or Metal shader code into bytecode and include the compiled versions in the
QShader
. After a baked shader pack is written into a file, its contents can be examined by running
qsb -d
on it. Run
qsb
with
--help
了解更多信息。
The alternative approach is to perform the same at run time. This involves creating a QShaderBaker instance, calling setSourceFileName (), and then setting up the translation targets via 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 .
同义词 QPair < QShader::Source , QShaderVersion >.
Constructs a new QShaderBaker.
[noexcept]
QShaderBaker::
~QShaderBaker
()
析构函数。
Runs the compilation and translation process.
返回
QShader
instance. To check if the process was successful, call
QShader::isValid
(). When that indicates
false
,调用
errorMessage
() to retrieve the log.
This is an expensive operation. When calling this from applications, it can be advisable to do it on a separate thread.
注意: QShaderBaker instances are reusable: after calling bake(), the same instance can be used with different inputs again. However, a QShaderBaker instance should only be used on one single thread during its lifetime.
Returns the error message from the last bake () run, or an empty string if there was no error.
注意: Errors include file read errors, compilation, and translation failures. Not requesting any targets or variants does not count as an error even though the resulting QShader 无效。
When generating a QShader::BatchableVertexShader variant, location specifies the input location for the inserted vertex input. The value is by default 7 and needs to be overridden only if the vertex shader already uses input location 7.
Controls the behavior when shader translation (from SPIR-V to GLSL/HLSL/MSL) fails. By default this setting is true, which will cause bake () to return with an error if a requested shader cannot be generated. If that is not desired, and the intention is to generate what we can but silently skip the rest, then set enable 为 false。
Targeting multiple GLSL versions can lead to errors when a feature is not translatable to a given version. For example, attempting to translate a shader using textureSize() to GLSL ES 100 would fail the entire bake () call with the error message "textureSize is not supported in ESSL 100". If it is acceptable to not have a GLSL ES 100 shader in the result, even though it was requested, then setting this flag to false makes bake () to succeed.
Specifies which shader variants are generated. Each shader version can have multiple variants in the resulting QShader .
In most cases v contains a single entry, QShader::StandardShader .
注意: when no variants are set, the resulting QShader will be empty and thus invalid.
Specifies what kind of shaders to compile or translate to. Nothing is generated by default so calling this function before bake () is mandatory
注意: when this function is not called or v is empty or contains only invalid entries, the resulting QShader will be empty and thus invalid.
For example, the minimal possible baking target is SPIR-V, without any additional translations to other languages. To request this, do:
baker.setGeneratedShaders({ QShader::SpirvShader, QShaderVersion(100) });
注意:
QShaderBaker
only handles the SPIR-V and human-readable source targets. Further compilation into API-specific intermediate formats, such as
QShader::DxbcShader
or
QShader::MetalLibShader
is implemented by the
qsb
command-line tool, and is not part of the
QShaderBaker
runtime API.
[since 6.7]
void
QShaderBaker::
setMultiViewCount
(
int
count
)
When transpiling shaders using multiview (e.g. a vertex shader using gl_ViewIndex for a renderer relying on GL_OVR_multiview2, VK_KHR_multiview, etc.), for some of the targets it is necessary to declare the number of views in the shader. This is not done in the Vulkan-style GLSL code, and is not relevant for targets such as SPIR-V or HLSL, but is required for OpenGL and GLSL, and so the value has to be provided as additional metadata.
By default the value is 0, which disables injecting the
num_views
statement. Setting 1 is not useful since that is the default
num_views
regardless. Therefore
count
should be >= 2 to make an effect. When set to, for example, 2, the generated GLSL shader will contain a
layout(num_views = 2) in;
语句。
Setting a
count
of 2 or greater also injects some preprocessor statements:
QSHADER_VIEW_COUNT
被设为
count
, whereas the
GL_EXT_multiview
extension is enabled automatically. Therefore, setting the appropriate
count
can be relevant with other types of shaders as well, e.g. when sharing a uniform buffer between the vertex and fragment shader and both shaders have to be able to write something like
#if QSHADER_VIEW_COUNT >= 2
.
该函数在 Qt 6.7 引入。
Sets per-target compilation to enable . By default this is disabled, meaning that the Vulkan/GLSL source is compiled to SPIR-V once per variant. (so once by default, twice if it is a vertex shader and the Batchable variant as requested as well). The resulting SPIR-V is then translated to the various target languages (GLSL, HLSL, MSL).
In per-target compilation mode, there is a separate GLSL to SPIR-V compilation step for each target, meaning for each GLSL/HLSL/MSL version requested via
setGeneratedShaders
(). The input source is the same, but with target-specific preprocessor defines inserted. This is significantly more time consuming, but allows applications to provide a single shader and use
#ifdef
blocks to differentiate. When this mode is disabled, the only way to achieve the same is to provide multiple versions of the shader file, process each separately, ship {.qsb} files for each, and choose the right file based on run time logic.
The following macros will be automatically defined in this mode. Note that the macros are always tied to shading languages, not graphics APIs.
QSHADER_SPIRV
- defined when targeting SPIR-V (to be consumed, typically, by Vulkan).
QSHADER_SPIRV_VERSION
- the targeted SPIR-V version number, such as
100
.
QSHADER_GLSL
- defined when targeting GLSL or GLSL ES (to be consumed, typically, by OpenGL or OpenGL ES)
QSHADER_GLSL_VERSION
- the targeted GLSL or GLSL ES version number, such as
100
,
300
,或
330
.
QSHADER_GLSL_ES
- defined only when targeting GLSL ES
QSHADER_HLSL
- defined when targeting HLSL (to be consumed, typically, by Direct 3D)
QSHADER_HLSL_VERSION
- the targeted HLSL shader model version, such as
50
QSHADER_MSL
- defined when targeting the Metal Shading Language (to be consumed, typically, by Metal)
QSHADER_MSL_VERSION
- the targeted MSL version, such as
12
or
20
.
This allows writing shader code like the following.
#if QSHADER_HLSL || QSHADER_MSL vec2 uv = vec2(uv_coord.x, 1.0 - uv_coord.y); #else vec2 uv = uv_coord; #endif
注意: Version numbers follow the GLSL-inspired QShaderVersion syntax and thus are a single integer always.
注意: There is only one QShaderDescription per QShader , no matter how many individual targets there are. Therefore members of uniform blocks, vertex inputs, etc. must not be made conditional using the macros described above.
警告: Be aware of the differences between the concepts of graphics APIs and shading languages. QShaderBaker and the related tools work strictly with the concept of shading languages, ignoring how the results are consumed afterwards. Therefore, if the higher layers in the Qt graphics stack one day start using SPIR-V also for an API other than Vulkan, the assumption that QSHADER_SPIRV implies Vulkan will no longer hold.
Specifies a custom preamble that is processed before the normal shader code.
This is more than just prepending to the source string: the validity of the GLSL version directive, which is required to be placed before everything else, is not affected. Line numbers in the reported error messages also remain unchanged, ignoring the contents given in the preamble .
One use case for preambles is to transparently insert dynamically generated
#define
语句。
Sets the source device . This allows using any QIODevice instead of just files. stage specifies the shader stage, while the optional fileName contains a filename that is used in the error messages.
Sets the name of the shader source file to fileName . This is the file that will be read when calling bake (). The shader stage is deduced automatically from the file extension. When this is not desired or not possible, use the overload with the stage argument instead.
The supported file extensions are:
.vert
- vertex shader
.frag
- fragment (pixel) shader
.tesc
- tessellation control (hull) shader
.tese
- tessellation evaluation (domain) shader
.geom
- geometry shader
.comp
- compute shader
Sets the name of the shader source file to fileName . This is the file that will be read when calling bake (). The shader stage is specified by stage .
Sets the input shader sourceString . stage specified the shader stage, while the optional fileName contains a filename that is used in the error messages.
When generating MSL shader code for a tessellation control shader, the tessellation mode (triangles or quads) must be known upfront. In GLSL this is declared in the tessellation evaluation shader typically, but for Metal it must be known also when generating the compute shader from the tessellation control shader.
When not set, the default is triangles.
When generating MSL shader code for a tessellation evaluation shader, the output vertex count of the tessellation control shader must be known upfront. in GLSL this would be declared in the tessellation control shader typically, but for Metal it must be known also when generating the vertex shader from the teselation evaluation shader.
When not set, the default value is 3.