Search code examples
opengllwjglvbovao

Why are glDeleteBuffers and glDeleteVertexArrays so slow?


At some point in my program's flow I generate anywhere from between 0 and 300 meshes, each of them like so:

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);
}

When the user presses a button these meshes need to be deleted again, so I run a cleanup method on each of these mesh objects:

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

The problem is that I am trying to run at 60 fps and deleting 70 of these mesh objects takes about 30 ms (and deleting 110 of them takes 75 ms). This creates a noticable hiccup in performance because one frame should take at most ~16 ms.

Is this not the right way to dispose of VBO's and VAO's? I read in a different question (glDeleteBuffers slower than glBufferData) that

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

but I am not sure how I can get rid of these VBO's and VAO's without calling the above functions.

I have thought of adding all meshes-to-be-deleted to a queue and only deleting a couple of them each frame, slowly emptying the queue, but that does not feel like the right solution. Another (possible) solution I have thought of is to use instanced rendering, but, as far as I understand, when I make sub 1000 draw calls per frame, non-instanced rendering should work fine too. My program will never have much more than 1000 Mesh objects at any given time, and I am not even sure this will solve my problem.

UPDATE: Besides from the below answer pointing me in exactly the right direction, I also discovered I wasn't actually deleting ~0-300 VBO's, but a factor of 48 more! No wonder performance was killed. So if anyone else ever has the same problem, thoroughly check the amount of glDeleteBuffers your code is performing.


Solution

  • You've hit some mental roadblock there. You seem to think that "per mesn: {one vertex attribute == one VBO}", but that's not how its supposed to work. What you should do is use one single, large VBO and use as a pool of memory from which you allocate chunks, each holding some data.

    So you put not only all the vertex attributes of a single mesh into a common VBO, you also put several meshes into a single VBO.

    Also it seems like you're creating and deleting your VBOs and VAOs on every single rendering iteration. Why? Do the meshes dramatically change between every frame? If that is so, that must be epilepsy inducing to watch; mesh deformations baked into the geometry data don't require recreation of the buffers, you just overwrite the data with glBufferSubData.