GLSL Compute Shader Setting buffer with lookup table 导致没有数据写入,设置与其他数据相同的缓冲区有效

GLSL Compute Shader Setting buffer with lookup table results in no data written, setting the same buffer with other data works

我正在尝试在计算着色器中实现 this standard marching cubes algorithm 的略微修改版本。 我已经到了使用 triTable 将正确的顶点索引插入缓冲区并将 table 修改为一维 (const int triTable[4096]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3...})

的阶段

以下代码显示了我遇到的错误(这没有实现算法,但它充分说明了当前问题):

layout(binding=1) buffer Grid
{
    float GridData[]; //contains 512*512*512 data volume previously generated, unused in this test case
};
uniform uint marchableCount;
uniform uint pointCount;

layout(std430, binding = 4) buffer X    {uvec4 marchableList[];}; //format is x,y,z,cubeIndex

layout(std430, binding = 5) buffer v {vec4 vertices[];};
layout(std430,binding = 6) buffer n {vec4 normals[];};
layout(binding = 7) uniform atomic_uint triCount;
void main()
{
    uvec3 gid = marchableList[gl_GlobalInvocationID.x].xyz; //xyz of grid cell

    int E = int(edgeTable[marchableList[gl_GlobalInvocationID.x].w]);
    if (E != 0)
    {
        uint cubeIndex = marchableList[gl_GlobalInvocationID.x].w;

        uint index = atomicCounterIncrement(triCount);
        int tCount = 0;//unused in this test, used for iteration in actual algorithm
        int tGet = tCount+16*int(cubeIndex); //correction from converting 2d array to 1d array

        vertices[index] = vec4(tGet);
    }
}

此代码产生预期值:顶点缓冲区充满数据并且原子计数器递增

更改此行:

vertices[index] = vec4(tGet);

vertices[index] = vec4(triTable[tGet]);

vertices[index] = vec4(triTable[tGet]+1);

(证明 triTable 并非巧合地返回零) 结果看起来是着色器的完全失败:缓冲区被零填充并且原子计数器不增加。编译着色器时不会输出任何错误消息。 tGet 小于 4096.

以下测试用例也产生正确的输出:

vertices[index] = vec4(triTable[3]); //-1

vertices[index] = vec4(triTable[4095]); //also -1

显示 triTable 实际上已正确实现 是什么导致着色器在这些非常具体的情况下出现问题?

我更惊讶的是 const int triTable[4096] = {...}; 完全可以编译。如果实际需要,该数组的大小为 16KB。这对于着色器来说已经很多了,即使数组位于共享内存中。

最有可能发生的情况是,每当编译器检测到此数组的使用时,它无法将其优化为简单值(triTable[3] 将始终为 1,因此编译器不需要存储整个 table),编译失败或导致无法正常运行的着色器。

最好让这个table成为一个统一的缓冲区。 SSBO 也可能工作,但一些硬件通过专用内存而不是全局内存获取来实现统一块。