C ++函数调用后SSBO的内容无效

时间:2014-08-10 14:37:29

标签: c++ opengl gpgpu

我有一个名为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上工作。我不知道为什么。

1 个答案:

答案 0 :(得分:2)

错误是您的使用方式

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时它已经具有正确的数据(在这种情况下,你理论上需要设置Texture和SSBO位:更新SSBO之前的纹理屏障,以及使用之前的SSBO屏障)。

如果您可以使用小代码重现问题,那么它可能是驱动程序错误。 请记住在具有不同硬件的多台计算机上测试代码,因为由于缺少内存障碍,您仍然可能会得到意外的结果。