当 GLSL 规范规定“其他着色器调用”时,这是指仅在当前通道期间运行的着色器调用,还是指过去或未来通道中任何可能的着色器调用?
它的意思正是它所说的:“其他着色器调用”。它可能是相同的程序代码。它可能是不同的代码。没关系:不是这个着色器调用。
通常,OpenGL 会为您处理同步,因为 OpenGL 可以相当轻松地跟踪同步。如果您映射一个缓冲区对象的范围,修改它,然后取消映射它,OpenGL 知道您(可能)更改了多少内容。如果您使用 glTexSubImage2D,它知道您更改了多少内容。如果您进行转换反馈,它可以准确地知道有多少数据写入了缓冲区。
如果您确实将反馈转换为缓冲区,然后将其绑定为顶点数据源,OpenGL 知道这将导致管道停顿。它必须等到变换反馈完成,然后清除一些缓存才能将缓冲区用于顶点数据。
当您处理图像加载/存储时,您失去这一切。由于很多内容都可以以完全随机、未知和不可知的方式编写,因此 OpenGL 通常对规则非常宽松,以便让您能够灵活地获得最大可能的性能。这会触发很多未定义的行为。
一般来说,您可以遵循的唯一规则是 OpenGL 4.2 规范第 2.11.13 节中概述的规则。最重要的一个(对于着色器到着色器的讨论)是舞台上的规则。如果您使用片段着色器,则可以安全地假设专门计算点/线/三角形的顶点着色器你的三角形已完成。因此,您可以自由加载它们存储的值。但只来自那些造就了你的人.
您的着色器无法假设先前渲染命令中执行的着色器已完成(我知道这听起来很奇怪,考虑到刚才所说的内容,但请记住:“仅来自那些使您成为可能的着色器”)。您的着色器不能假设在同一渲染命令中使用相同制服、图像、纹理等的同一着色器的其他调用已完成,除非上述情况适用。
您唯一可以假设的是,编写着色器实例本身使其对其自身可见。所以如果你做一个imageStore
并做一个imageLoad
到相同的内存位置通过同一个变量,那么您一定会得到相同的值。
好吧,除非有人同时写信给它。
您的着色器不能假设稍后的渲染命令将当然获取前一个写入的值(通过图像存储或原子更新)。不管多久之后!你将什么绑定到上下文并不重要。您上传或下载的内容并不重要(从技术上讲)。在某些情况下您可能会得到正确的行为,但未定义的行为仍然存在不明确的).
如果您需要这种保证,如果您需要发出一个渲染命令来获取由图像存储/原子更新写入的值,则必须在发出写入调用之后和发出读取调用之前的某个时间明确要求同步内存。这是用完成的glMemoryBarrier http://www.opengl.org/wiki/GLAPI/glMemoryBarrier.
因此,如果你渲染一些进行图像存储的东西,你cannot渲染使用存储数据的内容,直到发送适当的屏障(在着色器中显式或在 OpenGL 代码中显式发送)。这可能是图像加载操作。但它可以从着色器代码编写的缓冲区对象进行渲染。它可能是纹理获取。它可能正在对附加到 FBO 的图像进行混合。没关系;你做不到。
请注意,这适用于all处理图像加载/存储/原子的操作,而不仅仅是着色器操作。因此,如果您使用图像存储写入图像,则不一定会读取正确的数据,除非您使用GL_TEXTURE_UPDATE_BARRIER_BIT
障碍。