是不是 GLSL 中的 memoryBarrier 在单个着色器调用中对内存事务进行排序,而 OpenGL API 中的 glMemoryBarrier 在多个着色器调用(不一定属于同一程序)中对内存事务进行排序。
1 回答
是不是 GLSL 中的 memoryBarrier 在单个着色器调用中对内存事务进行排序,而 OpenGL API 中的 glMemoryBarrier 在多个着色器调用(不一定属于同一程序)中对内存事务进行排序。
不完全是。您应该首先明确什么是着色器调用:它是处理单个输入实体的着色器代码的执行。因此,对于您进行的绘制调用的每个顶点都有一个顶点着色器调用,并且对于光栅化产生的每个片段至少有一次片段着色器调用(在某些类型的多重采样中它将不止一个)。不同绘制调用(可能不同)的着色器调用当然也是不同的调用。但通常,当人们谈到“多次调用”时,一种方法是在同一个绘图调用期间使用同一个着色器(它们都可能并行执行)。
GLSL 规范(4.40 版) (第8.17 节)对内存屏障有这样的说法:
所有类型的着色器都可以使用图像变量读取和写入纹理和缓冲区对象的内容。虽然单个着色器调用中的读取和写入顺序是明确定义的,但从多个单独的着色器调用中读取和写入单个共享内存地址的相对顺序在很大程度上是未定义的。正如其他着色器调用所观察到的,由一个着色器调用执行的内存访问顺序在很大程度上也是未定义的,但可以通过内存控制函数进行控制。
因此,这可能是也可能不是您对上述语句的含义,具体取决于您对“单个调用”的含义,但前提是您将其解释为“单个绘图调用的所有调用”。
这是来自OpenGL 4.4 核心配置文件规范,第 7.12.2 节
需要显式同步以确保着色器执行的缓冲区和纹理数据存储的效果将对使用相同对象的后续操作可见,并且不会覆盖仍由先前请求的操作读取的数据。如果没有手动同步,“新”图元的着色器存储可能会在“旧”图元的处理完成之前完成。此外,“旧”原语的存储可能不会在“新”原语的处理开始之前完成。
因此,这也不仅仅与以下绘制调用的着色器调用有关。它甚至根本不需要新的着色器调用:如果以下 GL 命令使用或覆盖着色器写入的数据,则必须手动同步。请注意,这仅在您的着色器写入缓冲区或纹理时才相关,它与通过管道写入的“普通”帧缓冲区无关:
相同着色器类型的调用的相对顺序未定义。着色器在处理图元 B 时发出的存储可能在存储图元 A 之前完成,即使在图元 B 之前指定了图元 A。这甚至适用于片段着色器;虽然片段着色器输出以原始顺序写入帧缓冲区,但片段着色器调用执行的存储不是。
我建议您阅读完整的第 7.12 节,此处太长无法粘贴,但对于理解 GL 的内存屏障功能至关重要。