【问题标题】:OpenGL: efficient way to read sparce pixel data from many framebuffer textures?OpenGL:从许多帧缓冲区纹理中读取稀疏像素数据的有效方法?
【发布时间】:2015-10-18 06:54:05
【问题描述】:

我正在编写一个使用 GPU 计算内容的程序,并且我想从帧缓冲区中读取数据以在我的客户端代码中使用。我正在使用的帧缓冲区大约有 40 个纹理,大小均为 1024x1024,所有这些都包含需要读取的数据,但非常稀少,例如每个纹理的任意 x/y 坐标中的 50 个左右像素。为每个纹理、每个帧使用 glReadPixels 对我来说成本太高了……

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

【问题讨论】:

    标签: c++ opengl gpu


    【解决方案1】:

    无论您如何切片,这听起来都相当昂贵。我想到了几种方法:

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

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

    这两种方法应该会产生大致相同的工作量和同步开销。但其中一种可能更有效,具体取决于驱动程序中的哪些路径得到了更好的优化。

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

    【讨论】:

    • 选项 2 对我来说似乎是两者中更快的一个,并且效果很好! (不幸的是,需要撤回这些值是不可避免的)
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2015-07-02
        • 2012-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-24
        • 2023-03-17
        • 1970-01-01
        相关资源
        最近更新 更多