Opengl 关于相干限定符
我不清楚Opengl 关于相干限定符,opengl,synchronization,glsl,atomic,Opengl,Synchronization,Glsl,Atomic,我不清楚一致性限定符和原子操作是如何协同工作的 我使用此代码在同一SSBO位置上执行一些累加操作: uint prevValue, newValue; uint readValue = ssbo[index]; do { prevValue = readValue; newValue = F(readValue); } while((readValue = atomicCompSwap(ssbo[index], prevValue, newValue)) != prevValue
一致性限定符和原子操作是如何协同工作的
我使用此代码在同一SSBO位置上执行一些累加操作:
uint prevValue, newValue;
uint readValue = ssbo[index];
do
{
prevValue = readValue;
newValue = F(readValue);
}
while((readValue = atomicCompSwap(ssbo[index], prevValue, newValue)) != prevValue);
这段代码对我来说很好,但在这种情况下,我是否需要用一致的限定符声明SSBO(或图像)
如果只调用atomicAdd
,是否需要使用连贯的
我到底什么时候需要使用一致的限定符?我是否只需要在直接写入的情况下使用它:ssbo[index]=value代码>?TL;博士
我发现有证据支持这两个关于连贯性的答案
当前分数:
- 需要原子的一致性:1.5
- 省略原子的一致性:5.75
底线,尽管有分数,仍然不确定。在一个工作组中,我确信实践中不需要连贯一致的。在这些情况下,我不太确定:
glDispatchCompute中有1个以上的工作组
多个glDispatchCompute
调用,所有调用都访问相同的内存位置(原子地),它们之间没有任何glMemoryBarrier
然而,当您仅通过原子操作访问SSBO(或单个结构成员)时,声明SSBO(或单个结构成员)一致性
是否会有性能成本?根据下面的内容,我不认为会有性能成本,因为一致性
增加了“可见性”变量读或写操作的指令或指令标志。如果仅通过原子操作访问变量,编译器应该:
生成原子指令时忽略连贯的,因为它没有效果
使用适当的机制确保原子操作的结果在着色器调用、扭曲、工作组或渲染命令之外可见
从:
请注意,原子计数器在功能上与原子映像/缓冲区变量操作不同。后者仍然需要连贯的限定词、障碍等。(于2020年4月12日移除)
然而,如果内存以非相干的方式被修改,那么从该内存进行的任何后续读取都不能自动保证看到这些更改
+1用于要求连贯的
源代码
第二个着色器用于比较原子操作和非原子操作之间的相干
限定符的效果
AMD
AMD出版了一本和GPU结合在一起的书,让我们深入了解GPU是如何实现这一点的
着色器v1(Vega gfx900)
(不知道为什么这里使用exec掩码和分支…)
我们可以看到,两种原子操作(在相干和非相干缓冲区上)在Radeon GPU分析器的所有受支持架构上产生相同的指令:
buffer_atomic_add v0, v0, s[8:11], 0 E1080000 80020000
对该指令进行解码表明GLC
(全局相干)标志设置为0
,这意味着对于原子操作:“不返回以前的数据值。波前没有L1持久性”。修改着色器以使用返回的值将GLC
标记的both原子指令更改为1
,这意味着:“返回以前的数据值。波前没有L1持久性”
2013年的文件(海岛等)对BUFFER\u ATOMIC\u
说明进行了有趣的描述:
缓冲区对象原子操作。始终保持全球一致性
因此,在AMD硬件上,似乎一致性对原子操作没有影响
着色器v2(织女星gfx900)
相干
缓冲区上的buffer\u load\u dword
操作使用了glc
标志,而另一个不符合预期
在AMD上:+1用于省略连贯的
英伟达
可以通过检查glGetProgramBinary()
返回的blob来获取着色器的程序集。说明如和中所述
着色器v1
是否存在一致性
没有区别
着色器v2
相干
缓冲区上的LDB.U32
操作使用COH
修饰符,这意味着“使加载和存储操作使用相干缓存”
在NVIDIA上:+1表示省略连贯性
SPIR-V(带Vulkan目标)
让我们看看SPIR-V生成器生成了什么SPIR-V代码
着色器v1
buf
和buf_相干
之间的唯一区别是后者的装饰为memberdecoration 21(buf_相干)0相干
。它们以后的用法是相同的
将#pragma use_vulkan_memory_model
添加到着色器可启用并产生以下(缩写)更改:
也就是说。。。我不太清楚,因为我不精通Vulkan的复杂性。我确实发现了这个:
虽然GLSL(和传统SPIR-V)对变量应用了“一致”修饰(出于历史原因),但该模型将每个内存访问指令视为具有可选的隐式可用性/可见性操作。GLSL到SPIR-V编译器应该映射一致变量上的所有(非原子)操作,以使此模型中的{Pointer,Texel}{Available}{Visible}标志可用
原子操作隐式地具有可用性/可见性操作,这些操作的范围取自原子操作的范围
着色器v2
(跳过完整输出)
buf
和buf_相干
之间的唯一区别还是18(buf_相干)0相干
将#pragma use_vulkan_memory_model
添加到着色器可启用并产生以下(缩写)更改:
注意添加了MakePointerAvailableKHR
和MakePointerAvailableKHR#version 460
layout(local_size_x = 512) in;
// Non-coherent qualified SSBO
layout(binding=0) restrict buffer Buf { uint count; } buf;
// Coherent qualified SSBO
layout(binding=1) coherent restrict buffer Buf_coherent { uint count; } buf_coherent;
void main()
{
// First shader with atomics (v1)
uint read_value1 = atomicAdd(buf.count, 2);
uint read_value2 = atomicAdd(buf_coherent.count, 4);
// Second shader with non-atomic add (v2)
buf.count += 2;
buf_coherent.count += 4;
}
s_getpc_b64 s[0:1] BE801C80
s_mov_b32 s0, s2 BE800002
s_mov_b64 s[2:3], exec BE82017E
s_ff1_i32_b64 s4, exec BE84117E
s_lshl_b64 s[4:5], 1, s4 8E840481
s_and_b64 s[4:5], s[4:5], exec 86847E04
s_and_saveexec_b64 s[4:5], s[4:5] BE842004
s_cbranch_execz label_0010 BF880008
s_load_dwordx4 s[8:11], s[0:1], 0x00 C00A0200 00000000
s_bcnt1_i32_b64 s2, s[2:3] BE820D02
s_mulk_i32 s2, 0x0002 B7820002
v_mov_b32 v0, s2 7E000202
s_waitcnt lgkmcnt(0) BF8CC07F
buffer_atomic_add v0, v0, s[8:11], 0 E1080000 80020000
label_0010:
s_mov_b64 exec, s[4:5] BEFE0104
s_mov_b64 s[2:3], exec BE82017E
s_ff1_i32_b64 s4, exec BE84117E
s_lshl_b64 s[4:5], 1, s4 8E840481
s_and_b64 s[4:5], s[4:5], exec 86847E04
s_and_saveexec_b64 s[4:5], s[4:5] BE842004
s_cbranch_execz label_001F BF880008
s_load_dwordx4 s[8:11], s[0:1], 0x20 C00A0200 00000020
s_bcnt1_i32_b64 s0, s[2:3] BE800D02
s_mulk_i32 s0, 0x0004 B7800004
v_mov_b32 v0, s0 7E000200
s_waitcnt lgkmcnt(0) BF8CC07F
buffer_atomic_add v0, v0, s[8:11], 0 E1080000 80020000
label_001F:
s_endpgm BF810000
buffer_atomic_add v0, v0, s[8:11], 0 E1080000 80020000
s_getpc_b64 s[0:1] BE801C80
s_mov_b32 s0, s2 BE800002
s_load_dwordx4 s[4:7], s[0:1], 0x00 C00A0100 00000000
s_waitcnt lgkmcnt(0) BF8CC07F
buffer_load_dword v0, v0, s[4:7], 0 E0500000 80010000
s_load_dwordx4 s[0:3], s[0:1], 0x20 C00A0000 00000020
s_waitcnt vmcnt(0) BF8C0F70
v_add_u32 v0, 2, v0 68000082
buffer_store_dword v0, v0, s[4:7], 0 glc E0704000 80010000
s_waitcnt lgkmcnt(0) BF8CC07F
buffer_load_dword v0, v0, s[0:3], 0 glc E0504000 80000000
s_waitcnt vmcnt(0) BF8C0F70
v_add_u32 v0, 4, v0 68000084
buffer_store_dword v0, v0, s[0:3], 0 glc E0704000 80000000
s_endpgm BF810000
!!NVcp5.0
OPTION NV_internal;
OPTION NV_shader_storage_buffer;
OPTION NV_bindless_texture;
GROUP_SIZE 512;
STORAGE sbo_buf0[] = { program.storage[0] };
STORAGE sbo_buf1[] = { program.storage[1] };
STORAGE sbo_buf2[] = { program.storage[2] };
TEMP R0;
TEMP T;
ATOMB.ADD.U32 R0.x, {2, 0, 0, 0}, sbo_buf0[0];
ATOMB.ADD.U32 R0.x, {4, 0, 0, 0}, sbo_buf1[0];
END
!!NVcp5.0
OPTION NV_internal;
OPTION NV_shader_storage_buffer;
OPTION NV_bindless_texture;
GROUP_SIZE 512;
STORAGE sbo_buf0[] = { program.storage[0] };
STORAGE sbo_buf1[] = { program.storage[1] };
STORAGE sbo_buf2[] = { program.storage[2] };
TEMP R0;
TEMP T;
LDB.U32 R0.x, sbo_buf0[0];
ADD.U R0.x, R0, {2, 0, 0, 0};
STB.U32 R0, sbo_buf0[0];
LDB.U32.COH R0.x, sbo_buf1[0];
ADD.U R0.x, R0, {4, 0, 0, 0};
STB.U32 R0, sbo_buf1[0];
END
// Generated with glslangValidator.exe -H --target-env vulkan1.1
// Module Version 10300
// Generated by (magic number): 80008
// Id's are bound by 30
Capability Shader
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint GLCompute 4 "main"
ExecutionMode 4 LocalSize 512 1 1
Source GLSL 460
Name 4 "main"
Name 8 "read_value1"
Name 9 "Buf"
MemberName 9(Buf) 0 "count"
Name 11 "buf"
Name 20 "read_value2"
Name 21 "Buf_coherent"
MemberName 21(Buf_coherent) 0 "count"
Name 23 "buf_coherent"
MemberDecorate 9(Buf) 0 Restrict
MemberDecorate 9(Buf) 0 Offset 0
Decorate 9(Buf) Block
Decorate 11(buf) DescriptorSet 0
Decorate 11(buf) Binding 0
MemberDecorate 21(Buf_coherent) 0 Coherent
MemberDecorate 21(Buf_coherent) 0 Restrict
MemberDecorate 21(Buf_coherent) 0 Offset 0
Decorate 21(Buf_coherent) Block
Decorate 23(buf_coherent) DescriptorSet 0
Decorate 23(buf_coherent) Binding 1
Decorate 29 BuiltIn WorkgroupSize
2: TypeVoid
3: TypeFunction 2
6: TypeInt 32 0
7: TypePointer Function 6(int)
9(Buf): TypeStruct 6(int)
10: TypePointer StorageBuffer 9(Buf)
11(buf): 10(ptr) Variable StorageBuffer
12: TypeInt 32 1
13: 12(int) Constant 0
14: TypePointer StorageBuffer 6(int)
16: 6(int) Constant 2
17: 6(int) Constant 1
18: 6(int) Constant 0
21(Buf_coherent): TypeStruct 6(int)
22: TypePointer StorageBuffer 21(Buf_coherent)
23(buf_coherent): 22(ptr) Variable StorageBuffer
25: 6(int) Constant 4
27: TypeVector 6(int) 3
28: 6(int) Constant 512
29: 27(ivec3) ConstantComposite 28 17 17
4(main): 2 Function None 3
5: Label
8(read_value1): 7(ptr) Variable Function
20(read_value2): 7(ptr) Variable Function
15: 14(ptr) AccessChain 11(buf) 13
19: 6(int) AtomicIAdd 15 17 18 16
Store 8(read_value1) 19
24: 14(ptr) AccessChain 23(buf_coherent) 13
26: 6(int) AtomicIAdd 24 17 18 25
Store 20(read_value2) 26
Return
FunctionEnd
Capability Shader
+ Capability VulkanMemoryModelKHR
+ Extension "SPV_KHR_vulkan_memory_model"
1: ExtInstImport "GLSL.std.450"
- MemoryModel Logical GLSL450
+ MemoryModel Logical VulkanKHR
EntryPoint GLCompute 4 "main"
Decorate 11(buf) Binding 0
- MemberDecorate 21(Buf_coherent) 0 Coherent
MemberDecorate 21(Buf_coherent) 0 Restrict
- MemberDecorate 18(Buf_coherent) 0 Coherent
- 23: 6(int) Load 22
- 24: 6(int) IAdd 23 21
- 25: 13(ptr) AccessChain 20(buf_coherent) 11
- Store 25 24
+ 23: 6(int) Load 22 MakePointerVisibleKHR NonPrivatePointerKHR 24
+ 25: 6(int) IAdd 23 21
+ 26: 13(ptr) AccessChain 20(buf_coherent) 11
+ Store 26 25 MakePointerAvailableKHR NonPrivatePointerKHR 24