我正在尝试通过GeForce 8600 GT上的统一块(一切均根据GLSL“#version 330”)将整数数组传递给片段着色器。
在应用程序一侧,我有:
int MyArray[7102];
…
//filling, binding, etc
…
glBufferData(GL_UNIFORM_BUFFER, sizeof(MyArray), MyArray, GL_DYNAMIC_DRAW);
在我的片段着色器中,我按照以下方式声明了根据块:
layout (std140) uniform myblock
{
int myarray[7102];
};
问题在于,成功执行glCompileShader之后,glLinkProgram会返回一个错误,指出它无法绑定适当的存储资源。
其他事实:
1)GL_MAX_UNIFORM_BLOCK_SIZE返回值65536
2)如果我将元素数量减少到4096,则可以正常工作,并且无论我使用“int”还是“ivec4”作为数组类型都没有区别。高于4096的值都会给我同样的“存储错误”
3)如果我使用“共享”或“打包”,则一切都可疑
在参考了std140的GLSL 3.3规范之后,我假设根据以下内容对齐/填充存在问题:
“1)如果成员是消耗N个基本机器单位的标量,则基本对齐
是N。
...
4)如果成员是标量或向量的数组,则基本比对和数组
跨度设置为匹配单个数组元素的基本对齐方式
遵循规则(1),(2)和(3),并四舍五入到vec4的基本对齐方式。的
数组的末尾可能有填充;成员的基本偏移量
数组将四舍五入到基本比对的下一个倍数。”
我的问题:
1)“myblock”占用的空间是7102 * 4 = 28408字节的4倍,这是真的吗?即std140将myarray的每个成员扩展为vec4,实际内存使用量为7102 * 4 * 4 = 113632字节,这是问题的原因吗?
2)之所以选择“共享”或“打包”,是因为通过优化消除了这些差距?
3)也许是驱动程序错误?所有事实都指出“…并四舍五入为vec4的基本对齐方式”是原因,但是很难接受的是,像int数组这样简单的东西最终在内存限制方面的效率要低4倍。
4)如果不是bug,那么在std140的情况下应该如何组织和访问阵列?我可以使用“ivec4”来实现最佳数据分配,但是我不得不牺牲性能来做类似x = myarray [i / 4] [i%4]的操作,以引用每个ivec4的各个元素,而不是简单的x = myarray [i] ?还是我错过了什么,并且有明显的解决方案?
最佳答案
1)(...)舍入为vec4的基本对齐方式吗? (...)
是。
2)之所以选择“共享”或“打包”,是因为通过优化消除了这些差距?
是;只是这不是优化性能的明智选择。
3)也许是驱动程序错误?
编辑编号GPU在本质上可以与矢量化类型一起使用。包装类型需要添加更多指令以对向量进行解复用。自编写此答案以来,GPU架构发生了重大变化。如今制造的GPU都是单标量架构,其设计着重于强大的超标量矢量化。
4)如果不是bug,那么在std140的情况下应该如何组织和访问阵列?
不要对如此大的数据使用统一的缓冲区对象。将数据放入一维纹理中,并使用texelFetch
对其进行索引。