OpenGL:从许多帧缓冲纹理中读取空间像素数据的有效方法

OpenGL: efficient way to read sparce pixel data from many framebuffer textures?

本文关键字:像素数 像素 数据 方法 有效 空间 读取 许多帧 缓冲 纹理 OpenGL      更新时间:2023-10-16

我正在写一个程序,使用GPU来计算的东西,我想从帧缓冲区读取数据在我的客户端代码中使用。我使用的framebuffer大约有40个纹理,大小都是1024x1024,所有这些纹理都包含需要读取的数据,但只是非常稀疏,比如每个纹理的任意x/y坐标中的50个左右像素。使用glReadPixels为每个纹理,为每个帧,是证明太昂贵了,我做尽管…

我只需要从每个纹理中读取几个选择像素,是否有一种方法可以快速收集他们的数据,而无需从GPU下载每个整个纹理?

无论你怎么划分,这听起来都相当昂贵。我想到了两种方法:

  • 我首先尝试的是glReadPixels(),但使用PBO。绑定一个足够大的缓冲区来容纳GL_PIXEL_PACK_BUFFER目标的所有像素,然后提交glReadPixels()调用,并将结果偏移放置在缓冲区的不同部分。然后调用glMapBufferRange()回读值

  • 另一种方法是将所有想要读取的像素复制到单个纹理中。您可以使用glBlitFramebuffer()glCopyTexSubImage2D()。然后使用单个glReadPixels()glGetTexImage()调用从该纹理获取所有数据。

这两种方法应该导致相同数量的工作和同步开销。但其中一个可能更有效,这取决于驱动程序中的哪条路径优化得更好。

正如前面的答案所建议的那样,我会使非常确定您确实需要这个,并且没有任何方法可以在GPU上保存和处理数据。每当你回读数据时,你就会在GPU和CPU之间引入同步,这对性能是最有害的。

您对可以使用的OpenGL版本有任何限制吗?如果没有,听起来你应该看看计算着色器。你说你正在计算数据,所以我认为你是"滥用"渲染管道为您的应用程序,特别是片段着色器,并存储片段数据在帧缓冲区,被解释为其他东西而不是颜色。

如果是这种情况,那么你所需要的只是一个着色器存储缓冲区和一个原子计数器。在某些时候,现在你决定片段(x, y, z [z是纹理索引])应该有值v。所以在你的计算着色器中,你像在片段着色器中那样进行计算,但作为输出,你存储一个元组(x, y, z, v)。你将这个元组存储在着色器存储缓冲区中的原子计数器的索引处,在每个写入元素后增加。最后,将数据紧凑地存储在缓冲区中,只需要回读这些元素。确切的数字是原子计数器在终止后保持的值。将带有glGetBufferSubData的缓冲区下载到位置-值对数组中,遍历它并执行您的CPU魔法。

如果您需要将数据从GPU复制到CPU内存,则没有办法(AFAIK)使用glReadPixels。

根据您使用的平台和程序的具体情况,您可以使用fbo尝试几种优化:

  • 只复制部分纹理,假设你知道像素的位置。请注意,在大多数情况下,复制整个纹理比发出几个小的读取

  • 更快。
  • 如果你不需要32位纹理,你可以渲染到一个较低的颜色分辨率。

  • 也许你真的不需要复制像素,因为你打算将它们用作下一阶段的纹理输入?在这种情况下,你可以使用glCopyTexImage2D

  • 直接在GPU上复制像素