Flutter Engine
The Flutter Engine
|
A specialization constant is a named variable that is known to be constant at runtime but not when the shader is authored. These variables are bound to specific values when the shader is compiled on application start up and allow the backend to perform optimizations such as branch elimination and constant folding.
Specialization constants have two possible benefits when used in a shader:
These goals are related: The number of shaders can be reduce by adding runtime branching to create more generic shaders. Alternatively, branching can be reduced by adding more specialized shader variants. Specialization constants provide a happy medium where the source files can be combined with branching but done so in a way that has no runtime cost.
Consider the case of the "decal" texture sampling mode. This is implement via clamp-to-border with a border color set to transparent black. While this functionality is well supported on the Metal and Vulkan backends, the GLES backend needs to support devices that do not have this extension. As a result, the following code was used to conditionally decal:
This works great as long as we know that the GLES backend can never do the decal sample mode. This is also "free" as the ifdef branch is evaluated in the compiler. But eventually, we added a runtime check for decal mode as we need to support this on GLES. So the code turned into (approximately) the following:
Now we've got decal support, but we've also got new problems:
Instead of using a runtime check, we can create a specialization constant that is set when compiling the shader. This constant will be 1
if decal is supported and 0
otherwise.
Immediately we realize a number of benefits:
Const values are floats and can be used to represent:
AVOID adding specialization constants for color values or anything more complex.
Specialization constants are provided to the CreateDefault argument in content_context.cc and aren't a part of variants. This is intentional: specialization constants shouldn't be used to create (potentially unlimited) runtime variants of a shader.
Backend specific information:
#ifdef SPIRV_CROSS_CONSTANT_i
, where i is the index of constant. The Impeller runtime will insert #define SPIRV_CROSS_CONSTANT_i
in the header of the shader.