是否可以就地调整 VBO 的大小?
标题说明了一切,但为了清楚起见,我会添加一些额外的文字。
在这种情况下,调整大小意味着:
- 在旧vbo的末尾获得更多存储空间,
- 将旧数据保存在前面
- (希望不是复制,但至少不是在CPU端,这意味着驱动程序应该处理这个)
编辑
为了解释更多细节并证明我的问题:
我会将(正手)未知大小的数据存储到 VBO,但我只知道一个非常粗略估计的上限(在异常条件下为 10 - 100 倍甚至更多)。
当然,当我完成后,我知道我存储了多少数据,所以最好存储数据,直到我发现我的 VBO 太小并调整它的大小,然后继续存储。
这就是为什么我不想复制(尤其是 CPU 端):
我在 GPU 上执行所有这些操作都是为了获得交互式帧速率。当我必须复制时,它非常慢甚至不可能,因为没有足够的空间。最糟糕的是通过 CPU 复制数据,从而通过总线将所有内容传递到具有足够大小的新内存区域,然后使用新大小和新内存区域来 glBufferData
处理 VBO来源。那将是性能杀手。
规避
我通过精确估计所需空间来规避这个问题。但我会让这个问题一周内得不到答案,看看是否有人对此有其他提示,因为我对解决方案不太满意。
The title says everything, but just to be clear I'll add some extra words.
In this case, resize means:
- getting more storage space at the end of the old vbo
- saving the old data at the front
- (hopefully not copying, but at least not on CPU side, meaning the driver should handle this)
EDIT
As to explain some more details and justify my question:
I will store data of (in forehand) unknown size to the VBO but I only know an upper limit that is a very rough estimation (10 - 100x as much or even more in unusual conditions).
Of course I know how much data I stored, when I am done with it, so it would be nice to store data until I find my VBO too small and resize it and then go on storing.
Here is why I don't want to copy(especially not on CPU side):
I am doing all this on the GPU to get interactive frame rates. When I have to copy it is very slow or even not possible, because there is not enough space. Worst of all is to copy the data over the CPU, hence passing everything over the bus, into a new memory region that has sufficient size, then glBufferData
ing the VBO with new size and the new memory region as source. That would be the performance killer.
circumvented
I circumvented the problem with an exact estimation of the needed space. But I will let this question be unanswered for a week to see if someone has another hint on this as I am not very happy with the solution.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为如果不进行复制,您将无法解决此问题,因为调整缓冲区大小的唯一方法是调用glBufferData,并且IMO无法告诉驱动程序保留旧数据。
为了至少不将其复制到 CPU 并再次返回,您可能可以做的是为此目的创建某种辅助 VBO,并直接从 VBO 复制到辅助 VBO(使用 ARB_copy_buffer 扩展名),调整 VBO 的大小并将其内容复制回来。
但我认为最好的方法是预先分配一个更大的缓冲区,因此不需要调整大小,但当然在这种情况下您需要知道大约需要多少额外存储。
I think without doing a copy you won't get around this, because the only way to resize a buffer is to call
glBufferData
and there is IMO no way to tell the driver to keep the old data.What you probably can do to at least not copy it to the CPU and back again, is creating some kind of auxiliary VBO for these purposes and copy directly from the VBO into the auxiliary VBO (using the ARB_copy_buffer extension), resize the VBO and copy its contents back.
But I think the best way is just to allocate a larger buffer beforehand, so the resize is not neccessary, but of course in this case you need to know approximately how much extra storage you need.
几年后重新审视这个问题,随着新版本和扩展的出现,情况发生了一些变化。
GPU端复制
Christian Rau的答案中提到的扩展是自3.1以来的核心,它允许我们复制内容(通过 glCopyBufferSubData )从一个 VBO 到另一个。希望驱动程序在 GPU 端执行此操作!
使用这个函数,我们可以创建一个更大的缓冲区并复制前导数据。这样做的缺点是内存需求加倍,因为我们需要两个缓冲区。
真正的调整大小
好消息是:使用 稀疏缓冲区 更好的解决方案是在地平线上。
有了这个扩展,我们就可以为我们的数据分配一个具有足够空间的虚拟缓冲区,而无需为不需要的空间付费。我们只需“提交”我们物理上想要存储数据的内存区域。这意味着我们可以通过在 VBO 末尾提交新页面来“增长”VBO。
坏消息是:截至当前的 OpenGL 版本 (4.5),这仍然是一个扩展,还不是核心,因此采用它可能是不可能的。您也不应该注意到规范中有一些尚未制定的细节。例如,当前扩展中不允许映射稀疏缓冲区,但可能会在未来版本中添加支持。
如果您有任何相关数据,我很想知道此扩展的可用性。
Revisiting this question after some years, the landscape has changed a bit with newer versions and extensions.
GPU Side Copying
The extension mentioned in Christian Rau's answer is core since 3.1 which allows us to copy contents (via glCopyBufferSubData) from one VBO to another. Hopefully, the driver does this on the GPU side!
Using this function we could create a larger buffer and copy the leading data over. This has the disadvantage of doubling the memory requirements because we need both buffers.
True resizing
The good news is: With sparse buffers an even better solution is on the horizon.
Given this extension we can allocate a virtual buffer with more than enough space for our data without ever paying for the unneeded space. We only have to "commit" the regions of memory we physically want to store data in. This means we can "grow" the VBO by committing new pages at the end of it.
The bad news is: As of the current OpenGL version (4.5) this is still an extension and not yet core, so adopting this might not be possible. You should also not that there are some details in the specification that are not yet worked out. For example, mapping of sparse buffers is disallowed in the current extension but support might be added in future versions.
I would be keen to hear about the availability of this extension if you have any data on that.
假设您支持最新的 OpenGL 标准,VBO 的替代方案可能是将数据存储在纹理中(再次假设您的卡上有足够的内存)。新旧纹理之间的数据复制将在卡上进行,不会影响数据传输。
具体如何实现这一目标取决于您的代码正在做什么。但原则上,您可以使用纹理数据来覆盖绘图调用中的虚拟顶点数据,或者可以使用实例化。这需要大量的思考和返工。
Assuming you have support for a recent OpenGL standard, an alternative to VBOs might be to store your data in textures ( again, assuming you have enough memory on your card ). Copying data between old and new textures would take place on the card and not affect the data transfer.
Exactly how you achieve this depends on exactly what your code is doing. But in principle, you use texture data to overwrite dummy vertex data in your drawing calls, or maybe use instancing. It would require a lot of thought and rework.