OpenGL/OpenGLES 中的帧缓冲纹理行为

Posted

技术标签:

【中文标题】OpenGL/OpenGLES 中的帧缓冲纹理行为【英文标题】:Framebuffer Texture behavior in OpenGL/OpenGLES 【发布时间】:2011-06-23 19:06:46 【问题描述】:

在 OpenGL/ES 中,在实现渲染到纹理功能时,您必须小心不要导致反馈循环(从您正在写入的同一纹理中读取像素)。由于显而易见的原因,当您读取和写入纹理的相同像素时,行为是未定义的。但是,如果您正在读取和写入同一纹理的不同像素,它是否也是未定义的行为?一个例子是,如果我试图制作一个内部带有渲染纹理的纹理图集。在渲染纹理时,我从存储在纹理图集中的另一个纹理中读取像素。

因为我没有在纹理中读取和写入相同的像素,所以行为仍然被认为是未定义的,只是因为数据来自同一个纹理?

【问题讨论】:

【参考方案1】:

但是,如果您正在读取和写入同一纹理的不同像素,它是否也是未定义的行为?

是的。

缓存是这里的大问题。写入像素数据时,不一定会立即写入图像。写入存储在缓存中,因此可以一次写入多个像素。

纹理访问做同样的事情。问题是它们没有 same 缓存。所以你可以写一些在写缓存中的数据,但是纹理缓存不知道。

现在,这里的规范有点强硬。 理论上您可以从纹理的一个区域读取并写入另一个区域(但规范未定义),只要您从不从您的任何位置读取'已经写信给,反之亦然。显然,这不是很有帮助。

NV_texture_barrier 扩展允许您解决这个问题。尽管是 NVIDIA 扩展,但它也支持 ATI 硬件。它的工作方式是在您想要刷新所有缓存时调用glTextureBarrierNV 函数。这样,您就可以确定当您从某个位置读取数据时,您已经写入了该位置。

因此,您可以将纹理的一个区域指定为写入区域,将另一个区域指定为读取区域。在你渲染了一些东西之后,你需要做回读,你触发一个屏障并交换纹理区域。这就像纹理乒乓球,但没有附加新纹理或绑定 FBO 或更改绘制缓冲区的繁重操作。

【讨论】:

【参考方案2】:

问题不在于反馈循环的可能性(从技术上讲,这不会导致循环,而是读取/写入像素的未定义顺序导致无法定义的行为),而是 GPU 实现的访问模式的限制:缓冲区只能在任何给定时间读取或写入(收集与分散访问)。 GPU 总是将缓冲区视为一个整体。这是造成这种限制的主要原因。

【讨论】:

【参考方案3】:

是的,它仍然是,GPU 是大规模并行的,所以你不能真的说你一次写入“一个”像素,当你准备好纹理时也会填充缓存系统。如果您写入相同的纹理,则需要同步缓存,等等。

如需了解更多信息,您可以查看NV_texture_barrier OpenGL 扩展,旨在为该区域增加一些灵活性。

【讨论】:

【参考方案4】:

是的,读取/写入纹理的不同区域也是未定义的。但是为什么要关心它是否未定义,只需写入另一个纹理并完全避免问题!

【讨论】:

以上是关于OpenGL/OpenGLES 中的帧缓冲纹理行为的主要内容,如果未能解决你的问题,请参考以下文章

我是不是需要将渲染缓冲区附加到已经附加了纹理的帧缓冲区?

opengl - 比我设置的更小的帧缓冲纹理?

WebGL:在带有深度模板纹理附件的帧缓冲区上未清除颜色

OpenGL(FBO)中的普通后台缓冲区+渲染到深度纹理

OpenGLES 2.0 帧缓冲区可以同时绑定到纹理和渲染缓冲区吗?

WebGL:显示深度纹理