索引到第二个数组元素总是 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);
也就是说,当索引超过第一个 uvec4
时 num_index
在没有 index %= 128;
的情况下变得错误。
我有一个 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);
也就是说,当索引超过第一个 uvec4
时 num_index
在没有 index %= 128;
的情况下变得错误。