索引到第二个数组元素总是 returns 零

Indexing into 2nd array element always returns zero

我有一个 UBO,看起来像这样:

#version 450
#extension GL_ARB_separate_shader_objects : enable

const uint InstanceCount = 64;

layout(std140, align = 16, binding = 0) uniform UBO
{
    vec4 array_indices[InstanceCount];
    mat4 proj;
    mat4 model;
    mat4 models[InstanceCount];
    uint selection[128];
} ubo;

并且每个顶点着色器实例从 uint selection[128] 访问一位,如下所示:

layout(location = 1) out uint is_selected;

void main() {
    uint id = gl_InstanceIndex;
    uint num_index = id / 32;
    uint bit_index = id % uint(32);
    uint n = ubo.selection[num_index];
    is_selected = n & (1u << bit_index);
...
}

问题是只要 id 大于 31(即当 num_index 为 1 或更大时),n 始终为零。但是 RenderDoc 显示 ubo.selection[128] 的前 2 个 uint 是 F0000380 和 0000000F(这意味着第二个 uint 不为零),所以我猜着色器在索引到数组,所以有什么想法为什么 n 是零,除非我索引到数组的第一个元素?

AMD Polaris10 显卡。

提供此 UBO 的 C++ 结构是:

static const u32 InstanceCount = 64;

struct UBO
{
    vkm::vec4 array_indices[InstanceCount];
    vkm::mat4 proj;
    vkm::mat4 model;
    vkm::mat4 models[InstanceCount];
    u32 selection[128];
};

vkm::mat4 是具有单个成员 float arr[16] 的 class。

std140 布局中,所有数组都有一个元素到元素的数组步幅,四舍五入到最接近的 sizeof(vec4),即 16 字节。因此,除非 u32 实际上是一个 16 字节的结构,否则 u32 selection[128]; 与您的定义不匹配。

你的 GLSL 需要做的是取一个比实际大小小 4 倍的 uvec4 数组,并像这样索引数组:

const int num_selection_elements = 128;
const int num_selection_words = num_selection_elements / 4
layout(std140, align = 16, binding = 0) uniform UBO
{
    ...
    uvec4 selection[num_selection_words];
} ubo;

void main() {
    uint id = gl_InstanceIndex;
    uint bit_index = id % 32;
    uint word_index = (id / 32) % 4;
    uint vec_index = id / (num_selection_words * 32 * 4);
    uint n = ubo.selection[vec_index][word_index];
    is_selected = n & (1u << bit_index);
...
}

经过更多测试后,这是对 uvec4 数组的最终正确索引:

uint index = gl_InstanceIndex;
const uint vec_index = index / 128; // 128 = 32 * 4 = vec size
index %= 128;
uint num_index = index / 32;
const uint bit_index = index % 32;
const uint n = ubo.selection[vec_index][num_index];
is_selected = n & (1u << bit_index);

也就是说,当索引超过第一个 uvec4num_index 在没有 index %= 128; 的情况下变得错误。