用于数组大小的特化常量

Specialization constant used for array size

我正在尝试使用 SPIR-V 专业化常量 来定义统一块中数组的大小。

#version 460 core

layout(constant_id = 0) const uint count = 0;

layout(binding = 0) uniform Uniform
{
    vec4 foo[count];
    uint bar[count];
};

void main() {}

在着色器中声明 count = 0,编译失败并显示:

array size must be a positive integer

使用 count = 1 和 5 的特化,代码编译但 linking 在运行时失败并抱怨别名:

error: different uniforms (named Uniform.foo[4] and Uniform.bar[3]) sharing the same offset within a uniform block (named Uniform) between shaders
error: different uniforms (named Uniform.foo[3] and Uniform.bar[2]) sharing the same offset within a uniform block (named Uniform) between shaders
error: different uniforms (named Uniform.foo[2] and Uniform.bar[1]) sharing the same offset within a uniform block (named Uniform) between shaders
error: different uniforms (named Uniform.foo[1] and Uniform.bar[0]) sharing the same offset within a uniform block (named Uniform) between shaders

统一块的布局(每个成员的偏移量)似乎在专门化期间不受影响,因此 foobar 重叠。

显式偏移也不起作用并导致相同的 link 错误:

layout(binding = 0, std140) uniform Uniform
{
    layout(offset = 0) vec4 foo[count];
    layout(offset = count) uint bar[count];
};

这是有意为之的行为吗?俯瞰? 可以使用特化常量来定义数组的大小吗?

这是 ARB_spir_v 的一个怪癖。来自 the extension specification:

Arrays inside a block may be sized with a specialization constant, but the block will have a static layout. Changing the specialized size will not re-layout the block. In the absence of explicit offsets, the layout will be based on the default size of the array.

由于默认大小为 0,因此块中的结构将按照数组大小为零的方式进行布局。

基本上,您可以使用专门化常量使数组比默认数组更短,但不能更长。即使您将它们缩短,它们仍然占用与默认值相同的 space。

所以,实际上,在块数组长度中使用专门化常量只是一种 shorthand 声明数组的方式,将默认值作为其长度,然后将 name.length() 替换为专业化 constant/expression。这纯粹是语法糖。