Push Constants

对于一些经常变化的小数据,比如说变换矩阵、光源位置等,可以通过流水线中的 push constants 直接传入 shader,其直接从 data path 传入,从而可以避免分配缓存等更重的操作,节省性能开销。

需要注意,一个 shader 只能分配一个 push constants 块,并且这个块的大小极度受限(maxPushConstantsSize)。Vulkan 规定大小至少为 128 Bytes,在笔者的机器上为 256 Bytes。

由于 Push constants 是流水线的一部分,所以首先在设置 pipeline layout 阶段(包含 descriptor set layout 和 push constants)就要让流水线知道有 push constants 的存在。使用 VkPushConstantRange 声明设置 push constants 的用途和大小。最后在使用 pipelineLayoutCreateInfo 提交 Pipeline Layout 的时候将上述结构体传入即可。注意此时只是在勾勒流水线的布局,并没有真正传入数据。之后,在 command buffer 中使用 vkCmdPushConstants 命令来提交真正的 push constants 数据,即可完成传递。

在 shader 中,通过 layout(push_constant) 替代 binding 来接收 push constant:

layout(push_constant) uniform KernelType {
    layout(offset = 0) int size;
    layout(offset = 4) float value[];
} kernel;

Specialization Constants

Specialization Constants 为 GLSL 中的一个常量,在创建流水线时指定其值。对于每一个你想要改变该常量的流水线,需要首先对于每一个常量填写一个 VkSpecializationMapEntry 结构体,里面包含这个常量的值 constant_id,以及 size 和 offset ,这里需要这两个元素的原因是如果有多个常量需要提交,我们需要把所有常量打包成一个 struct 再提交,所以需要指定这个常量在 struct 中的偏移量和该类型的大小(sizeof)。之后使用 VkSpecializationInfo 传入上述声明的 struct。之后在每次声明流水线的时候改变那个 struct 中对应的值即可,注意,在流水线指定这个值之后,这个值不会再在流水线生命周期内更改。

在shader中,内置变量 gl_WorkGroupSize可以使用特殊布局local_size_{xyz}_id,参考,如下:

layout(local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;

References

[1] https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html [2] https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples-(Legacy-synchronization-APIs) [3] https://github.com/google/shaderc [4] http://vulkan.gpuinfo.org/ [5] https://github.com/tgjones/shader-playground [6] https://vulkan.lunarg.com/sdk/home [7] https://www.khronos.org/registry/OpenCL/ [8] https://www.khronos.org/opencl/ [9] https://www.khronos.org/opencl/resources/opencl-applications-using-opencl [10] https://github.com/codeplaysoftware