Qt Shader Tools Build System Integration
Introduction
The Qt Shader Tools module provides a CMake macro file that provides useful functions applications can take into use in their CMakeLists.txt
.
When using the qt6_add_shaders
function, the qsb tool will get invoked automatically by the build system, and the resulting .qsb
files get added to the resource system implicitly.
First Example
Let's look at a simple example. Assume that we have a Qt Quick application that wants to provides its own wobble effect via ShaderEffect. The fragment shader is implemented in wobble.frag
. The ShaderEffect item's fragmentShader property refers to wobble.frag.qsb
. How do we ensure this .qsb file gets generated at build time?
... 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" )
The above is sufficient to enable the application to access :/wobble.frag.qsb
at run time. The original Vulkan-style GLSL source code (wobble.frag) is not included in the application's executable and does not need to be shipped. If there are errors in the shader code, the glslang
compiler messages are printed at build time and the build fails. When changing the shader source file, the changes are picked up automatically in the next build, like they would for C++ and other source files.
The key is the qt6_add_shaders
function, which shares similarity with qt6_add_resources
. Without specifying further parameters, the function will lead to running qsb with a reasonable set of default arguments that are suitable for fragment shaders when targeting Vulkan, Metal, Direct 3D, and OpenGL or OpenGL ES.
Note: Watch out for the find_package
line. It is important to include the find_package
for ShaderTools
, otherwise qt6_add_shaders
will not be available.
Note: Multiple qt6_add_shaders
calls are supported. In complex applications it is not unlikely that different sets of shaders need different settings. The name after the project ("exampleapp_shaders"
in the above example) has to be unique for each call.
Configuration
By default qt6_add_shaders
invokes qsb as follows:
qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -o <output>.qsb <input>
This means that the resulting package will contain SPIR-V (for Vulkan 1.0), GLSL ES 100 (for OpenGL ES 2.0 and newer), GLSL 120 (for non-core profile OpenGL contexts), GLSL 150 (for core profile OpenGL contexts), HLSL source for Shader Model 5.0 (for Direct3D 11.1), and Metal Shading Language 1.2 source (for Metal).
This is a good set of defaults for Qt Quick, and creates applications that are highly portable to a wide variety of systems. These defaults are not always suitable however. If the shader uses functions or constructs that do not have an equivalent in these targets, the process, and so the build, will fail. If that is the case, the targets will need to be adjusted, and this also means that the application's minimum system requirements get adjusted implicitly. As an example, take the textureLod
GLSL function that is only available with OpenGL ES 3.0 and up (meaning GLSL ES 300 or higher). When requesting GLSL 300 es
instead of 100 es
, the build will succeed, but the resulting application will now require OpenGL ES 3.0 or higher and will not be compatible with OpenGL ES 2.0 based systems.
Shader type
The type of shader is deduced from the file extension. Thus, the extension must be one of the following:
.vert
- for vertex shaders.frag
- for fragment (pixel) shaders.comp
- for compute shaders
Targets
The following keywords are available:
GLSL
- Requests generating source code for the given list of GLSL versions. Watch out that the list follows the comma-separatedqsb
syntax. For example, a compute shader will want to specify"310 es,430"
here as the defaults are not suitable for it.NOGLSL
- This argument-less keyword disables generating GLSL source. Suitable for applications that do not wish to function with OpenGL at all.HLSL
- Requests generating source code for the given list of HLSL (shader model) versions. Theqsb
tool follows GLSL-style version numbers and therefore50
corresponds to Shader Model 5.0,51
is 5.1.NOHLSL
- This argument-less keyword disables generating HLSL source. Suitable for applications that do not wish to function with Direct 3D at all.MSL
- Requests generating source code for the given version of the Metal Shading Language.12
corresponds to 1.2,20
to 2.0.NOMSL
- This argument-less keyword disables generating MSL source. Suitable for applications that do not wish to function with Metal at all.
The most commonly overridden setting is GLSL
. For example, if the application's shaders use OpenGL 3.x features, it will likely want to specify something higher than 100 es
or 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 )
Note: The space before the es
suffix is optional.
Qt Quick specifics
BATCHABLE
- Specifying this single, argument-less keyword is essential for vertex shaders that are used with Qt Quick, either in a ShaderEffect or in a QSGMaterialShader. It has no effect for fragment or compute shaders, and different types can safely be included in the same list since the keyword is taken into account only for the.vert
files. Equivalent to the-b
argument of qsb.
Invoking external tools
PRECOMPILE
- Equivalent to the-c
or-t
options of qsb, depending on the platform. When building on Windows, this leads to invokingfxc
from the Windows SDK to do the first phase of compilation (HLSL source to DXBC bytecode) at build time instead of at run time. On macOS it uses invokves the Metal tools to generate a Metal library. In either case the resulting.qsb
file will only include the compilation results, not the HLSL or MSL source.OPTIMIZED
- Invokesspirv-opt
(which must be available from the Vulkan SDK or elsewhere) to perform optimizations on the SPIR-V bytecode. Equivalent to the-O
argument of qsb.
Other settings
DEFINES
- Defines macros that are active during shader compilation. Equivalent to the-D
argument of qsb. The list has the form of"name1=value1;name2=value2"
. Alternatively, just likeFILES
, the list can be separated by newlines.OUTPUTS
- When the name of the generated .qsb file needs to be different from the source, for example because one shader file serves as the source for multiple .qsb files due to differentiating viaDEFINES
, this list can contain an entry for each item inFILES
, specifying a file name typically ending in.qsb
. The specified name is then passed in the-o
argument to qsb instead of just appending.qsb
to the source file name.DEBUGINFO
- Enables generating full debug information for SPIR-V, thus enabling tools like RenderDoc to display the full source when inspecting a pipeline or when performing vertex or fragment debugging. Equivalent to the-g
argument of qsb. Also has an effect for Direct 3D in case thePRECOMPILE
keyword has been specified, asfxc
is then instructed to include debug information in the generated intermediate bytecode.QUIET
- Suppresses debug and warning output from qsb. Only fatal errors are printed.