我想知道是否在同一wave /子组(扭曲)中,我们需要调用memoryBarrierShared
和barrier
来同步共享变量?我认为在NVIDIA中这不是必需的,但我不知道其他IHV。
编辑:投票
因为我在谈论wave /子组,所以我在谈论ARB_shader_ballot
扩展名。
假设我们有这样的代码(1):
shared uint s_data[128];
uint tid = gl_GlobalInvocationID.x;
// initialization of some s_data
memoryBarrierShared();
barrier();
if(tid < gl_SubGroupSizeARB) {
for(uint i = gl_SubGroupeSizeARB; i > 0; i>>=1)
s_data[tid] += s_data[tid + i];
}
根据我的说法,此代码不正确。根据规范,正确的是(2):
if(tid < gl_SubGroupSizeARB) {
for(uint i = gl_SubGroupeSizeARB; i > 0; i>>=1) {
s_data[tid] += s_data[tid + i];
memoryBarrierShared();
barrier();
}
}
但是,由于调用是在wave /子组中并行运行的,因此barrier
函数似乎没有用:这个函数应该正确,并且比第二个函数(3)更快:
if(tid < gl_SubGroupSizeARB) {
for(uint i = gl_SubGroupeSizeARB; i > 0; i>>=1) {
s_data[tid] += s_data[tid + i];
memoryBarrierShared();
}
}
但是,由于我们不需要barrier
函数,所以我想知道(1)是否正确,即使对我来说不太可能;如果不正确,(3)是否正确(那意味着我理解是正确的)
EDIT:将int更改为uint,然后将=
更改为+=
答案 0 :(得分:3)
OpenGL和Vulkan关于计算着色器共享的执行模型并没有真正认识到“波动”的概念。它具有工作组的概念,但这不是一回事。一个工作组可能比GPU“波形”大得多,对于小型工作组,多个工作组可能在同一GPU“波形”上执行。
因此,这些规范未声明其任何功能相对于“波动”的行为(着色器选票功能除外)。因此,如果您希望标准说明的同步将在所有符合要求的实现上都可以使用,则必须按标准规定调用这两个函数。
即使使用ARB_shader_ballot
,其行为也不会修改着色器的执行模型。它仅允许子组之间的交叉通信,并且只能通过其提供的显式机制进行 。
着色器调用的执行模型和内存模型是,它们彼此之间是无序的,除非您明确地将它们与障碍对齐。