问题 是否可以就地调整VBO的大小?


标题说明了所有内容,但为了清楚起见,我会添加一些额外的单词。

在这种情况下, 调整 手段:

  • 在旧的vbo结束时获得更多的存储空间
  • 将旧数据保存在前面
  • (希望不要复制,但至少不要在CPU端,这意味着驱动程序应该处理这个)

编辑

至于解释一些更多细节并证明我的问题:
我将(正手)未知大小的数据存储到VBO,但我只知道一个非常粗略估计的上限(在异常条件下10-100倍甚至更多)。

当然,我知道我存储了多少数据,当我完成它时,所以存储数据会很好,直到我发现我的VBO太小并重新调整它然后继续存储。

这就是为什么我不想复制(特别是不在CPU端):
我在GPU上做这一切以获得交互式帧速率。当我不得不复制时,它很慢甚至不可能,因为没有足够的空间。最糟糕的是通过CPU复制数据,从而通过总线将所有内容传递到具有足够大小的新内存区域,然后 glBufferData使用新大小的VBO和新的内存区域作为源。那将是性能杀手。

绕开

我通过准确估计所需空间来规避问题。但是我会让这个问题在一个星期内无法回答,看看是否有人对此有另一个暗示,因为我对解决方案不太满意。


3564
2017-08-31 11:46


起源

你试图只使用一个(和巨大的)VBO吗? - Rookie
@Rookie:我想让VBO尽可能小,但它仍然可以很大(> 100mb)。但是我希望并行存储至少3个,以及大约40mb大小的额外数据。 - Nobody
我不确定VBO的性能如何在不同的卡之间变化, 但 在我的卡上我可以使最大1MB VBO或我失去了很多性能。考虑100MB VBO听起来很疯狂。尝试将它们分成最大1MB的碎片,我不认为你会渲染任何更慢的东西,即使有超过100倍的VBO(在你的情况下只有300个VBO)。这也应该解决你的调整大小问题。更不用说:在我的卡片中,我的CANT大于4MB或其他东西,之后数据被破坏并且不会渲染其余部分。 - Rookie
@Rookie:对我来说,那些大的VBO不是问题,它们可以很好地呈现没有损坏的数据或减速。你的卡多久了?我认为调用300次glDrawArrays要比在大型VBO上调用一次要高得多,但我没有测试过这个。 - Nobody
如果你没有测试它,你应该...也许你的卡是如此之快,你认为即使只有1%的性能也没有减速;)我的卡不是市场上最好的,但它非常好,任何游戏运行得很好。如果你只为自己做这件事,那么如果其他人不能运行你的程序就没关系,否则你应该运行大量测试它如何对不同的用户执行,我不认为我能够运行那个东西,甚至可能爆炸我的卡... ;) - Rookie


答案:


我认为没有复制你就不会解决这个问题,因为调整缓冲区的唯一方法是调用 glBufferData 并且IMO无法告诉驱动程序保留旧数据。

您可能做的至少不能将其复制到CPU并再次返回,为这些目的创建某种辅助VBO并直接从VBO复制到辅助VBO(使用 ARB_copy_buffer 扩展),调整VBO的大小并将其内容复制回来。

但我认为最好的方法是预先分配一个更大的缓冲区,因此调整大小不是必需的,但当然在这种情况下你需要知道你需要多少额外的存储空间。


7
2017-08-31 12:16



如果您需要动态调整大小VBO,您可以尝试模拟其行为 std::vector 并在添加元素时获得固定的循环时间。 - pmr
我也考虑过这一点,但GPU内存(1GB)上有很重的负载,因此没有太多空间来保存额外的副本。我记得根据实现情况阅读调整大小。司机 能够 调整大小但不是必需的。顺便说一句。问候〜rauc;) - Nobody
我忘记了大缓冲区:我必须为我不知道但只能估计的数据分配缓冲区。估计给我的分配大小比需要的大100倍,但我之前无法说明。因此,在这种情况下,我还必须调整大小(缩小)以避免浪费那么多内存,这在我已经说过的情况下很少见。 - Nobody


多年后重新审视这个问题,新版本和扩展版本的情况发生了一些变化。

GPU端复制

Christian Rau的回答中提到的扩展是自3.1以来的核心,它允许我们复制内容(通过 glCopyBufferSubData)从一个VBO到另一个。希望驱动程序在GPU方面做到这一点!

使用此功能,我们可以创建更大的缓冲区并复制前导数据。这样做的缺点是内存需求加倍,因为我们需要两个缓冲区。

真正的大小调整

好消息是:随着 稀疏缓冲区 一个更好的解决方案即将出现。

鉴于此扩展,我们可以为数据分配一个具有足够空间的虚拟缓冲区,而无需支付不必要的空间。我们只需要“提交”我们实际想要存储数据的内存区域。这意味着我们可以通过在其末尾提交新页面来“增长”VBO。

坏消息是:截至当前的OpenGL版本(4.5),这仍然是一个扩展而不是核心,因此采用这种方法可能是不可能的。您还应该注意,规范中还有一些尚未解决的细节。例如,当前扩展中不允许映射稀疏缓冲区,但可能会在将来的版本中添加支持。

如果你有任何数据,我会很想知道这个扩展的可用性。


6
2018-01-20 23:04





假设您支持最近的OpenGL标准,VBO的替代方案可能是将数据存储在纹理中(同样,假设您的卡上有足够的内存)。在新旧纹理之间复制数据将在卡上进行,而不会影响数据传输。

具体如何实现这一点取决于您的代码究竟在做什么。但原则上,您使用纹理数据覆盖绘图调用中的虚拟顶点数据,或者使用实例化。这需要大量的思考和返工。


-2
2018-03-12 10:01