我有一个名为sparseMatrix
的SSBO和以下操作顺序:
void callerFunc()
{
func1();
func2();
}
/* Clear buffer data store and fill with compute shader */
void func1()
{
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, sparseMatrix);
GLfloat floatZero = 0.0f;
glClearBufferSubData(GL_SHADER_STORAGE_BUFFER, GL_R32F, **EDIT: 0**, sizeof(GLfloat)*size, GL_RED, GL_FLOAT, &floatZero);
/* use shader program, bind uniforms */
glDispatchCompute(numWorkGroups,1,1); // fills buffer by adding a few numbers
}
/* Download data store contents and print */
void func2()
{
glBindBuffer(GL_SHADER_STORAGE_BUFFER, sparseMatrix);
GLfloat* temp = new GLfloat[size];
glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLfloat)*size, temp);
/* print values to console */
}
func1()
和func2()
之间没有来电。
打印到控制台的值是垃圾(每个浮点数为-107374176.000000
)。我在两台机器上进行了测试,一台配备了GeForce GTX 570,另一台配备了GeForce GT 750M,结果完全相同,包括下面的改动。驱动程序版本为335.23。
我尝试对代码进行以下所有更改(每次更改):
func2()
的内容移至func1()
的末尾,则结果很好。func2()
的内容直接移至callerFunc()
,则结果不错。glGetBufferSubData()
末尾的SSBO上添加了额外的func1()
来电,则func2()
中的值查询结果正常。glFinish()
电话之后或glClearBuffer
结束时放置func1()
,func2()
中的值都是正确的。如果我将glFinish()
放在func2()
的开头,但它并没有改变任何内容。glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT)
放在任何地方都不会有任何帮助。有没有人对这种特殊行为有解释?
编辑:我使用计算机着色器替换了对glClearBufferSubData(...)
的调用,该计算机着色器使用常量值填充数据存储,现在行为符合预期。但我仍然不知道造成这个问题的原因。
编辑2:感谢您的回答,但实际上我正确使用了它。当我在这里发布代码时,我忘了输入偏移参数,抱歉:(我在另一个连续计算调度的长列表中再次遇到问题。我尝试了很多东西,最后它帮助放了一个GL_TEXTURE_FETCH_BARRIER_BIT内存屏障而不是GL_SHADER_STORAGE_BARRIER_BIT障碍,虽然计算着色器纯粹在SSBO上工作。我不知道为什么。
答案 0 :(得分:2)
错误是您的使用方式
glClearBufferSubData
功能
看看规格:
你基本上没有提供偏移,我猜你为什么没有得到任何编译器错误,因为你错过了一个参数
代码示例:
GLfloat zeroFloat = 0.0f;
glClearBufferSubData(GL_SHADER_STORAGE_BUFFER, //target
GL_R32F, //internal format
0, //you were missing this: offset
sizeof(GLfloat)*size, //size
GL_RED, //format
GL_FLOAT, //type
&zeroFloat); //data
编辑回答以反映评论中的要求:
GPU可能在管道的不同级别使用缓存,因此从管道的其他阶段立即看不到BufferObject中的更改。内存屏障强制指定目标的一致性,以便屏障之前的每个写操作都可以在屏障之后看到。如果您在屏障之后有任何写操作,那么您就遇到了麻烦。
write
Memory Barrier
read
你提到了一个很长的计算,然后(假设没有驱动程序错误)可能是SSBO的当前内容取决于纹理。因此纹理上的内存屏障可确保SSBO的内容具有纹理数据。然后看起来SSBO上的内存屏障不是必需的,因为当访问SSBO时它已经具有正确的数据(在这种情况下,你理论上需要设置Texture和SSBO位:更新SSBO之前的纹理屏障,以及使用之前的SSBO屏障)。
如果您可以使用小代码重现问题,那么它可能是驱动程序错误。 请记住在具有不同硬件的多台计算机上测试代码,因为由于缺少内存障碍,您仍然可能会得到意外的结果。