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



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

由于我没有在纹理中读取和写入相同的像素,仅仅因为数据来自相同的纹理,行为是否仍被认为是未定义的?

然而,如果你对同一纹理的不同像素进行读取和写入,这是否也是未定义的行为?

是的。

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

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

现在,这里的规范有点苛刻。理论上可以从纹理的一个区域读取并写入另一个区域(但规范未定义),只要从未从写入的任何位置读取,反之亦然。显然,这没有多大帮助。

NV_texture_barrier扩展允许您绕过此问题。尽管它是NVIDIA的扩展,但ATI硬件也支持它。它的工作方式是,当您想刷新所有缓存时,调用glTextureBarrierNV函数。这样,你就可以确保当你从一个位置读取时,你已经向它写入了内容

因此,我们的想法是将纹理的一个区域指定为写入区域,另一个区域则指定为读取区域。渲染完一些东西后,需要进行读回,然后发射一个屏障并交换纹理区域。这就像纹理乒乓球,但不需要附加新纹理、绑定FBO或更改绘图缓冲区等繁重操作。

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

是的,GPU是大规模并行的,所以你不能真的说你一次写一个像素,还有缓存系统,当你准备好纹理时会填充。如果写入相同的纹理,则需要同步缓存,依此类推

为了获得一些见解,您可以查看NV_texture_barrier OpenGL扩展,它旨在为这一领域增加一些灵活性。

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

最新更新