【问题标题】:Is having a buffer per mesh in a model optimal?模型中的每个网格都有一个缓冲区是最优的吗?
【发布时间】:2017-07-19 13:18:31
【问题描述】:

我曾经认为绑定顶点比绑定着色器和纹理更重要,但现在我了解到情况恰恰相反。所以我正在重新配置我的绘图。基本上:

在一个模型中绘制多个网格,每个模型一个缓​​冲区是否最佳?或者是否有替代解决方案来绑定更少更大的缓冲区? (我以前将所有网格合并到一个大缓冲区中并简单地调用偏移量,但现在这意味着我绑定了不必要的顶点,因为这些顶点现在可能已绑定但稍后会使用)。

我所说的最佳是指 CPU、GPU 和驱动程序的传输速度。

【问题讨论】:

  • "现在这意味着我绑定了不必要的顶点,因为这些顶点可能稍后会被绑定" 这是什么意思?

标签: opengl graphics 3d buffer


【解决方案1】:

答案当然是“视情况而定”,并且因 GPU、驱动程序和您的应用程序要求而异。

绑定可以是一个非常轻量级的操作(类似于仅设置一个指针),或者可能需要将数据从主机 (CPU) 内存传输到 GPU — 这在很大程度上取决于资源使用情况和 GPU 内存中的驻留情况。例如,如果您有许多适合 GPU 内存的静态几何图形以及所有其他图形资源(例如纹理、元素数组等),那么大缓冲区可能会更好,因为您可以将其初始化一次,并且司机会很快发现它应该留在原地。

相反,如果您为每个对象使用大量不同的资源(例如,切换大量纹理),所有这些对象都不能同时驻留在 GPU 中,那么使用较小的缓冲区可能会更好,因为它为驱动程序提供了更多通过驱逐回收内存的选项。然而,硬币的另一面是它可能导致内存碎片,并可能浪费一些内存(尽管如果您对此感到担忧,则不需要回答这个问题)。

我能提供的最佳建议是,如果您需要从 CPU 更新缓冲区中的数据,请尝试仅更新受这些更改影响的缓冲区区域。使用glBufferSubData 之类的东西,并且只更新您需要的区域(并且明智地;例如,如果您需要更新两个由几个字节分隔的 1K 块,则在一个操作中完成所有操作)。并尽量避免在离散内存 GPU 系统上使用glMapBuffer 和朋友。该操作可能需要大量数据从 GPU 复制到 GPU;它对集成内存 GPU 系统的影响较小(尽管这不是一个具体的规则——缓冲区可能会被重新格式化,以便在后台进行更优化的内存操作)。

最明智的建议是:先做对,然后再做快(且仅在不够快的情况下)。

【讨论】:

  • 虽然我同意您的大部分回答,但据我所知,针对glMapBuffer 的建议是不正确的。首先,使用它来更新缓冲区可以节省用户空间和驱动程序内存之间的复制。其次,在最新硬件上实现最高吞吐量数据流的一般智慧是将glMapBufferRangeGL_MAP_UNSYNCHRONIZED_BIT 结合使用。
  • @ybungalobill:在最新的硬件上,您使用持久映射缓冲区。
  • 嗯嗯,有没有办法以一大块写入内存,然后将其分段为单独的缓冲区?
  • @KarimAbdelHamid: 只需使用一个大的缓冲区对象(可以留有间隙!)并根据需要调整顶点属性的偏移量,以便仅选择缓冲区的切片进行实际绘图。
  • @ybungalobill 您的前提非常依赖于系统和实现,这意味着我们都不能是全局正确的(here are some performance results 表明了这一点)。几乎不可能知道(在每种情况下)从glMapBuffer* 返回的内存是如何由驱动程序管理的; glBufferSubData 和朋友们更加明确,这使得驱动程序的工作更简单(至少在我工作过的驱动程序上)。但最终,它们都通过那根小吸管将数据发送到 GPU。
猜你喜欢
  • 2021-02-16
  • 1970-01-01
  • 2018-03-26
  • 2011-07-09
  • 1970-01-01
  • 2013-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多