QShaderBaker Class
Compiles a GLSL/Vulkan shader into SPIR-V, translates into other shading languages, and gathers reflection metadata. More...
Header: | #include <QShaderBaker> |
qmake: | QT += shadertools |
Public Types
typedef | GeneratedShader |
Public Functions
QShaderBaker() | |
~QShaderBaker() | |
int | bake() |
QString | errorMessage() const |
void | setGeneratedShaderVariants(const int &v) |
void | setGeneratedShaders(const QVector<QShaderBaker::GeneratedShader> &v) |
void | setSourceDevice(QIODevice *device, int stage, const QString &fileName = QString()) |
void | setSourceFileName(const QString &fileName) |
void | setSourceFileName(const QString &fileName, int stage) |
void | setSourceString(const QByteArray &sourceString, int stage, const QString &fileName = QString()) |
Detailed Description
Compiles a GLSL/Vulkan shader into SPIR-V, translates into other shading languages, and gathers reflection metadata.
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 QRhiShader instance, which also provides simple and fast serialization and deserialization.
Note: 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. This tool uses QShaderBaker itself and writes the serialized version of the generated QRhiShader 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 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 QRhiShader by calling QRhiShader::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.
Typical Workflow
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; } ubuf; out gl_PerVertex { vec4 gl_Position; }; void main() { v_color = color; gl_Position = ubuf.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; } ubuf; void main() { fragColor = vec4(v_color * ubuf.opacity, ubuf.opacity); }
To get QRhiShader 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
tool:
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 QRhiShader::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 QRhiShader. 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
for more information.
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({ QRhiShaderKey::StandardShader }); QVector<QShaderBaker::GeneratedShader> targets; targets.append({ QRhiShaderKey::SpirvShader, QRhiShaderVersion(100) }); targets.append({ QRhiShaderKey::GlslShader, QRhiShaderVersion(100, QRhiShaderVersion::GlslEs) }); targets.append({ QRhiShaderKey::SpirvShader, QRhiShaderVersion(120) }); targets.append({ QRhiShaderKey::HlslShader, QRhiShaderVersion(50) }); targets.append({ QRhiShaderKey::MslShader, QRhiShaderVersion(12) }); baker.setGeneratedShaders(targets); QRhiShader shaders = baker.bake(); if (!shaders.isValid()) qWarning() << baker.errorMessage();
See also QRhiShader.
Member Type Documentation
typedef QShaderBaker::GeneratedShader
Synonym for QPair<QRhiShaderKey::ShaderSource, QRhiShaderVersion>.
Property Documentation
Member Function Documentation
QShaderBaker::QShaderBaker()
Constructs a new QShaderBaker.
QShaderBaker::~QShaderBaker()
Destructor.
int QShaderBaker::bake()
Runs the compilation and translation process.
Returns a QRhiShader instance. To check if the process was successful, call QRhiShader::isValid(). When that indicates false
, call 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.
Note: 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.
QString QShaderBaker::errorMessage() const
Returns the error message from the last bake() run, or an empty string if there was no error.
Note: 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 QRhiShader is invalid.
void QShaderBaker::setGeneratedShaderVariants(const int &v)
Specifies which shader variants are genetated. Each shader version can have multiple variants in the resulting QRhiShader.
In most cases v contains a single entry, QRhiShaderKey::StandardShader.
Note: when no variants are set, the resulting QRhiShader will be empty and thus invalid.
void QShaderBaker::setGeneratedShaders(const QVector<QShaderBaker::GeneratedShader> &v)
Specifies what kind of shaders to compile or translate to. Nothing is generated by default so calling this function before bake() is mandatory
Note: when this function is not called or v is empty or contains only invalid entries, the resulting QRhiShader 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({ QRhiShaderKey::SpirvShader, QRhiShaderVersion(100) });
void QShaderBaker::setSourceDevice(QIODevice *device, int stage, const QString &fileName = QString())
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.
void QShaderBaker::setSourceFileName(const QString &fileName)
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
void QShaderBaker::setSourceFileName(const QString &fileName, int stage)
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.
void QShaderBaker::setSourceString(const QByteArray &sourceString, int stage, const QString &fileName = QString())
Sets the input shader sourceString. stage specified the shader stage, while the optional fileName contains a filename that is used in the error messages.