我有一个片段着色器,使用图像加载/存储操作在imageBuffer上执行处理。我只关心以下情况:
- 我有一个单一的片段着色器(没有多级(例如。顶点然后片段着色器)考虑,并且没有多通道渲染)
- imageBuffer变量被声明为一致的。只对相干imageBuffers感兴趣。
为了让事情更清楚,我的场景是这样的:
// Source code of my sole and unique fragment shader:
coherent layout(1x32) uniform uimageBuffer data;
void main()
{
...
various calls to imageLoad(data, ..., ...);
...
various calls to imageStore(data, ..., ...);
...
}
我主要看了规范
ARB_shader_image_load_store
尤其是这一段:
"使用声明为"coherent"的变量保证商店将立即可见的着色器调用使用similarly-declared变量;调用MemoryBarrier是必需的确保存储对其他操作可见。"
注意:我的"coherent uniform imageBuffer data;"声明是一个"类似声明"的变量。我的场景是单通道,单阶段(片段着色器)。
现在,我已经看了各种网站和绊倒(像大多数人一样,我认为)在stackoverflow.com上的这个线程:
GLSL's "是如何"连贯"的?内存限定符解释的GPU驱动程序的多通道渲染?
,更具体地说,这一段:
"你的着色器甚至不能假设发出一个负载之后,store会获取刚刚存储在这里的内存非常着色(是的,真的。你得放个记忆屏障进去才能拉把那个关掉)。"
我的问题是:
与连贯限定符指定,在我的单着色器,单通道处理场景,我可以是或否确定imageStore()的将立即可见的所有调用我的片段着色器(例如。(当前调用以及其他并发调用)?
通过阅读ARB_shader_image_load_store规范,在我看来:
- 这个问题的答案是肯定的,我不需要任何类型的memoryBarrier(),
- 上面引用的stackoverflow线程中的引用句可能确实是误导和错误的。
使用内存屏障。
一方面,GPU可以优化和获取整个内存块来读取,并有单独的内存来写入。
换句话说,如果你的着色器总是修改单个位置只有一次,那么它是可以的,但如果它依赖于邻居值后,一些计算应用,那么你需要内存屏障。
与连贯限定符指定,在我的单着色器,单通道处理场景,我可以是或否确定imageStore()的将立即可见的所有调用我的片段着色器(例如。(当前调用以及其他并发调用)?
如果每个片段着色器写入图像中的单独位置,并且每个片段着色器仅读取它写入的位置,那么您甚至不需要coherent
。然而,如果一个片段着色器实例想要读取其他片段着色器实例写的数据,你就错了。没有你可以为它做什么。
如果它是一个计算着色器,你可以发出barrier
调用来同步工作组内的操作。这将确保您想要读取的写入发生(您仍然需要memoryBarrier
调用来使它们可见)。但是,这只能确保来自该工作组中的实例的写入已经发生。来自其他实例的写入仍然未定义。
顺便说一句,那一段是错的。大错特错。可惜写这段话的人永远不会被认出来;),更具体地说,这一段: