Today I refactored the vsg::ShaderStage (wrapper of VkShaderStage) support for Specialization Constants to make them easier to setup. What are they? Have a look at the LunarG docs on them:
They are essentially a means of passing constant int/float scaler values to the shader setup so that the driver can optimize the shaders. Common usage of Specialization Constants is to use them to save arrays or pass in constant numerical value. Alas Vulkan/GLSL/SPIR-V doesn't yet support pass vec2/vec3/vec4/mat4 or struct, if you try you'll just errors :report -|
The only examples we currently have of Specialization Constants being used are in the vsgUnity project and vsgExamples/Desckrtop/vsgcompute example. The
computeStage->setSpecializationConstants({
{0, vsg::intValue::create(width)},
{1, vsg::intValue::create(height)},
{2, vsg::intValue::create(workgroupSize)}
});
The maps to GLSL shader:
layout(constant_id = 0) const int WIDTH = 1024;
layout(constant_id = 1) const int HEIGHT = 1024;
layout (local_size_x_id = 2, local_size_y_id = 2, local_size_z = 1 ) in; // pass in WORKGROUP_SIZE as specialization constant_id=2
Note the shader provides defaults in case the application doesn't provide the SpecializationConstants. In the above example we are using ints, but you can use vsg::intValue/vsg::uintValue, vsg::floatValue and vsg::doubleValue for int, uint, float and double respectively. You can also now mix and match the types, so pass int's for dimensions, and floats for scales/offsets etc.
The API for ShaderStage::setSpecializationConstants() takes a map<uint32_t, ref_ptr<vsg::Data>>, the example above uses an C++11 initialize list to set up this map and pass it to he ShaderStage. The first value/key of the map is the constant_id value used i the GLSL shader, while the value_type is a vsg::Data object, so the API allows you to pass in any Data type, but until Vulkan/GLSL/SPir-V becomes more flexible you'll need to stick to the vsg::Value<T> types.
The new API replaces two set methods and associated data structures that were more Vulkan centric, but as the this particular bit of the Vulkan API is a bit cryptic you also needed to know how it hung together, the new API is simpler and does all the Vulkan specific packing when required for you rather than have you work out value sizes and offsets and packing all the data together.
The downside of this change is existing .vsgb and .vsgt files that contain vsg::ShaderStage will have the old style data structures serialized in them, rather than the newly recreated SerializationConstants map that is now serialized. This change unfortunately means that when you update to VSG master you'll need to rebuild your .vsgb and .vsgt files.
For this pain though you get an API that is works in a way that is much more of clear mapping between the scene graph level settings and how you use it in GLSL, no longer do you have to worry about packing in intermediate data structures, you can just pass the values you want to use and associated them with appropriate constant_id. No need to shy away for using what would be otherwise an esoteric feature.