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