GLRE的"连贯"内存限定符究竟是由GPU驱动程序解释为多遍渲染?

met*_*eap 4 opengl textures glsl multipass

GLSL规范规定,对于"相干"内存限定符:"内存变量,其中读取和写入与来自其他着色器调用的读取和写入一致".

实际上,我不确定现代GPU驱动程序如何解释多个渲染过程.当GLSL规范声明"其他着色器调用"时,它是指仅在当前传递期间运行的着色器调用,还是过去或将来传递中的任何可能的着色器调用?为了我的目的,我将一个传递定义为"glBindFramebuffer-glViewPort-glUseProgram-glDrawABC-glDrawXYZ-glDraw123"循环; 我现在正在每次"渲染循环迭代"执行2次这样的传递,但是稍后可能会有更多的每次迭代.

Nic*_*las 9

当GLSL规范声明"其他着色器调用"时,它是指仅在当前传递期间运行的着色器调用,还是过去或将来传递中的任何可能的着色器调用?

这正是它所说的:"其他着色器调用".它可能是相同的程序代码.它可能是不同的代码.没关系:着色器调用不是这个.

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

如果你确实将反馈转换为缓冲区,然后将其绑定为顶点数据的源,OpenGL知道这会使管道停顿.它必须等到变换反馈完成后,然后清除一些缓存以便将缓冲区用于顶点数据.

当您处理图像加载/存储时,您将丢失所有这些.因为可以用完全随机,未知和不可知的方式编写这么多内容,OpenGL通常会非常松散地遵守规则,以便您可以灵活地获得最大可能的性能.这会触发很多未定义的行为.

通常,您可以遵循的唯一规则是OpenGL 4.2规范的2.11.13节中概述的规则.最大的一个(用于着色器到着色器的谈话)是舞台上的规则.如果你在一个片段着色器的时候,它是安全的假设,即专为计算点/线/三角形的顶点着色器(S)的三角形已经完成.因此,您可以自由加载它们存储的值.但只能来自那些让你成功的人.

你的着色器不能假设在先前的渲染命令中执行的着色器已经完成(我知道这听起来很奇怪,考虑到刚才所说的,但请记住:"只有那些使你成为的人").除非上述情况适用,否则您的着色器无法假设在同一渲染命令中使用相同的制服,图像,纹理等完成同一着色器的其他调用.

您唯一可以假设的是,您自己制作的着色器实例的编写是可见的...... 因此,如果您通过相同的变量执行imageStore并执行imageLoad相同的内存位置,那么您可以保证获得相同的值.

好吧,除非有人在此期间给它写信.

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

如果需要该保证,如果需要发出将获取由图像存储/原子更新写入的值的渲染命令,则必须在发出写入调用之后和发出读取调用之前显式请求同步内存.这是完成的glMemoryBarrier.

因此,如果渲染某些进行图像存储的内容,则无法渲染使用存储数据的内容,直到发送了适当的屏障(在着色器中显式显示或在OpenGL代码中显式).这可能是图像加载操作.但它可能是由着色器代码编写的缓冲区对象渲染的.它可能是纹理提取.它可以与附加到FBO的图像进行混合.没关系; 你不能这样做.

请注意,这适用于处理图像加载/存储/原子的所有操作,而不仅仅是着色器操作.因此,如果使用图像存储区写入图像,除非使用GL_TEXTURE_UPDATE_BARRIER_BIT?屏障,否则不一定会读取正确的数据.