Opengl GLSL'究竟是什么;s";连贯的;由GPU驱动程序解释的用于多次渲染的内存限定符?

Opengl GLSL'究竟是什么;s";连贯的;由GPU驱动程序解释的用于多次渲染的内存限定符?,opengl,glsl,textures,multipass,Opengl,Glsl,Textures,Multipass,GLSL规范规定,对于“一致”内存限定符:“读取和写入与其他着色器调用的读取和写入一致的内存变量” 在实践中,我不确定现代GPU驱动程序如何解释多个渲染过程。当GLSL规范声明“其他着色器调用”时,这是指仅在当前过程中运行的着色器调用,还是指在过去或未来过程中任何可能的着色器调用?出于我的目的,我将过程定义为一个“glBindFramebuffer-glViewPort-glUseProgram-glDrawABC-glDrawXYZ-glDraw123”循环;我目前在每个“渲染循环迭代”中执行

GLSL规范规定,对于“一致”内存限定符:“读取和写入与其他着色器调用的读取和写入一致的内存变量”

在实践中,我不确定现代GPU驱动程序如何解释多个渲染过程。当GLSL规范声明“其他着色器调用”时,这是指仅在当前过程中运行的着色器调用,还是指在过去或未来过程中任何可能的着色器调用?出于我的目的,我将过程定义为一个“glBindFramebuffer-glViewPort-glUseProgram-glDrawABC-glDrawXYZ-glDraw123”循环;我目前在每个“渲染循环迭代”中执行2个这样的过程,但以后每次迭代可能会执行更多

当GLSL规范声明“其他着色器调用”时,这是指仅在当前过程中运行的着色器调用,还是指在过去或未来过程中任何可能的着色器调用

它的意思正是它所说的:“其他着色器调用”。它可能是相同的程序代码。可能是不同的代码。这无关紧要:着色器调用不是这一个

通常,OpenGL会为您处理同步,因为OpenGL可以相当容易地跟踪同步。如果您映射缓冲区对象的一个范围,修改它,并取消映射它,OpenGL就会知道您(可能)更改了多少内容。如果您使用glTexSubImage2D,它知道您更改了多少内容。如果您转换反馈,它可以准确地知道有多少数据写入了缓冲区

如果将反馈转换为缓冲区,然后将其绑定为顶点数据的源,OpenGL知道这将暂停管道。它必须等待变换反馈完成,然后清除一些缓存,以便对顶点数据使用缓冲区

当您处理图像加载/存储时,您会丢失所有这些。因为很多东西都可以完全随机、未知和不可知的方式编写,所以OpenGL通常会严格遵守规则,以允许您灵活地获得最大可能的性能。这会触发许多未定义的行为

通常,您只能遵循OpenGL 4.2规范第2.11.13节中概述的规则。最大的一个(对于着色器到着色器的对话)是关于阶段的规则。如果在片段着色器中,可以安全地假设专门计算三角形的点/线/三角形的顶点着色器已完成。因此,您可以自由加载它们存储的值。但只有那些造就你的人

您的着色器无法假设在以前的渲染命令中执行的着色器已经完成(我知道这听起来很奇怪,考虑到刚才所说的,但请记住:“仅从创建您的着色器中执行”)。着色器不能假设在同一渲染命令中使用相同制服、图像、纹理等对同一着色器的其他调用已完成,除非上述情况适用

唯一可以假设的是,着色器实例本身所做的写入是可见的。。。自言自语。因此,如果您通过相同的变量对相同的内存位置执行
imageStore
并执行
imagesload
,则可以保证返回相同的值

除非有人同时写信给它

着色器不能假定稍后的渲染命令一定会获取前一个渲染命令写入的值(通过图像存储或原子更新)不管过多久与上下文绑定的内容并不重要。不管你上传或下载了什么(从技术上讲,可能在某些情况下你会得到正确的行为,但未定义的行为仍然是未定义的)

如果您需要这种保证,如果您需要发出一个渲染命令来获取图像存储/原子更新写入的值,那么您必须在发出写入调用之后和发出读取调用之前的某个时间显式地请求同步内存。这件事就这样结束了

因此,如果渲染不用于图像存储的对象,则在发送适当的屏障(在着色器中显式地或在OpenGL代码中显式地)之前,无法渲染使用存储数据的对象。这可能是图像加载操作。但它可以从着色器代码编写的缓冲区对象进行渲染。这可能是一个纹理提取。它可以对附加到FBO的图像进行混合。没关系;你不能这么做


请注意,这适用于所有处理图像加载/存储/原子的操作,而不仅仅是着色器操作。因此,如果使用图像存储写入图像,则不一定要读取正确的数据,除非使用
GL\u纹理\u更新\u屏障\u位​屏障。

非常感谢您提供了这些非常详细的深入见解。允许着色器写入内容的image\u load\u store是一个相当新的东西,所以这些确切的警告正是我在网上阅读时遗漏的。非常感谢!实际上,我的第二个frag着色器读取我的第一个frag着色器编写的内容,所以听起来我必须在这两个过程之间调用一个glMemoryBarrier。嗯。。。。或者,根据我的理解,我可以指定连贯性/易失性,内存障碍与否——但由于第一个(生产者)着色器是写的,第二个(消费者)着色器是只读的,不指定任何内存限定符并在两个着色器之间放置一个屏障可能更有效?@PhilS.:否。指定
一致性
没有帮助<代码>一致性
不保证订购<代码>一致性
意味着关闭缓存,以便其他
一致性
读取可以看到
一致性
写入。不影响完成顺序;只有障碍物才能做到这一点。既然你需要一个屏障,你根本不需要连贯的。Ind