2015-10-16 44 views
0

我正在编写一个使用GPU来计算东西的程序,我想从我的客户端代码中使用的帧缓冲区中读取数据。我正在使用的帧缓冲区大约有40个纹理,所有的尺寸都是1024x1024,所有这些纹理都包含需要读取的数据,但只是非常细腻,就像每个纹理任意x/y坐标中的50个像素。使用glReadPixels为每个纹理,对于每一帧,对我而言都证明过于昂贵,尽管...OpenGL:从许多framebuffer纹理读取sparce像素数据的有效方法?

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

回答

2

这听起来相当昂贵的,无论你如何切它直接复制像素。想到几个方法:

  • 我想先尝试的是glReadPixels(),但使用PBO。绑定足够大的缓冲区,以将所有像素保存到目标,然后提交glReadPixels()调用,并使用偏移量将结果放在缓冲区的不同部分。然后致电glMapBufferRange()回读这些值。

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

这两种方法都会导致大致相同的工作量和同步开销。但其中一个或另一个可能更有效率,这取决于驱动程序中的哪个路径得到了更好的优化。如前面的答案已经提出,我会让确定你确实需要这个,并且没有任何方法来保存和处理GPU上的数据。无论何时读回数据,都会在GPU和CPU之间引入同步,这对性能影响最大。

+0

选项2对我来说似乎是两者中速度更快的,并且效果相当好! (不幸的是需要提取值是不可避免的) –

0

如果您需要将GPU中的数据复制到CPU内存,则无法使用glReadPixels(AFAIK)。

取决于你使用什么平台,和你的程序的具体,你可以尝试一些优化,使用的FBO:

  • 仅复制纹理的一部分,假设你知道的位置像素。请注意,在大多数情况下,复制整个纹理的速度更快,而不是发出几个小的读数

  • 如果不需要32位纹理,则可以渲染到较低的颜色分辨率。具体取决于您的平台扩展。

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

2

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

如果是这样的话,那么你需要的只是一个着色器存储缓冲区和一个原子计数器。在某一时刻,您正在决定片段(x,y,z [z是纹理索引])的值应该是v。因此,在您的计算着色器中,您将按照在片段着色器中的计算方式进行计算, ,你存储一个元组(x,y,z,v)。您可以将此元组存储在着色器存储缓冲区中原子计数器的索引处,该元素在每个写入元素后递增。最后,您将数据紧凑地存储在缓冲区中,只需要读回这些元素。确切的数字是原子计数器在终止后保持的值。将glGetBufferSubData缓冲区下载到位置值对的数组中,迭代它并完成CPU的魔力。

相关问题