需要使用计算着色器中的内存内置函数实现同步

时间:2014-01-09 10:33:37

标签: opengl glsl

我想知道内存函数在计算着色器中的工作原理。因此,正在尝试下面的代码。

使用NIVIDA OPENGL 4.3,GL 430。

计算着色器:

layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in;

layout(std140, binding=1) buffer Res{
 coherent int result;
};
void main()
{
 int a=0;
 result=1;
 a = atomicAdd(result, 1);
 //barrier();
 //memoryBarrier()
}

在程序中,启动工作组

 glGenBuffers(1, &bufferObj, nResult);
 glBindBuffer(GL_SHADER_STORAGE_BUFFER, bufferObj);
 glBufferData(GL_SHADER_STORAGE_BUFFER, 4, NULL, GL_DYNAMIC_READ);
 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, bufferObj);

 glDispatchCompute(17,1,1);
 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);

 buffer = (GLint*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4, GL_MAP_READ_BIT);
 printf("value =%d", *buffer);
 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);

但是对于每次执行我都会得到'result'缓冲变量的随机值。想要使用记忆功能,但仍然无法正常工作。
获得正确的结果,直到num_groups_x = 16。此外,直到num_groups_x = 16,它在着色器中也不需要任何记忆功能。

1 个答案:

答案 0 :(得分:1)

屏障功能将阻止着色器的调用超出某个点,直到所有调色板都到达它。它有效地影响调度以防止数据危害。否则,它们都将以GPU /驱动程序选择的任何偶然顺序执行。计算着色器实际上添加了一种新的屏障,用于仅同步同一工作组中着色器的调用,称为memoryBarrierShared。

顺便说一下,这是一个设置记忆障碍的愚蠢场所。字面上 没有 发生在障碍之后,所以我不明白你为什么要在那里添加同步点。通常,只有在需要确保着色器的所有其他调用都已完成load之类的操作之前,才会在着色器级别引入内存障碍,然后再使用store覆盖相同的资源。您以同步的名义引入了一个人工停顿。我指的是着色器中已注释的屏障。


现在,此代码中还有另一个问题,它根本与完全无关,可以解释您的问题。您正在从缓冲区对象(buffer = (GLint*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4, GL_MAP_READ_BIT);)返回指向映射内存的指针,在对该指针执行任何操作之前,您将取消映射内存。因此,buffer指向无效的内存,结果将是未定义的 - 您可能会崩溃您的程序或只是读取垃圾内存。

buffer仅在映射时有效。

此外,在代码摘录的开头,buffer是缓冲区对象的名称。在摘录的最后,它被用于存储指向内存的指针。 glGenBuffers (...)在C语言绑定中也只占用2个参数。您的编译器在方向盘处于睡眠状态,您将此代码粘贴错误,或者这是除C之外的某种语言。