GLSL Compute Shader编译报错:SSBO中uint类型赋值失败排查
Vulkan Compute Shader SSBO编译错误排查
我正尝试在Vulkan应用中添加Compute Shader,当前Shader仅实现将输入SSBO复制到输出SSBO的功能,Shader源码如下:
#version 320 es layout(std140, binding = 0) uniform UniformBufferObjectTest { uint num_segments; } ubo; layout(std140, binding = 1) readonly buffer verticesSSBOIn { vec3 posIn; uint vert_typeIn; uvec4 mirrorsIn; vec3 other_posIn; }; layout(std140, binding = 2) buffer verticesSSBOOut { vec3 posOut; uint vert_typeOut; uvec4 mirrorsOut; vec3 other_posOut; }; layout (local_size_x = 256, local_size_y = 1, local_size_z = 1) in; void main() { uint index = gl_GlobalInvocationID.x; if (index < ubo.num_segments) { posOut[index] = posIn[index]; vert_typeOut[index] = vert_typeIn[index]; mirrorsOut[index] = mirrorsIn[index]; other_posOut[index] = other_posIn[index]; } }
使用glslc编译时出现如下错误:
$ make ~/opengl/vulkan/shaderc/build/glslc/glslc -fshader-stage=compute comp.glsl -o comp.spv comp.glsl:29: error: 'expression' : left of '[' is not of type array, matrix, or vector comp.glsl:29: error: 'expression' : left of '[' is not of type array, matrix, or vector comp.glsl:29: error: 'assign' : l-value required (can't modify a const) 3 errors generated. make: *** [Makefile:40: comp.spv] Error 1
注释vert_typeOut[index] = vert_typeIn[index]这一行后即可正常编译,请问GLSL是否不支持Shader Storage Buffer Object(SSBO)中的uint类型?
问题原因与解决方法
GLSL完全支持SSBO中的uint类型,错误根源是SSBO的声明方式错误。
你的SSBO块中同时声明了多个独立变量(posIn、vert_typeIn等),但在代码中却用数组下标[index]去访问这些变量——单个uint或vec3不是数组,自然不能用索引访问。
GLSL里只有当SSBO块中仅声明一个变量时,编译器才会自动将其视为该类型的数组(语法糖)。但你的块里有多个变量,此时整个块对应的是一个结构体,而非多个独立数组。正确的做法是先定义包含所有顶点数据的结构体,再声明结构体的数组:
#version 320 es layout(std140, binding = 0) uniform UniformBufferObjectTest { uint num_segments; } ubo; // 定义包含所有顶点字段的结构体 struct VertexData { vec3 pos; uint vert_type; uvec4 mirrors; vec3 other_pos; }; // 输入SSBO:VertexData类型的数组 layout(std140, binding = 1) readonly buffer verticesSSBOIn { VertexData dataIn[]; }; // 输出SSBO:VertexData类型的数组 layout(std140, binding = 2) buffer verticesSSBOOut { VertexData dataOut[]; }; layout (local_size_x = 256, local_size_y = 1, local_size_z = 1) in; void main() { uint index = gl_GlobalInvocationID.x; if (index < ubo.num_segments) { dataOut[index].pos = dataIn[index].pos; dataOut[index].vert_type = dataIn[index].vert_type; dataOut[index].mirrors = dataIn[index].mirrors; dataOut[index].other_pos = dataIn[index].other_pos; } }
之前注释掉uint相关行能编译是巧合:编译器对向量类型的错误写法兼容性稍高,但本质整个访问逻辑都是错误的,只有改用结构体数组才能彻底解决问题。
内容的提问来源于stack exchange,提问作者user256552
相关产品推荐
相关产品推荐

