【问题标题】:OpenGL 3.3 vertex buffer deletion before frame finished帧完成前的OpenGL 3.3顶点缓冲区删除
【发布时间】:2017-06-07 17:35:35
【问题描述】:

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

情况如下:我有一个所谓的“瞬态”(C++) 对象(从现在开始为 TO),它生成 GL 对象,使用它们将命令排入队列,然后删除它们。

现在考虑我在调用 SwapBuffers() 之前使用了不止一种这种类型。会发生以下情况:

  • TO 1. 生成一个名为 VBO1 的顶点缓冲区,以及一个 VAO1 和其他东西
  • TO 1. 使用 VBO1 调用一些映射/绘图命令
  • TO 1. 删除 VAO1 和 VBO1(因此名称 VBO1 被释放)
  • TO 2. 生成一个顶点缓冲区对象,现在当然与名称 1 同名 (VBO1) 被删除并可用,以及另一个 VAO(可能是 1)
  • TO 2. 使用这个新的 VBO1(不同的顶点位置等)调用其他一些映射/绘图命令
  • TO 2. 删除新的 VBO1
  • SwapBuffers()

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

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

我想在这件事上寻求您的帮助;虽然我知道我不应该在帧中删除/生成对象,但除此之外,这种“错误”机制真的让我感到不安(我的意思是那我怎么能信任 GL?...简短的回答:我不能...)

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

【问题讨论】:

  • 能否添加相关代码以便我们重现此内容?
  • 不幸的是,不,因为它是与工作相关的代码......我唯一可以尝试的是用我现有的一些代码重现它,但这需要时间......我会看到我的可以做。在此期间,请不要等我......
  • 您确定在删除任何内容之前取消映射吗?在交换缓冲区之前调用glFlush() 有帮助吗?没有看到代码,这些都是在黑暗中拍摄的。
  • "我有一个所谓的“瞬态”(C++) 对象(从现在开始为 TO),它生成 GL 对象,使用它们将命令排入队列,然后删除它们。"这是一个想法:停止这样做。 “瞬态”存储应该通过持久地创建一个缓冲区并从中分配部分来完成。不是通过不断创建和销毁缓冲区对象。如果你每帧都调用glGenBuffers,那你就错了。
  • @Ripi2:那么他根本无法渲染场景,并且按照他的方式,对glBufferData 的调用将失败。无论哪种方式,它都失败了。但是这种方式消除了对 API 的不当使用。 “或者数据缓冲区在每一帧中都会改变它们的大小?”这就是为什么你从主缓冲区对象中“sub-allocate”。

标签: opengl vertex-buffer


【解决方案1】:

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

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

对于我的瞬态顶点,我有一大块内存用于写入存储,并跳过 VBO 提交。我不知道您的设置是什么或您正在推动多少个顶点,但如果您 1) 重新生成每一帧或 2) 推动少量顶点,您可能不会从 VBO 中受益。无论是否使用 VBO,都绝对可以进行性能测试。

【讨论】:

  • 正是...我的代码也是多线程的(因此采用了这种方法)。您的建议似乎与我的想法几乎相同(使对象不那么短暂),所以最后我将实现一个管理器类。
【解决方案2】:

我找到了问题的原因,我认为值得一提(这样其他开发人员就不会陷入同样的​​困境)。实际的问题是 VAO,或者更准确地说是 VAO 的缓存

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

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

  • VBO1 已创建,VAO1 已创建
  • VAO1 已缓存在管道缓存中
  • VBO1 已删除,但仅释放名称,而不释放对象
  • glGenBuffers() 在名称可用时再次返回 1
  • 但缓存中的 VAO1 仍然引用旧的 VBO1
  • 驱动程序很困惑,不允许我修改新的 VBO1

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

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

欢迎来到 OpenGL 的世界...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多