有没有可能对VBO进行原地调整大小?

16

标题已经说明了一切,但为了清楚起见,我会添加一些额外的词语。

在这种情况下,resize 的意思是:

  • 在旧的 vbo 结尾获取更多的存储空间
  • 在前面保存旧数据
  • (希望不需要复制,但至少不是在 CPU 端进行复制,这意味着驱动程序应该处理此操作)

编辑

为了解释更多细节和证明我的问题:
我将把(事先)未知大小的数据存储到 VBO 中,但我只知道一个非常粗略的上限估计(在不寻常的情况下比原来的数据量大 10 到 100 倍甚至更多)。

当然,当我完成后,我知道存储了多少数据,因此如果找到 VBO 太小并进行调整大小,然后继续存储数据,那将是很好的。

以下是我不想复制(特别是不想在 CPU 端进行复制)的原因:
我正在 GPU 上完成所有这些操作,以获得交互式帧速率。 当我必须复制时,速度非常慢或根本不可能,因为没有足够的空间。最糟糕的是在 CPU 上复制数据,因此将所有内容传递到总线上,进入具有足够大小的新内存区域,然后使用新大小和新内存区域作为源 glBufferData VBO。这将是性能杀手。

避免

我通过对所需空间进行精确估计来避免了问题。但我将让这个问题未被回答一周,看看是否有人对此有其他提示,因为我对解决方案不是很满意。


你是在尝试只使用一个(巨大的)VBO吗? - Rookie
@新手:我想让VBO尽可能小,但它仍然可能很大(> 100mb)。但我希望同时存储至少3个VBO和一些额外的数据,这些数据约为40mb大小。 - Nobody moving away from SE
2
我不确定VBO在不同的显卡上的性能差异,但是在我的显卡上,如果VBO超过1MB,性能会大幅下降。考虑到100MB的VBO听起来很疯狂,尝试将它们分成最大1MB的块,即使有100倍更多的VBO(在你的情况下只有300个VBO),我认为你也不会渲染得更慢。这应该也可以解决你的调整大小问题。更不用说,在我的显卡上,我无法制作大于4MB或其他大小的VBO,否则数据会损坏并且无法渲染其余部分。 - Rookie
@Rookie:对我来说,那些大的VBO并不是问题,它们可以正常渲染,没有损坏的数据或减速。你的显卡多久了?我认为调用300次glDrawArrays比在一个大的VBO上调用一次要更耗费资源,但我没有测试过。 - Nobody moving away from SE
如果你没有测试过它,那么你应该...也许你的显卡太快了,以至于即使你只得到1%的性能,你也认为没有减速;)我的显卡不是市场上最好的,但它非常好,任何游戏都可以很好地运行。如果你只是为自己做这件事,那么其他人无法运行你的程序就无所谓了,否则你应该在不同的用户上运行大量测试,我不认为我能运行那个东西,甚至可能会炸掉我的显卡...;) - Rookie
调用300次VBO并不是真正的瓶颈,可以将其视为在屏幕上绘制300个对象:300个对象太多了吗?当然不!我会说,在50000次VBO调用之后你可能会看到一些差异(我也测试过,实际上几乎没有注意到FPS的任何差异...)然而,最好自己测试这些,因为你(或者你使用的显卡类型)似乎是唯一一个使用该程序的人。 - Rookie
3个回答

9

我认为如果不进行复制的话,你无法绕过此问题,因为调整缓冲区大小的唯一方法是调用glBufferData,在我看来没有办法告诉驱动程序保留旧数据。

您可能可以做的是创建某种辅助VBO,以便直接从VBO复制到辅助VBO(使用ARB_copy_buffer扩展),调整VBO的大小并将其内容复制回去。但是我认为最好的方法是预先分配较大的缓冲区,这样就不需要调整大小,但是在这种情况下,您需要大概知道需要多少额外的存储空间。


6
如果您需要动态调整大小的VBO,可以尝试模仿std::vector的行为,在添加元素时获得均摊常数时间。 - pmr
我也考虑过这个问题,但GPU内存(1GB)已经很紧张了,所以没有太多的空间来容纳额外的副本。我记得读到过调整大小取决于实现的文章。驱动程序可以调整大小,但不是必需的。顺便问候一下~rauc ;) - Nobody moving away from SE
我忘记了大缓冲区:我必须为我不知道但只能估计的数据分配缓冲区。估计给出的分配大小比实际需要的大约大100倍,但我无法提前知道。因此,在这种情况下,我还必须调整大小(缩小)以避免浪费太多内存,这很少见,正如我之前所述。 - Nobody moving away from SE

9

几年后回顾这个问题,随着新版本和扩展的出现,情况有所变化。

GPU端复制

在Christian Rau的答案中提到的扩展从3.1版开始就是核心扩展了,它允许我们通过glCopyBufferSubData将一个VBO的内容复制到另一个VBO中。希望驱动程序可以在GPU端完成此操作!

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

真正的调整大小

好消息是:有了稀疏缓冲区,我们可以期待更好的解决方案。

借助这个扩展,我们可以分配一个虚拟缓冲区,其中包含比我们的数据更多的空间,而不必支付未使用空间的费用。我们只需要“提交”我们要存储数据的物理内存区域。这意味着我们可以通过在其末尾提交新页面来“扩展”VBO。

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

如果您拥有任何数据,请告知此扩展的可用性,我将不胜感激。


-2

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接