时间:2016-12-22 23:46:18

标签: multithreading opengl glsl compute-shader

我正在尝试为Forward + Shading创建一个全局链表,但是有一些

实施过程中的困难。

对于计算着色器中的每个组,它有一个共享变量:一个本地索引数组,并且此数组具有可变长度(容量是常量,但内容不是)。这是一个例子:

shared int array [1024]; // GLSL中的声明

shared int length; //它也是工作组中的共享变量。

组0:长度= 4,数组= 3,5,7,1,-1,-1,-1,-1 ....( - 1 =无效)

组1:长度= 2,数组= 1,6,-1,-1,-1 ....

组2:长度= 1,数组= 8,-1,-1,-1,-1 ....

现在我想将这些索引合并到一个全局索引数组中。即着色器存储缓冲区对象。订单基于组索引:

全局索引数组:3,5,7,1,1,6,8,-1,-1,-1 ......

困难在于,我不知道如何在不同的群体之间进行同步。由于OpenGL中的barrier()仅保证同一组中的同步。

我发现其他帖子中说OpenGL不支持不同组之间的同步。

OpenGL Compute shader sync different work groups

所以,我的问题是。无论如何要实现我的目标吗?

例如,我可以声明一些Shader存储缓冲区对象,例如已完成更新的最新组ID和全局索引数组的偏移量吗?

示例:

unit latestGroupIDUpdated = -1; // a SSBO
unit globalIdxOffset = 0; // a SSBO
in each group:
while( myGroupId - 1 != latestGroupIDUpdated )
{ //keep waiting  }

// my previous group has updated the global list
globalIdxOffset+= myArrayLength;
latestGroupIDUpdated = myGroupId;
//now start appending the local index array into global index array 

这种尝试会起作用吗?或者它会失败,为什么?

如果失败,建议采用何种方法?

1 个答案:

答案 0 :(得分:0)

看起来,看起来你在1D中组织了你的LOCAL GROUP:

layout(local_size_x = X​, local_size_y = 1, local_size_z = 1) in;

如果您致电glDispatch(n * X, 1, 1),您将有n个小组。 n组之间的处理也是并行执行的,因此您不会知道每个groupID的更新顺序。使用“latestGroupIDUpdated”无效。

这是我的方法,您应该使用内置变量

gl_GlobalInvocationID (gl_GlobalInvocationID.x in our case)
gl_GlobalInvocationID.x = gl_WorkGroupID.x * gl_WorkGroupSize.x + gl_LocalInvocationID.x; 

---//gl_WorkGroupID.x;  [0, n) - 'n' : num groups you dispatched

---//gl_WorkGroupSize.x; X - size (3 in your example)

---//gl_LocalInvocationID.x; [0, gl_WorkGroupSize.x) - or [0, X)

您可以使用gl_GlobalInvocationID.x索引“global'SSBO列表以存储”length“。类似的东西:

GlobalLengthList[gl_GlobalInvocationID.x] = length; 

所有这些只是为了在'length'SSBO列表中以组顺序存储动态值'global'。在C / C ++应用程序中调用length后,所有这些“glMemoryBarrier()”都会更新。

之后,您将不得不修改此数组,以便它存储“长度”数组的“前缀和”(包括)。此过程高度并行化。如果您正在尝试节省时间,可以在单独的计算着色器中执行此操作。 (如果你的长度数组很长,我建议你这样做。)您也可以在CPU上执行此操作。

在你拥有包含前缀和长度数组(让我们称之为PrefixSumLengthArray)之后,你需要再次调用glDispatch()来发送与总'长度'值一样多的着色器调用 - 你的{的最后一个值{1}}。然后,您将使用PrefixSumLengthArray索引到新的gl_GlobalInvocationID列表以存储阵列。类似的东西:

SSBO

这将在不同的群体之间进行同步!