GLSL 计算着色器 使用查找表设置缓冲区会导致不写入任何数据,与其他数据设置相同的缓冲区有效

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

本文关键字:设置 数据 缓冲区 任何 有效 其他 计算 GLSL 查找      更新时间:2023-10-16

我正在尝试在计算着色器中实现此标准行进立方体算法的略微修改版本。 我已经到了使用triTable将正确的顶点索引插入缓冲区的阶段,并将表格修改为 1 维 (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,因此编译器不需要存储整个表),编译要么失败,要么导致非功能性着色器。

最好使此表成为统一的缓冲区。SSBO 也可能有效,但某些硬件通过专用内存而不是全局内存提取来实现统一块。