首页 > 解决方案 > 索引到第二个数组元素总是返回零

问题描述

我有一个看起来像这样的 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 显示前 2uintubo.selection[128]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] 的类。

标签: arraysindexingglslvulkan

解决方案


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

您的 GLSL 需要做的是采用uvec4比实际大小小 4 倍的数组,并像这样索引数组:

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);
...
}

推荐阅读