Multithreading 组之间的OpenGL计算着色器同步

Multithreading 组之间的OpenGL计算着色器同步,multithreading,opengl,glsl,compute-shader,Multithreading,Opengl,Glsl,Compute Shader,我正在尝试为正向+着色创建一个全局链接列表,但是有一些 实施过程中的困难 对于计算着色器中的每个组,它都有一个共享变量:一个局部索引数组,该数组具有可变长度(容量是常量,但内容不是)。下面是一个例子: 共享整数数组[1024];//GLSL中的声明 共享整数长度;//它也是工作组中的一个共享变量 第0组:长度=4,数组=3,5,7,1,-1,-1,-1。。。。(-1=无效) 第1组:长度=2,数组=1,6,-1,-1 第2组:长度=1,数组=8,-1,-1,-1 现在我想把这些索引合并成一个全局

我正在尝试为正向+着色创建一个全局链接列表,但是有一些

实施过程中的困难

对于计算着色器中的每个组,它都有一个共享变量:一个局部索引数组,该数组具有可变长度(容量是常量,但内容不是)。下面是一个例子:

共享整数数组[1024];//GLSL中的声明

共享整数长度;//它也是工作组中的一个共享变量

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

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

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

现在我想把这些索引合并成一个全局索引数组。i、 e.着色器存储缓冲区对象。顺序基于组索引:

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

困难在于,我不知道如何在不同的组之间同步。因为OpenGL中的barrier()只保证同一组中的同步

我发现另一篇文章说OpenGL不支持不同组之间的同步

所以,我的问题是。有没有办法实现我的目标

例如,我可以声明一些着色器存储缓冲区对象,例如已完成更新的最新组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 
这种尝试有效吗?还是会失败?为什么


如果失败,建议采取什么样的方法?

从外观上看,您似乎在1D中组织了您的本地团队:

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\u globalinovationid.x
索引到您的“
global
”SSBO列表中,以存储“
length
”。比如:

GlobalLengthList[gl_GlobalInvocationID.x] = length; 
 int i = 0; // index to PrefixSumLengthArray array get the 'length' upto and including.

 int j = 0; // index [0, length) to get the localArray

 if (gl_GlobalInvocationID.x < PrefixSumLength[i]) {
       GlobalArrayList[gl_GlobalInvocationID.x] = localArray[j]; 
       j++; 
 } else {
       j = 0; 
       i++; 
 }
所有这些只是为了将动态值“
length
”按组顺序存储在“
global
”SSBO列表中。在C/C++应用程序中调用
glMemoryBarrier()
后,所有这些“
length
”都将更新

在此之后,您必须修改此数组,使其存储“长度”数组的“前缀和”(包括)。这个过程是高度并行的。如果要节省时间,可以在单独的计算着色器中执行此操作。(如果长度数组很长,我建议您查找此项)。您也可以在CPU上执行此操作

拥有包含前缀和长度数组(我们称之为PrefixSumLengthArray)后,需要再次调用
glDispatch()
,以调度与总“length”值(即
PrefixSumLengthArray
中的最后一个值)一样多的着色器调用。然后,您将使用
gl\u globalinchibitid
索引到新的
SSBO
列表中以存储阵列。比如:

GlobalLengthList[gl_GlobalInvocationID.x] = length; 
 int i = 0; // index to PrefixSumLengthArray array get the 'length' upto and including.

 int j = 0; // index [0, length) to get the localArray

 if (gl_GlobalInvocationID.x < PrefixSumLength[i]) {
       GlobalArrayList[gl_GlobalInvocationID.x] = localArray[j]; 
       j++; 
 } else {
       j = 0; 
       i++; 
 }
int i=0;//PrefixSumLengthArray数组的索引获取最长的“长度”,包括。
int j=0;//索引[0,长度)以获取localArray
if(gl_globalinovationid.x

这将在不同的组之间同步!!!

当你说“组”时,你的意思是“工作组”,对吗?如果是,工作组不能有不同的“长度”。如果是“长度”,您指的是每个组的调用数。是的,组表示工作组,不同的长度?是的,组表示工作组。但是,长度不是调用。我的意思是每个工作组都有自己的共享变量:idxarray[1024],因此容量是常量,但有效长度不是。GLSL中的正式声明是:shared int indexarray[1024];它还将删除所有不必要的'-1'值。