这与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);
答案 0 :(得分:1)
要直接回答这个问题,这两行代码生成不同的指令,具有不同的性能特征和硬件管道使用情况。
uint read_value = b.field; // generates a load instruction
uint read_value2 = atomicAdd(b.field, 0); // generates an atomic instruction
buffer_load_dword
与buffer_atomic_add
LDG
与ATOM
GLSL spec部分4.10内存限定符指出,coherent
仅涉及跨调用(着色线程)的读写可见性。他们还对隐含性能发表了评论:
当使用未声明为一致性的变量访问内存时,着色器访问的内存可能由实现缓存,以为将来对同一地址的访问提供服务。可以按以下方式缓存内存存储,即写入的值对于访问同一内存的其他着色器调用可能不可见。该实现可以缓存由内存读取获取的值,并将相同的值返回给访问同一内存的任何着色器调用,即使自第一次读取内存以来已修改了基础内存。虽然未声明为一致的变量可能对在着色器调用之间进行通信没有用,但是使用非一致的访问可能会提高性能。
GPU内存系统中的一致性点通常是最后一级的缓存(L2缓存),这意味着所有一致性访问必须由L2缓存执行。这也意味着相干缓冲区不能在L1或更靠近着色器处理器的其他缓冲区中进行缓存。现代GPU在L2缓存中还具有专用的原子硬件。普通负载不会使用这些负载,但是atomicAdd(..., 0)
会通过这些负载。原子硬件通常比完整的L2缓存具有更低的带宽。
答案 1 :(得分:0)
SPIR-V有一条OpAtomicLoad
指令。大概至少有一种硬件,无论缓冲区描述符具有什么限定符,非原子负载都不能替代原子负载。
不幸的是,我所知道的没有Vulkan GLSL构造可以转换为OpAtomicLoad
。