Why are glDeleteBuffers and glDeleteVertexArrays so slow? - opengl

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.

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.

Related

OpenGL VAO VBO resize

I have ran into an issue that uploading new content of a different size to the buffer causes VAO to behave unpredictably. Causing my object to look as if the buffer size was incorrectly set.
1) I generate VAO and VBO for an object
glGenVertexArrays(1, &_vao); // Generate 1 VAO
glGenBuffers(1, &_vbo); // Generate 1 VBO
2) Get location of uniform variables and attributes
3) Set the bindings like this:
glBindBuffer(GL_ARRAY_BUFFER, _vbo); // Bind VBO first
glBindVertexArray(_vao); // Bind VAO properties to VBO
{
GLsizei packSize = DIM * sizeof(GLfloat) * 2;
glEnableVertexAttribArray(_position);
glVertexAttribPointer(_position, DIM, GL_FLOAT, GL_FALSE, packSize, (GLvoid*)0);
// And so on ...
}
glBindVertexArray(0); // Unbind VAO
glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBO
4) Then I load my data:
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(float),
_vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
The problem starts when I try to load new data of a different size:
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(float),
_vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
And my buffer size seem to remain the same.
Though, if I define and bind my vao to vbo again (like in 3-d step)
glDeleteBuffers(1, &_vbo);
glGenBuffers(1, &_vbo);
// glBindBuffer... See step 3
// ...
It works.
Is it possible to avoid recreating the new buffer?
What is prefered way of resizing it?
Resize screenshot
Why it behaves such way?
I use OpenGL version 4.2.0 Build 10.18.10.3379
What is prefered way of resizing it?
The preferred way of resizing buffer objects is to not resize them. I'm being serious.
The OpenGL ARB created an entire alternate way of allocating storage for buffers, for the sole purpose of making it impossible to reallocate them later. OK, if you want to be technical, the purpose of immutable storage is to allow persistent mapping, which requires immutability, but if they just wanted persistent mapped buffers, they could have restricted the new API to just those.
Figure out what the maximum size of your data will be (or whatever maximum you want to support), allocate that up front, and just whatever part you want to.
Technically, your code ought to work. By the standard, if you resize a buffer object, things that reference it ought to be able to see the resized storage. But since implementations don't want you to resize them, high-performance applications don't resize them. So that code is rarely tested in real applications, and bugs can linger for quite some time.
Just don't do it.

Is it necessary to bind all VBOs (and textures) each frame?

I'm following basic tutorial on OpenGL 3.0. What is not clear to me why/if I have to bind, enable and unbind/disable all vertex buffers and textures each frame.
To me it seems too much gl**** calls which I guess have some overhead. For example here you see each frame several blocks like:
// do this for each mesh in scene
// vertexes
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glVertexAttribPointer( 0, 3, GL_FLOAT,GL_FALSE,0,(void*)0);
// normals
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, normal_buffer );
glVertexAttribPointer( 1, 3, GL_FLOAT,GL_FALSE,0,(void*)0);
// UVs
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, uv_buffer );
glVertexAttribPointer( 2, 2, GL_FLOAT,GL_FALSE,0,(void*)0);
// ...
glDrawArrays(GL_TRIANGLES, 0, nVerts );
// ...
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
imagine you have not just one but 100 different meshes each with it's own VBOs for vertexes,normas,UVs. Should I really do this procedure each frame for each of them? Sure I can encapsulate that complexity into some function/objects, but I worry about overheads of this gl**** function calls.
Is it not possible some part of this machinery to move from per frame loop into scene setup ?
Also I read that VAO is a way how to pack corresponding VBOs for one object together. And that binding VAO automatically binds corresponding VBOs. So I was thinking that maybe one VAO for each mesh (not instance) is how it should be done - but according to this answer it does not seems so?
First things first: Your concerns about GL call overhead have been addressed with the introduction of Vertex Array Objects (see #Criss answer). However the real problem with your train of thought is, that you equate VBOs with geometry meshes, i.e. give each geometry its own VBO.
That's not how you should see and use VBOs. VBOs are chunks of memory and you can put the data of several objects into a single VBO; you don't have to draw the whole thing, you can limit draw calls to subsets of a VBO. And you can coalesce geometries with similar or even identical drawing setup and draw them all at once with a single draw call. Either by having the right vertex index list, or by use of instancing.
When it comes to the binding state of textures… well, yeah, that's a bit more annoying. You really have to do the whole binding dance when switching textures. That's why in general you sort geometry by texture/shader before drawing, so that the amount of texture switches is minimized.
The last 3 or 4 generations of GPUs (as of late 2016) do support bindless textures though, where you can access textures through a 64 bit handle (effectively the address of the relevant data structure in some address space) in the shader. However bindless textures did not yet make it into the core OpenGL standard and you have to use vendor extensions to make use of it.
Another interesting approach (popularized by Id Tech 4) is virtual textures. You can allocate sparsely populated texture objects that are huge in their addressable size, but only part of them actually populated with data. During program execution you determine which areas of the texture are required and swap in the required data on demand.
You should use vertex array object (generated by glGenVertexArrays). Thanks to it you don't have to perform those calls everytime. Vertex buffer object stores:
Calls to glEnableVertexAttribArray or glDisableVertexAttribArray.
Vertex attribute configurations via glVertexAttribPointer.
Vertex buffer objects associated with vertex attributes by calls to
glVertexAttribPointer.
Maybe this will be better tutorial.
So that you can generate vao object, then bind it, perform the calls and unbind. Now in drawing loop you just have to bind vao.
Example:
glUseProgram(shaderId);
glBindVertexArray(vaoId);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glUseProgram(0);

glBufferData syncronization between drawcalls

I found myself in trouble working with openGl es, in particular feeding the VBO with my data.
Here is the code causing the problem:
void Renderer::DrawCurrentData()
{
glBufferData(GL_ARRAY_BUFFER, (currentVertexIndex) * sizeof(Vertex), vertices, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (currentIndexIndex) * sizeof(GLushort), indices, GL_STREAM_DRAW);
glDrawElements(GL_TRIANGLE_STRIP, currentIndexIndex, GL_UNSIGNED_SHORT, 0);
currentVertexIndex = 0;
currentIndexIndex = 0;
bufVertex = &vertices[currentVertexIndex];
}
It works fine until I have only one draw call per frame, so glBufferData is called only once for each buffer per frame before calling glDrawElements. But if I want to make several draw calls per frame like
frame begin
glBufferData
glDrawElements
.. repeat steps 2,3
presentRenderbuffer
Then I got crash in glBufferData. This probably happens because of buffer is still locked by previous draw call when I try to feed it with new data. I know I should use synchronization here but I'm not sure how to do that in right way.
I tried to orphan the buffer using glBufferData with NULL data pointer before providing new data but it din't help. I got the crash on presenting frame buffer in that case. The question is how to manage buffer feeding with new data while the old data still in use?
I tried to use GL_STREAM_DRAW and GL_DYNAMIC_DRAW both showed same results.

glDeleteBuffers slower than glBufferData

I'm having a bit of performance issue in my iOS/Android game where several VBO's have to be updated every once in a while. After profiling my game it turns out that glDeleteBuffers() takes up to 7ms per VBO update. This of course results in a hiccup when frames normally take only 4 ms to render.
Here's the part where I update my VBO:
Chunk* chunk;
pthread_join(constructionThread, (void**)&chunk);
building = false;
if (vboID)
{
//takes 7 milliseconds
glDeleteBuffers(1, &vboID);
vboID = 0;
}
if (offset)
{
glGenBuffers(1, &vboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
//takes about 1-2 milliseconds, which is acceptable
glBufferData(GL_ARRAY_BUFFER, offset * 4, constructionBuffer, GL_STATIC_DRAW);
}
where offset is an instance variable is basically the size of the new VBO, which is quite variable. vboID speaks for itself, I guess ;)
glGenBuffers and glDeleteBuffers are designed to only be run on initialization and cleanup, respectively. Calling them during runtime is bad.
glBufferData replaces the current buffer data with a new set of data, which automatically changes the size of the buffer. You can safely remove the whole glGenBuffers/glDeleteBuffers thing and move it into initialization and cleanup.
Additionally, you are creating the buffer as a static buffer. This is telling OpenGL that you will almost never change it so it stores it in a way that's quicker to access on the GPU but slower to access from the rest of the system. Try changing GL_STATIC_DRAW to GL_DYNAMIC_DRAW or GL_STREAM_DRAW. More on this here: http://www.opengl.org/wiki/Buffer_Objects#Buffer_Object_Usage

OpenGL structure of VAO/VBO for model with moving parts?

I came from this question:
opengl vbo advice
I use OpenGL 3.3 and will not to use deprecated features. Im using Assimp to import my blender models. But im a bit confused as to how much i should split them up in terms of VAO's and VBO's.
First off a little side question. I use glDrawElements, do that mean i cannot interleave my vertex attributes or can the VAO figure out using the glVertexAttribPointer and the glDrawElements offset to see where my vertex position is?
Main question i guess, boils down to how do i structure my VAO/VBO's for a model with multiple moving parts, and multiple meshes pr. part.
Each node in assimp can contain multiple meshes where each mesh has texture, vertices, normals, material etc. The nodes in assimp contains the transformations. Say i have a ship with a cannon turret on it. I want to be able to roatate the turret. Do this mean i will make the ship node a seperate VAO with VBO's for each mesh containing its attributes(or multiple VBO's etc.).
I guess it goes like
draw(ship); //call to draw ship VAO
pushMatrix(turretMatrix) //updating uniform modelview matrix for the shader
draw(turret); //call to draw turret VAO
I don't fully understand UBO(uniform buffer objects) yet, but it seems i can pass in multiple uniforms, will that help me contain a full model with moveable parts in a single VAO?
first, off VAO only "remembers" the last vertex attribute bindings (and VBO binding for an index buffer (the GL_ELEMENT_ARRAY_BUFFER_BINDING), if there is one). So it does not remember offsets in glDrawElements(), you need to call that later when using the VAO. It laso does not prevent you from using interleaved vertex arrays. Let me try to explain:
int vbo[3];
glGenBuffers(3, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, data0, size0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, data1, size1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, data2, size2);
// create some buffers and fill them with data
int vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// create a VAO
{
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO
glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * sizeof(float), NULL); // this is VAO saved state
glEnableVertexAttribArray(0); // this is VAO saved state
// sets up one vertex attrib array from vbo[0] (say positions)
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // not saved in VAO
glVertexAttribPointer(1, 3, GL_FLOAT, false, 5 * sizeof(float), NULL); // this is VAO saved state
glVertexAttribPointer(2, 2, GL_FLOAT, false, 5 * sizeof(float), (const void*)(2 * sizeof(float))); // this is VAO saved state
glEnableVertexAttribArray(1); // this is VAO saved state
glEnableVertexAttribArray(2); // this is VAO saved state
// sets up two more VAAs from vbo[1] (say normals interleaved with texcoords)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]); // this is VAO saved state
// uses the third buffer as the source for indices
}
// set up state that VAO "remembers"
glBindVertexArray(0); // bind different vaos, etc ...
Later ...
glBindVertexArray(vao); // bind our VAO (so we have VAAs 0, 1 and 2 as well as index buffer)
glDrawElements(GL_TRIANGLE_STRIP, 57, GL_UNSIGNED_INT, NULL);
glDrawElements(GL_TRIANGLE_STRIP, 23, GL_UNSIGNED_INT, (const void*)(57 * sizeof(unsigned int)));
// draws two parts of the mesh as triangle strips
So you see ... you can draw interleaved vertex arrays using glDrawElements using a single VAO and one or more VBOs.
To answer the second part of your question, you either can have different VAOs and VBOs for different parts of the mesh (so drawing separate parts is easy), or you can fuse all into one VAO VBO pair (so you need not call glBind*() often) and use multiple glDraw*() calls to draw individual parts of the mesh (as seen in the code above - imagine the first glDrawElements() draws the ship and the second draws the turret, you just update some matrix uniform between the calls).
Because shaders can contain multiple modelview matrices in uniforms, you can also encode mesh id as another vertex attribute, and let the vertex shader choose which matrix to use to transform the vertex, based on this attribute. This idea can also be extended to using multiple matrices per a single vertex, with some weights assigned for each matrix. This is commonly used when animating organic objects such as player character (look up "skinning").
As uniform buffer objects go, the only advantage is that you can pack a lot of data into them and that they can be easily shared between shaders (just bind the UBO to any shader that is able to use it). There is no real advantage in using them for you, except if you would be to have objects with 1OOOs of matrices.
Also, i wrote the source codes above from memory. Let me know if there are some errors / problems ...
#theswine
Not binding this during VAO initialization causes my program to crash, but binding it after binding the VAO causes it to run correctly. Are you sure this isn't saved in the VAO?
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO
(BTW: sorry for bringing up an old topic, I just thought this could be useful to others, this post sure was! (which reminds me, thank you!!))