如果“缓冲区”是“相干的”,那么读取字段或执行“ atomicAdd(field,0)”之间有什么区别吗?

时间:2019-07-19 14:31:54

标签: glsl vulkan

这与Vulkan语义有关(如果有区别的话)。

假设以下内容:

layout(...) coherent buffer B
{
    uint field;
} b;

说通过atomic*()函数对同一着色器(或派生着色器)的其他调用正在修改该字段。

如果着色器调用要从此field执行原子读取(与GLES中的atomicCounter()相同,如果不是atomic_uint,则有区别)在接下来的两个之间(显然不是其中一个可以读写)?

uint read_value = b.field;
uint read_value2 = atomicAdd(b.field, 0);

2 个答案:

答案 0 :(得分:1)

要直接回答这个问题,这两行代码生成不同的指令,具有不同的性能特征和硬件管道使用情况。

uint read_value = b.field;                 // generates a load instruction
uint read_value2 = atomicAdd(b.field, 0);  // generates an atomic instruction

GLSL spec部分4.10内存限定符指出,coherent仅涉及跨调用(着色线程)的读写可见性。他们还对隐含性能发表了评论:

  

当使用未声明为一致性的变量访问内存时,着色器访问的内存可能由实现缓存,以为将来对同一地址的访问提供服务。可以按以下方式缓存内存存储,即写入的值对于访问同一内存的其他着色器调用可能不可见。该实现可以缓存由内存读取获取的值,并将相同的值返回给访问同一内存的任何着色器调用,即使自第一次读取内存以来已修改了基础内存。虽然未声明为一致的变量可能对在着色器调用之间进行通信没有用,但是使用非一致的访问可能会提高性能。

GPU内存系统中的一致性点通常是最后一级的缓存(L2缓存),这意味着所有一致性访问必须由L2缓存执行。这也意味着相干缓冲区不能在L1或更靠近着色器处理器的其他缓冲区中进行缓存。现代GPU在L2缓存中还具有专用的原子硬件。普通负载不会使用这些负载,但是atomicAdd(..., 0)会通过这些负载。原子硬件通常比完整的L2缓存具有更低的带宽。

答案 1 :(得分:0)

SPIR-V有一条OpAtomicLoad指令。大概至少有一种硬件,无论缓冲区描述符具有什么限定符,非原子负载都不能替代原子负载。

不幸的是,我所知道的没有Vulkan GLSL构造可以转换为OpAtomicLoad