Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I call glDeleteBuffers()?

Tags:

opengl

I have the following working code, however I'm not convinced that I'm calling glDeleteBuffers in a safe way. In practice it's working (for now at least) but from what I've been reading I don't think it should work.

GLuint vao_id;
glGenVertexArrays(1, &vao_id);
glBindVertexArray(vao_id);

GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);

    //Alternate position <<----

//Unbind the VAO
glBindVertexArray(0);

//Current position <<----
glDeleteBuffers(1, &VBO);

I am currently calling glDeleteBuffers straight after unbinding the VAO. I have tried calling it in the alternative position marked - immediately after I have set the attribute pointer. This however caused a crash - my guess is this was because when I made the draw call there was no data to be drawn because I'd deleted it.

The thing that confuses me is that it works as I currently have it. I'm worried that a) I don't quite understand what happens when the buffer is delete and b) that it only works by chance and could unexpectedly break.

As far as I understand calling glDeleteBuffers deletes the data so there shouldn't be any data to draw - but there is. So my other thought was that when I re-bind the VAO the data is restored, although that didn't make much sense to me because I can't reason where the data would be restored from.

Can someone let me know if I am using glDeleteBuffer correctly? and if not where it should be called (I'm guessing once there is no need for the data to be drawn any more, probably at the end of the program).

like image 295
Francis Avatar asked Jan 14 '15 06:01

Francis


2 Answers

What you're seeing is well defined behavior. The following are the key parts of the spec related to this (emphasis added).

From section "5.1.2 Automatic Unbinding of Deleted Objects" in the OpenGL 4.5 spec:

When a buffer, texture, or renderbuffer object is deleted, it is unbound from any bind points it is bound to in the current context, and detached from any attachments of container objects that are bound to the current context, as described for DeleteBuffers, DeleteTextures, and DeleteRenderbuffers.

and "5.1.3 Deleted Object and Object Name Lifetimes":

When a buffer, texture, sampler, renderbuffer, query, or sync object is deleted, its name immediately becomes invalid (e.g. is marked unused), but the underlying object will not be deleted until it is no longer in use.

A buffer, texture, sampler, or renderbuffer object is in use if any of the following conditions are satisfied:

the object is attached to any container object

...

The VAO is considered a "container object" for the VBO in this case. So as long as the VBO is referenced in a VAO, and the VAO itself is not deleted, the VBO stays alive. This is why your version of the code with the glDeleteBuffers() at the end works.

However, if the VAO is currently bound, and you delete the VBO, it is automatically unbound from the VAO. Therefore, it is not referenced by the VAO anymore, and deleted immediately. This applies to the case where you call glDeleteBuffers() immediately after glVertexAttribPointer().

In any case the id (aka name) becomes invalid immediately. So you would not be able to bind it again, and for example modify the data.

There are some caveats if you dig into the specs more deeply. For example, if you delete a buffer, and it stays alive because it is still referenced by a VAO, the name of the buffer could be used for a new buffer. This means that you basically have two buffers with the same name, which can result in some confusing behavior.

Partly for that reason, I personally wouldn't call glDelete*() for objects that you want to keep using. But others like to call glDelete*() as soon as possible.

like image 87
Reto Koradi Avatar answered Oct 05 '22 23:10

Reto Koradi


I would like to highlight in a separate answer what @Onyxite has pointed out in the first comment of the accepted answer. This has driven me nuts and I have been hours tracking down this issue.

AMD Windows drivers have a BUG where if you delete a VBO after unbinding all its referenced VAOs, it will DELETE the buffer and its underlying object, so nothing will be drawn. This may result in a black screen, or OpenGL not drawing that part of the VAO.

So, taking this in consideration, the answer to the question would be:

Even when it is correct as per the OpenGL specification, you should not call glDeleteBuffers() until you are going to actually delete the VAOs referencing that buffer.

So you should follow Reto Korandi's advice and do not call glDelete*() for objects that you want to keep using.

like image 25
manueldeprada Avatar answered Oct 05 '22 23:10

manueldeprada