我正在编写一个使用GPU来计算内容的程序,我想从框架缓冲区中读取数据,以便在我的客户端代码中使用。我使用的帧缓冲区大约有40个纹理,大小都是1024x1024,所有这些纹理都包含需要读取的数据,但只是非常少,例如每个纹理的任意x / y坐标中有50个左右的像素。对于每个帧,每个纹理都使用glReadPixels对我来说太昂贵了... ...
我只需要从每个纹理中读取几个选择像素,有没有办法快速收集数据而无需从GPU下载每个整个纹理?
答案 0 :(得分:3)
无论你如何切片,这听起来都相当昂贵。我想到了几种方法:
我首先尝试的是glReadPixels()
,但是使用PBO。绑定足够大的缓冲区以将所有像素保存到GL_PIXEL_PACK_BUFFER
目标,然后提交glReadPixels()
调用,并使用偏移量将结果放在缓冲区的不同部分。然后拨打glMapBufferRange()
以回读这些值。
另一种方法是将要读取的所有像素复制到单个纹理中。您可以使用glBlitFramebuffer()
或glCopyTexSubImage2D()
。然后使用单个glReadPixels()
或glGetTexImage()
调用来获取此纹理中的所有数据。
这两种方法都应该导致大约相同的工作量和同步开销。但是,根据驱动程序中哪些路径得到更好的优化,其中一种可能更有效。
正如之前的回答已经建议的那样,我会确保非常确定你确实需要这个,并且没有任何方法可以保留和处理GPU上的数据。无论何时回读数据,都会引入GPU和CPU之间的同步,这对性能至关重要。
答案 1 :(得分:2)
您对可以使用的OpenGL版本有任何限制吗?如果没有,听起来你应该研究计算着色器。你说你在计算数据,所以我认为你是#"滥用"应用程序的渲染管道,尤其是片段着色器,并将帧片段数据存储在帧缓冲区中,并将其解释为颜色以外的其他内容。
如果是这种情况,那么您只需要一个着色器存储缓冲区和一个原子计数器。在某些时候,你现在决定片段(x,y,z [z是纹理索引])应该具有值v。所以在你的计算着色器中,你可以像在片段着色器中那样进行计算,但作为输出,你存储一个元组(x,y,z,v)。您将此元组存储在着色器存储缓冲区中的原子计数器的索引处,该索引在每个写入元素之后递增。最后,您将数据紧凑地存储在缓冲区中,只需读回这些元素即可。确切的数字是终止后原子计数器保存的值。将带有glGetBufferSubData的缓冲区下载到一个位置 - 值对的数组中,迭代它并完成你的CPU魔法。
答案 2 :(得分:0)
如果您需要将数据从GPU复制到CPU内存,则无法使用glReadPixels(AFAIK)。
根据您使用的平台以及您的程序的具体情况,您可以尝试使用FBO进行多项优化:
假设您知道像素的位置,只复制部分纹理。请注意,在大多数情况下,复制整个纹理仍然更快,而不是发出几个小读取
如果您不需要32位纹理,则可以渲染到较低的颜色分辨率。具体取决于您的平台扩展。
您可能不需要复制像素,因为您打算将它们用作下一阶段的纹理输入?在这种情况下,您可以使用glCopyTexImage2D