opengl - GPU 驱动程序如何解释 GLSL 的 "coherent"内存限定符以进行多 channel 渲染?

标签 opengl glsl textures multipass

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

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

最佳答案

When the GLSL spec states "other shader invocations", does that refer to shader invocations running only during the current pass, or any possible shader invocations in past or future passes?



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

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

如果您确实将反馈转换为缓冲区,然后将其绑定(bind)为顶点数据的源,OpenGL 知道这将停止管道。它必须等到变换反馈完成,然后清除一些缓存才能将缓冲区用于顶点数据。

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

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

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

您唯一可以假设的是,您自己编写的着色器实例是可见的……对自己。因此,如果您执行 imageStore做一个imageLoad通过相同的变量到相同的内存位置,那么你可以保证得到相同的值。

好吧,除非其他人在此期间给它写信。

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

如果您需要该保证,如果您需要发出将获取图像存储/原子更新写入的值的渲染命令,您必须在发出写入调用之后和发出读取调用之前的某个时间明确询问同步内存。这是通过 glMemoryBarrier 完成的。 .

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

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

关于opengl - GPU 驱动程序如何解释 GLSL 的 "coherent"内存限定符以进行多 channel 渲染?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9731204/

相关文章:

java - glDrawElements 不绘制任何东西

c++ - 绘制和加载 GL_DEPTH_COMPONENT 纹理

c++ - 为什么在 OpenGL 上创建着色器后需要分离和删除着色器?

opengl - 为什么我会在 GLSL 中看到这个 OpenGL 球形映射工件?

c++ - OpenGL 包装器中的 Alpha/纹理问题

opengl - glDrawBuffers 在 OS X 下用于多个渲染目标的用法

OpenGL模糊

java - LWJGL2 多灯不亮?所有实体都是黑色的

Swift Metal 将 bgra8Unorm 纹理保存到 PNG 文件

c++ - 立即模式纹理奇怪的输出