为什么 glDeleteBuffers 和 glDeleteVertexArrays 这么慢?

Why are glDeleteBuffers and glDeleteVertexArrays so slow?

在我的程序流程中的某个时刻,我生成了 0 到 300 个网格之间的任意位置,每个网格都是这样的:

public Mesh(float[] vertices, byte[] indices, float[] textureCoordinates)
{
    vao = glGenVertexArrays();
    glBindVertexArray(vao);

    vbo = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(vertices), GL_STATIC_DRAW);
    glVertexAttribPointer(ShaderProgram.VERTEX_ATTRIB, 3, GL_FLOAT, false, 0, 0);
    glEnableVertexAttribArray(ShaderProgram.VERTEX_ATTRIB);

    tbo = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, tbo);
    glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(textureCoordinates), GL_STATIC_DRAW);
    glVertexAttribPointer(ShaderProgram.TCOORD_ATTRIB, 2, GL_FLOAT, false, 0, 0);
    glEnableVertexAttribArray(ShaderProgram.TCOORD_ATTRIB);

    ibo = glGenBuffers();
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, BufferUtils.createByteBuffer(indices), GL_STATIC_DRAW);

    glBindVertexArray(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

当用户按下按钮时,这些网格需要再次删除,所以我 运行 对每个网格对象的清理方法:

public void cleanup()
{
        glDeleteBuffers(vbo);
        glDeleteBuffers(tbo);
        glDeleteBuffers(ibo);
        glDeleteVertexArrays(vao);
}

问题是我试图以 60 fps 运行 删除这些网格对象中的 70 个大约需要 30 毫秒(删除其中的 110 个需要 75 毫秒)。这会造成明显的性能问题,因为一帧最多需要 ~16 毫秒。

这不是处理 VBO 和 VAO 的正确方法吗?我在另一个问题 (glDeleteBuffers slower than glBufferData) 中读到

glGenBuffers and glDeleteBuffers are designed to only be run on initialization and cleanup, respectively. Calling them during runtime is bad.

但我不确定如何在不调用上述函数的情况下摆脱这些 VBO 和 VAO。

我想过将所有要删除的网格添加到队列中,并且每帧只删除其中的几个,慢慢清空队列,但这并不是正确的解决方案。我想到的另一个(可能的)解决方案是使用实例化渲染,但据我所知,当我每帧进行 1000 次以下绘制调用时,非实例化渲染也应该可以正常工作。我的程序在任何给定时间都不会有超过 1000 个网格对象,我什至不确定这会解决我的问题。

更新:除了下面的回答给我指明了正确的方向外,我还发现我实际上并没有删除 ~0-300 个 VBO,而是 48 的一个因子更多的!难怪性能被扼杀了。因此,如果其他人遇到同样的问题,请彻底检查您的代码执行的 glDeleteBuffers 数量。

你在那里遇到了一些心理障碍。您似乎认为 "per mesn: {one vertex attribute == one VBO}",但这不是它应该如何工作的。您应该做的是使用一个单一的大型 VBO,并将其用作您分配块的内存池,每个块都包含一些数据。

因此,您不仅将单个网格的所有顶点属性放入一个公共 VBO 中,还将多个网格放入一个 VBO 中。

另外,您似乎在每次渲染迭代时都在创建和删除 VBO 和 VAO。为什么?网格是否在每一帧之间发生显着变化?如果是这样,那一定是癫痫导致了观看;烘焙到几何数据中的网格变形不需要重新创建缓冲区,您只需用 glBufferSubData.

覆盖数据