帧完成前的 OpenGL 3.3 顶点缓冲区删除

OpenGL 3.3 vertex buffer deletion before frame finished

这是一个高级 OpenGL 问题,待定。它似乎更像是一个驱动程序错误。我知道标准明确指出,删除对象只会删除它的名称,因此生成器函数可以 return 相同的名称。但是目前还不清楚如何处理这个...

情况如下:我有一个所谓的 "transient" (C++) 对象(从现在开始为 TO),它生成 GL 对象,使用它们对命令进行排队,然后删除它们。

现在想想,在我调用 SwapBuffers() 之前,我使用了不止一种此类。发生以下情况:

结果是:只有 TO 1. 执行的修改有效。一言以蔽之:我想渲染一个三角形,然后渲染一个正方形,但我只得到了三角形。

解决方法:不删除 VBO,因此我在 TO 2 中获得了一个新名称。(VBO2)

在这件事上我想请你帮忙;虽然我知道我 不应该 delete/generate 对象中间帧,但除此之外,这个 "buggy" 机制 真的打扰我了(我的意思是我怎么能相信 GL?...简短的回答:我不能...)

(旁注:我从事 3D 图形编程已有 12 年了,但这件事真的让我毛骨悚然...)

我的多线程渲染代码也有类似的问题。我为渲染命令使用双缓冲系统,所以当我删除一个对象时,它可能会在下一帧中使用。

简而言之,TO 不应该直接删除 GL 对象。它需要将句柄提交给管理器 queue 以便在帧之间删除。使用我的双缓冲,我添加了一个小计时器在释放前倒计时 2 帧。

对于我的临时版本,我有一大块内存可以写入存储,并跳过 VBO 提交。我不知道你的设置是什么或你推了多少顶点,但如果你 1) 重新生成每一帧或 2) 推一小部分顶点,你可能不会从 VBO 中受益。使用和不使用 VBO 的绝对性能测试。

我找到了问题的原因,我觉得值得一提(以免其他开发者掉进同样的坑)。实际问题是 VAO,或者更准确地说是 VAO 的缓存

在 Metal 和 Vulkan 中,输入布局完全独立于实际使用的缓冲区:您只需指定缓冲区所在的绑定点(位置)。

但在 OpenGL 中不是...VAO 实际上持有对在其创建期间绑定的顶点缓冲区的强引用。因此发生了以下事情:

  • 已创建 VBO1,已创建 VAO1
  • VAO1 已缓存在管道缓存中
  • VBO1 被删除,但只有名称被释放,对象没有被释放
  • glGenBuffers() returns 1 再次因为名称可用
  • 但缓存中的 VAO1 仍然引用旧的 VBO1
  • 驱动搞糊涂了,不让我修改新的VBO1

解决方案...好吧...现在,当顶点缓冲区被删除时,我会删除所有引用该缓冲区的缓存管道。

从长远来看:我将为输入布局维护一个单独的缓存(即使它是管道状态的一部分),并将瞬态对象进一步向上移动,使其变得不那么瞬态。

欢迎来到 OpenGL 的世界...