Is it required that we should unbind a buffer object before deleting it? If I had bound it in a VAO and deleted it without unbinding (binding to 0), what will happen? Will the reference still exist?
public void dispose()
{
glBindVertexArray(0);
glDeleteVertexArrays(vaoID);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(vboVertID);
glDeleteBuffers(vboColID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDeleteBuffers(eboID);
}
Is it a good or a bad practice to unbind before deletion?
Is it necessary?
No.
Is it a good idea?
Possibly, but not in your current pseudo-code.
The only time you would want to manually unbind a resource in GL prior to deletion is if you have it bound in a separate context. That is because one the criteria for actually freeing the memory associated with a GL resource is that it have a reference count of 0. glDelete* (...) only unbinds an object from the current context prior to putting it on a queue of objects to free.
If you delete it while a VAO that is not currently bound holds a pointer to this buffer, or if it is bound in a completely different OpenGL context from the one you call glDelete* (...) in, then the reference count does not reach 0 before glDelete* (...) finishes. As a result, the memory will not be freed until you actually unbind it from or destroy all VAO / render contexts that are holding references. You will effectively leak memory until you take care of all the dangling references.
In short, glDelete* (...) will always unbind resources from the current context and reclaim any names for immediate reuse, but it will only free the associated memory if after unbinding it the reference count is 0.
In this case, unbinding is completely unnecessary because you are doing so in the same context you call glDeleteBuffers (...) from. This call implicitly unbinds the object you are deleting, so you are doing something redundant. What is more, you already deleted your VAO prior to calling glDeleteBuffers (...) -- when that VAO was deleted, it relinquished all of its pointers and thus decremented the reference count to your buffer.
Official documentation (https://www.opengl.org/sdk/docs/man/html/glDeleteBuffers.xhtml) says:
glDeleteBuffers deletes n buffer objects named by the elements of the array buffers. After a buffer object is deleted, it has no contents, and its name is free for reuse (for example by glGenBuffers). If a buffer object that is currently bound is deleted, the binding reverts to 0 (the absence of any buffer object).
As for VAO - https://www.opengl.org/registry/specs/ARB/vertex_array_object.txt
(2) What happens when a buffer object that is attached to a non-current
VAO is deleted?
RESOLUTION: Nothing (though a reference count may be decremented).
A buffer object that is deleted while attached to a non-current VAO
is treated just like a buffer object bound to another context (or to
a current VAO in another context).
Related
I've read that a VBO (Vertex Buffer Object) essentially keeps a reference count, so that if the VBO's name is given to glDeleteBuffers(), it isn't truly dismissed if a living VAO (Vertex Array Object) still references it. This behavior is similar to "Smart Pointers" newer languages are increasingly adopting. But to what extent this is true and can be designed around, and if it applies to IBO (Index Buffer Object) as well, I haven't been able to find any information on.
If a VBO is kept alive by a VAO that references it and I don't intend to update it or use it beyond the VAO's death, I think the best play is to destroy my reference to it. Is it proper to do so? And can I do the same with an IBO?
Objects can be attached to other objects. So long as an object is attached to another object, the attached object will not actually be destroyed by calling glDelete*. It will be destroyed only after it is either unattached or the object it is attached to is destroyed as well.
This isn't really something to worry about all that much. If you glDelete* an object, you should not directly use that name again.
let's say that I have the vbo id stored in an int, and I want to resize that buffer; what would I do?
1st choice: use glbufferdata function after binding the buffer.
2nd choice:.use gldeletebuffers then regenerate the buffer and use glbufferdata function after binding the buffer.
So my question is does glbufferdata deallocate the buffer by it self or it didn't?
Just call glBufferData. The glDeleteBuffers / glGenBuffers calls are unnecessary.
Think about it this way: glBufferData creates a new buffer. The glGenBuffers function creates a new name (integer) for a bufffer.
You don't need to deallocate the buffer yourself… not that OpenGL gives you a way to do that. Your OpenGL implementation will do that for you after it is done using the data in the buffer, as long as you don't hold a reference to it.
Is it legal OpenGL to re-allocate the storage of a buffer object with a different size? Yes. Is it a good idea? Well, consider this.
OpenGL has a new(ish) way to allocate storage for a buffer: glBufferStorage. It allocates "immutable" storage. So called because, once allocated, you cannot re-allocate it.
The people behind OpenGL would not have added this immutable buffer allocation method if they thought that reallocating the storage of a buffer object was a good idea.
Consider the following OpenGL code snippet:
GLuint vao;
glCreateVertexArrays(1, glBindVertexArray(&vao));
I'm under the impression that what this code does is
Creates a pointer, of type GLuint, that will eventually point to an OpenGL Vertex Array Object. The name of this pointer is vao.
Indirectly allocates memory through OpenGL for the actual Vertex Array Object (i.e., no use of malloc in C or new in C++). The way that this is done is through the function glCreateVertexArrays. This function also makes the pointer vao point to the Vertex Array Object.
Is my understanding correct? If so, in (1), why is the type of the pointer GLuint and not explicitly defined as a pointer type (for example with * in C/C++ or with the OpenGL type GLintptr)?
This code is invalid, glBindVertexArray returns void so you cannot pass its return value as a parameter to glCreateVertexArrays, because there is none.
The correct way to create a VAO, as per OpenGL 4.5 profile, is:
GLuint vao;
glCreateVertexArrays(1, &vao);
As per the meaning of vao and why its type is GLuint: it is not a pointer. It is an opaque value that is used internally to locate the VAO inside the OpenGL implementation tables. The driver may allocate memory on both, the CPU and/or GPU for storing the state associated with the VAO. It is a complex state with quite a lot of book-keeping, which is much more involved than malloc or new. (In particular malloc can't be used to allocate GPU memory.)
Let's say I allocate memory for a uniform buffer, like so:
GLuint length(0x1000);
GLuint myBuffer;
glGenBuffers(1, &myBuffer);
glBindBuffer(GL_UNIFORM_BUFFER, myBuffer);
glBufferData(GL_UNIFORM_BUFFER, length, NULL, GL_STATIC_DRAW);
When I am done using the buffer, I would like to make sure that the memory is available again for other buffers. Is it sufficient to call glDeleteBuffers(1,&myBuffer) to achieve that? Because my gut feeling tells me there should be a call symmetrical to glBufferData for that
(like glInvalidateBufferData in OpenGL 4), but nothing of the kind is mentioned in the documentation for glBufferData at all (http://www.opengl.org/sdk/docs/man/xhtml/glBufferData.xml)
Not to be a buzz kill, but container objects such as Vertex Array Objects significantly complicate this discussion.
Normally, when you delete a buffer object two key things happen that allow the memory to be reclaimed:
Its name (GLuint ID) is freed up for reuse immediately
The object is unbound from the currently active context
There is a hidden caveat that needs to be observed:
The data store is not actually freed until there are no remaining references to the object in any context.
When you delete a Vertex Buffer Object that is bound to a Vertex Array Object and that Vertex Array Object is not currently bound, the behavior discussed in bullet point 2 does not occur. What happens is the name is freed up, but the VAO continues to reference both the name (which is now invalid) and the data store (which continues to exist). The memory for the buffer object will not be reclaimed until this Vertex Array Object is deleted, or the binding is changed so that it no longer references the original buffer object.
For a more authoritative explanation of the above, I suggest you read Section 5.1.2 and Section 5.1.3 of the OpenGL 4.4 core spec. I will list the most relevant parts of both below.
5.1.2 Automatic Unbinding of Deleted Objects
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. If the object binding was established with other related state (such as a buffer range in BindBufferRange or selected level and layer information in FramebufferTexture or BindImageTexture), that state is not affected by the automatic unbind. Bind points in other contexts are not affected. Attachments to unbound container objects, such as deletion of a buffer attached to a vertex array object which is not bound to the context, are not affected and continue to act as references on the deleted object, as described in the following section.
5.1.3 Deleted Object and Object Name Lifetimes
[...]
The underlying storage backing a deleted object will not be reclaimed by the GL until all references to the object from container object attachment points, context binding points, or views are removed.
NOTE: This behavior applies to all container objects in OpenGL, memory is not reclaimed until all references to a resource are eliminated. Familiarizing yourself with the necessary conditions (see: 5.1.2) for references to be removed will serve you well in the long-run.
glDeleteBuffers marks the selected buffers for deletion and deallocation, which gets done as soon as no part of OpenGL any longer needs the buffer's data internally. For all practical means glDeleteBuffers frees the buffers.
Question 1
Do vertex buffer objects created under a certain VAO deleted once that VAO is deleted?
An example:
glGenBuffers(1, &bufferObject);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, bufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(someVertices), someVertices,
GL_STATIC_DRAW);
glEnableVertexAttribArray(positionAttrib);
glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 0, NULL);
When later calling glDeleteVertexArrays(1, &VAO);, will bufferObject be deleted as well?
The reason I'm asking is that I saw a few examples over the web that didn't delete those buffer objects.
Question 2
What is the maximum amount of memory that I can allocate for buffer objects? It must be system dependent of course, but I can't seem find an estimation for it. What happens when video RAM isn't big enough? How would I know?
1: Buffer objects are not "created under" VAOs. Buffer object state is not part of VAO state. VAOs can reference buffer objects, but that association is only made by calling glVertexAttribPointer (or other *Pointer calls). Simply binding a buffer to GL_ARRAY_BUFFER does not put it in the VAO. You can bind buffers to that target without a VAO being bound. This is legal code:
glGenBuffers(1, &bufferObject);
glBindBuffer(GL_ARRAY_BUFFER, bufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(someVertices), someVertices,
GL_STATIC_DRAW); //Creates the buffer storage.
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glEnableVertexAttribArray(positionAttrib);
glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 0, NULL); //Uses whatever is bound to GL_ARRAY_BUFFER
Note that this is not true of GL_ELEMENT_ARRAY_BUFFER. That binding is directly part of VAO state. So you need a VAO bound before you can bind to that target.
However, binding to a target is not creation. You can bind a buffer to GL_TRANSFORM_FEEDBACK_BUFFER, create it's storage with glBufferData, and then bind it later for use with GL_ARRAY_BUFFER. Or as a GL_ELEMENT_ARRAY_BUFFER.
As to the main thrust of your question, no. The destruction of a VAO will not destroy the buffer objects that it references.
2: There is no standard OpenGL function to detect the amount of available resources. If you attempt to create storage and the implementation is out of resources, you will get a GL_OUT_OF_MEMORY error.
Answer 1
It depends. If you called glDeleteBuffers before, it will be deleted when you delete the VAO. If not, it won't. The VAO holds a reference to the VBO, and so does your application after calling glGenBuffers. Both references need to be released before the VBO is deleted.
Answer 2
There's (afaik) no way to query the maximum amount you can allocate. However, according to the reference documentation, glBufferData will emit GL_OUT_OF_MEMORY if a buffer can not be allocated.