SSBO的内容在c++函数调用后失效
Contents of SSBO become invalid after C++ function call
我有一个名为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()
,值就会变好。 - 如果我在
func1()
的末尾在SSBO上添加一个额外的glGetBufferSubData()
调用,func2()
中的值查询结果很好。 - 如果我在
glClearBuffer
呼叫之后或func1()
结束时放置glFinish()
,则func2()
中的值是正确的。如果我把glFinish()
放在func2()
的开头,它不会改变任何东西。 - 把
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT)
放在任何地方也没有用。
有人能解释这种奇怪的行为吗?
EDIT:我用计算机着色器替换了对glClearBufferSubData(...)
的调用,该着色器用恒定值填充数据存储,现在行为如预期的那样。但是我仍然不知道是什么引起了这个问题。
编辑2:谢谢你的回答,但实际上我用对了。当我在这里发布代码时,我忘记了输入offset参数,对不起:(我在另一个连续计算调度的长列表中再次遇到了这个问题。我尝试了很多东西,最终它帮助放置了GL_TEXTURE_FETCH_BARRIER_BIT内存屏障,而不是GL_SHADER_STORAGE_BARRIER_BIT屏障,尽管计算着色器纯粹在ssbo上工作。我不知道为什么。
错误在于您如何使用
glClearBufferSubData
函数。
看说明书:
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被访问时,它已经有了正确的数据(在这种情况下,理论上你需要设置纹理和SSBO位:在更新SSBO之前设置纹理屏障,在使用SSBO之前设置SSBO屏障)。
如果你可以用小代码重现这个问题,那么它可能是一个驱动程序错误。记住在不同硬件的多台机器上测试代码,因为您仍然可能由于缺少内存屏障而得到意想不到的结果。
- 函数调用中参数的顺序重要吗
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 变量没有改变?通过向量的函数调用
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- 模板函数调用
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 析构函数调用
- 成员函数调用和C++对象模型
- 使用共享指针的函数调用,其对象应为 const
- C++:编译时检查匹配的函数调用对?
- 函数调用C++中的参数太少
- 来自 DLL 的函数调用 [表观调用的括号前面的表达式必须具有(指向-)函数类型]
- 返回指向对象的指针的函数调用是否为 prvalue?
- C++ 如何重载 [] 运算符并进行函数调用
- 代码的效率. 转到和函数调用
- 是同一作用域的函数部分中的函数调用
- 如何封装一个函数,以便它只能由同一类中的一个其他函数调用?
- SSBO的内容在c++函数调用后失效