Sample code:
1. glGenBuffers(1, &VboId);
2. glBindBuffer(GL_ARRAY_BUFFER, VboId);
3. glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
4. glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
So we generate a generic VBO handle, and then we bind it using "GL_ARRAY_BUFFER". Binding it seems to have 2 purposes:
We must bind the buffer before we can copy data to the GPU via glBufferData
We must bind the buffer before we can add attributes to it via glVertexAttribPointer
And I think those are the only 2 times you need to bind the VBO. My question is, is there any scenario in which target (GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, or GL_PIXEL_UNPACK_BUFFER) would be different on lines 2 and 3? Or we would want to rebind it to a different target before line 4?
Can we bind multiple buffer targets to a single VBO?
You do not bind targets to a buffer object. Targets are locations in the OpenGL context that you can bind things (like buffer objects) to. So you bind buffer objects to targets, not the other way around.
A buffer object (there is no such thing as a VBO. There are simply buffer objects) is just a unformatted, linear array of memory owned by the OpenGL driver. You can use it as source for vertex array data, by binding the buffer to GL_ARRAY_BUFFER and calling one of the gl*Pointer functions. These function only work with the buffer currently bound to GL_ARRAY_BUFFER. You can use them as the source for index data by binding them to GL_ELEMENT_ARRAY_BUFFER and calling one of the glDrawElements functions.
The functions used to modify a buffer objects contents (glBufferData, glMapBuffer, glBufferSubData, etc) all specifically take a target for their operations to work on. So glBufferData(GL_ARRAY_BUFFER, ...) does its stuff to whatever buffer is currently bound to GL_ARRAY_BUFFER.
So there are two kinds of functions that affect buffer objects: those that modify their contents, and those that use them in operations. The latter are specific to a source; glVertexAttribPointer always uses the buffer currently bound to GL_ARRAY_BUFFER. You can't make it use a different target. Similarly, glReadPixels always uses the buffer bound to GL_PIXEL_PACK_BUFFER. And so forth. If a function does stuff with buffer objects but doesn't take a target as a parameter, then its documentation will tell you which target it looks for its buffer from.
Note: Vertex arrays are kinda weird. The association between a vertex attribute and a buffer object is made by calling glVertexAttribPointer. What this function does is set the appropriate data for that attribute, using the buffer object that is currently bound to GL_ARRAY_BUFFER. By "currently bound", I mean bound at the time this function is called. So immediately after calling this function, you can call glBindBuffer(GL_ARRAY_BUFFER, 0), and it will change nothing about what happens when you go to render. It will render just fine.
In this way, you can use different buffer objects for different attributes. The information will be retained until you change it with another glVertexAttribPointer call for that particular attribute.
Related
My question relates to how allocations are handled in opengl.
If you create a buffer object using glGenBuffers(1, &id) then let's say populate it with a mesh's vertex data using glBindBuffer(GL_ARRAY_BUFFER, id) and glBufferData(GL_ARRAY_BUFFER, ...). The question I have now is : will the data I uploaded be bound to the GL_ARRAY_BUFFER tag specifically? So could I for example later use glBindBuffer(GL_UNIFORM_BUFFER, id) and use that data as a uniform buffer or does changing the associated target cause memory to be freed forcing me to use glGetBufferSubData to retrieve and re-upload the data now bound to the GL_UNIFORM_BUFFER tag? It seems intuitive that a buffer object keeps it's data as long as it is not deleted and that the target parameter is more to hint to the gpu where the data might be more optimally stored and what operations might be done with the buffer. What effects does doing something like this have on the state of opengl and is there a recommended alternative other than duel-uploading or re-uploading.
The buffer target does not have any effect on the content of a buffer. A buffer itself doesn't even know to which target it is bound. You can at any time bind the buffer to any other target and it can even be bound to multiple targets at the same time.
Buffer targets are only used by the API to determine which buffer a command should operate on. For example, glBufferData requires you to bind the buffer to the same target that you pass to it. But it doesn't really matter which target you are using. Some other commands, like glVertexAttribPointer expect a buffer to be bound to a certain target, but also here the binding doesn't alter/modify the buffer itself.
Note, that Direct State Access (DSA) methods which are core since OpenGL 4.5 do not use binding targets at all while providing the same functionality as the stateful methods.
Since binding a buffer to a target such as GL_ARRAY_BUFFER will modify the state of any bound vertex array object, writing a buffer safely can be tricky. The easiest solution seems to be to use a buffer target such as GL_COPY_WRITE_BUFFER which does not affect VAO state.
void write_buffer(GLint name, int size, const void* data)
{
// error handling omitted for clarity...
glBindBuffer(GL_COPY_WRITE_BUFFER, name);
glBufferData(GL_COPY_WRITE_BUFFER, size, data, GL_STATIC_DRAW);
}
This has the advantage of being safe to call without regard for which OpenGL context is current (assuming you are sharing state) and which VAO is currently bound.
However, according to the OpenGL API reference for glBindBuffer the initial target a buffer is bound to may be used as an optimization hint for how the buffer is stored internally:
Once created, a named buffer object may be re-bound to any target as often is needed. However, the GL implementation may make choices about how to optimize the storage of a buffer object based on its initial binding target.
This means that the above function may hinder optimization if the buffer name has not previously been bound to the appropriate eventual target.
The only way I can think of to avoid this penalty is to manually bind the buffer to the desired target immediately after creation and then restore the original binding:
GLint create_array_buffer()
{
GLint original, name;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &original);
glGenBuffers(1, &name);
glBindBuffer(GL_ARRAY_BUFFER, name);
glBindBuffer(GL_ARRAY_BUFFER, original);
return name;
}
Is there a better way to create and fill a buffer safely (with regard to VAOs)? The process should:
Preserve the optimization hint of the first binding target
Not disturb the state of any bound VAO
Not read state, change state and restore state like I do above
Just binding to GL_ARRAY_BUFFER does not affect a bound VAO. Only when glVertexAttribPointer is called is the binding state read and put into the VAO. Rebinding the GL_ELEMENT_ARRAY_BUFFER does affect the bound VAO state.
This means you are free to change the binding of GL_ARRAY_BUFFER as long as you make sure to bind the correct buffer before calling glVertexAttribPointer.
When creating a Buffer and setting its data, it is required to bind it first to a target and then populate the buffer bound to that target with some data:
GLenum target = GL_ARRAY_BUFFER;
glGenBuffers(1, &bufferId);
glBindBuffer(target, bufferId);
glBufferData(target, m_capacity*sizeof(value_type), m_data, GL_STREAM_DRAW);
glBindBuffer(target, 0);
But to my understanding it does not really matter if I a buffer that was populated on the GL_ARRAY_BUFFER target is later used on e.g. the GL_UNIFORM_BUFFER target. But if this is the case why do we need the target to populate the buffer and why is the signature of glBufferData not:
void glBufferData( GLint bufferId,
GLsizeiptr size,
const GLvoid * data,
GLenum usage);
Is that just a historical reason or because opengl is a statemachine or do I miss something and the target has an other purpose there.
This is a common OpenGL API thing - most of the work with OpenGL objects (textures, buffers, ...) is done via binding them to a specific target and then using this target to refer to currently bound object (more on this here). Unfortunatelly, I do not know the exact reason for this, but it seems to appear historical now - I've seen some proposed extension for direct object access via object id's (UPD: user ratchet freak says that it is direct_state_access extension, core in 4.5).
The documentation on glBindBuffer says that
When a buffer object is bound to a target, the previous binding for that target is automatically broken.
I'd suppose that changing a buffer's binding type and expecting the buffer's state to stay preserved is not a good idea.
UPDATE
From OpenGL wiki
The target​ defines how you intend to use this binding of the buffer object. When you're just creating and/or filling the buffer object with data, the target you use doesn't technically matter.
So, it seems that the target matters only on how you use the buffer, and you can safely bind it to any random type and fill it with data, but it still seems to be a bad practice.
To use glBufferData, you need some way of indicating the target of the data you are uploading. The target parameter (the first one), lets this call know the destination for your data. If your only aim is to upload the data and then unbind, as you said, it doesn't really matter which buffer binding you use. You are free to bind that buffer to any other binding at a later time.
However, it quite common to setup vertex attributes during GL_ARRAY_BUFFER data initialization time as well (with glVertexAttribPointer/glEnableVertexArray), which might be another reason to use GL_ARRAY_BUFFER binding over any other arbitrary binding. Also, if you intend to actually use the buffer data you are uploading in a subsequent draw call, and don't need to break the binding, it is more efficient to leave the binding in place.
I've been learning OpenGL for three days and I can get stuff done but I feel like copy pasting without knowing what I'm doing. I seriously think I lack basic understanding about when is exactly what (VBO, attributes, ...) bound to a Vertex Array Object (VAO), and haven't found any resources that clarify these aspects in detail.
In particular, these are some of my issues. If I create a VAO:
GLuint vao;
glGenVertexArrays(1, &vao);
can anything get bound to it before I bind the VAO? (if I create a VBO now, is it bound to the VAO?)
glBindVertexArray(vao);
After binding the VAO, if I create a VBO:
GLuint vbo;
glGenBuffers(1, &vbo);
is it bound to the VAO? Or does it happen when I bind it?
glBindVertexArray(vbo);
Or maybe when I copy something to it?
If I get an attribute location:
att = glGetAttribLocation(program_id, "name");
is it bound to the VAO? Or does it happen after enabling it:
glEnableVertexAttribArray(att);
... or after setting it:
glVertexAttribPointer(att, ...);
?
I guess EBOs behave just like VBOs, so I hope the same "rules" apply.
Uniforms should behave like globals, so they shouldn't be affected by VAOs at all.
Now, about unbinding:
If I "bind" a VBO to a VAO, and then unbind the VBO, does it get detached from a VAO?
If I have a VBO that is bound to multiple VAOs, what happens when I unbind that VBO?
And about freeing resources:
What happens when I delete an VBO? Does it get deleted from all the VAOs ? Or do they still have "dangling references" to that VBO?
And about programs:
IIUC I can reuse VBOs between programs. However, if VAOs bind attributes and VBOs, and attributes take a program parameter, can I reuse VAOs between programs? Why do attributes take a program parameter at all?
And about debugging:
Is there a way to pretty print the OpenGL state machine? I would like a way to know the programs that have been linked, with which shaders, which VAOs are there, which VBOs are bound to which VAOs, which attributes are bound to which VAOs and VBOs, have they been set? are they enabled? which uniforms are there...
And about drawing calls:
Suppose someone gives me a VAO, and I have to draw it. Is there a way to know if I should be calling glDrawArrays or glDrawElements? Can I query somehow this information from a VAO? Maybe along with the sizes of my VBOs stored in there?
That's a lot of sub-questions. But since this an area that is often confusing newer OpenGL enthusiasts, let me try and provide some content that will hopefully help more people. I will intentionally skim over some details, like vertex attributes that are not sourced from a buffer, to avoid writing a book here.
The key thing to understand is that a VAO is a collection of state. It does not own any data. It's VBOs that own vertex data. A VAO, on the other hand, contains all the state used to describe where a draw call gets its vertex attributes from. This includes, for each attribute:
If it's enabled.
Which buffer the attribute is stored in.
At which offset in the buffer the data starts.
The spacing between subsequent attributes (aka the stride).
The type of the data.
The number of components.
Plus, once only:
Which element array buffer is bound.
Mapping this to API calls, the following calls change state tracked by the currently bound VAO:
glEnableVertexAttribArray(...)
glDisableVertexAttribArray(...)
glVertexAttribPointer(...)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...)
Note that this does not include the current binding of GL_ARRAY_BUFFER. The buffer used for each attribute is tracked indirectly, based on which buffer was bound when glVertexAttribPointer() is called for the specific attribute.
This should set the basis for the specific sub-questions:
If I create a VAO, can anything get bound to it before I bind the VAO?
No. The VAO needs to be bound before you can modify any state stored in it.
(if I create a VBO now, is it bound to the VAO?)
No. You can bind a VBO before you bind a VAO, and fill the VBO with data using glBufferData(). A VBO is essentially just a dumb data container. But any kind of vertex attribute setup tracked in the VAO can only be done after the VAO is bound.
If I get an attribute location, is it bound to the VAO?
No, glGetAttribLocation() only does what the name suggests, which is get an attribute location. It does not change any state. You will use the attribute locations for calls like glEnableVertexAttribArray() and glVertexAttribPointer().
Or does it happen after enabling it ... or after setting it
The association of an attribute with a given VBO is established when you call glVertexAttribPointer() while the given VBO is bound.
I guess EBOs behave just like VBOs, so I hope the same "rules" apply.
Mostly, but not entirely. The GL_ELEMENT_ARRAY_BUFFER binding is part of the state stored in the VAO. This makes sense because there is only one element array buffer used for a draw call (while the vertex attributes could come from multiple different array buffers), and there is no separate call that specifies "use the index data from the currently bound element array buffer", like glVertexAttribPointer() specifies "use the vertex data from the currently bound array buffer". Instead that happens implicitly when you call glDrawElements(). Therefore, the element array buffer needs to be bound at the time of the draw call, and this binding is part of the VAO state.
Uniforms should behave like globals, so they shouldn't be affected by VAOs at all.
Correct. Uniforms are associated with shader programs, not VAOs.
If I "bind" a VBO to a VAO, and then unbind the VBO, does it get detached from a VAO?
No. I believe this is already covered by the explanations above.
If I have a VBO that is bound to multiple VAOs, what happens when I unbind that VBO?
Since nothing happens with one VAO, still nothing with multiple VAOs.
What happens when I delete an VBO? Does it get deleted from all the VAOs ? Or do they still have "dangling references" to that VBO?
This is one of the darker corners of OpenGL. If you can recite the exact deletion rules for all object types (they are not all the same), you have reached the advanced level... In this case, the VBO is automatically unbound from the currently bound VAO, but not from other VAOs that are not currently bound. If other VAOs have references to the VBO, the VBO will stay alive until all those bindings are broken, or the VAOs deleted.
However, if VAOs bind attributes and VBOs, and attributes take a program parameter, can I reuse VAOs between programs?
Yes, you can use a VAO for multiple programs. Program state and VAO state are independent. The vertex attribute location in the program specifies which vertex attribute is used to source the values for each attribute/in variable in the vertex shader.
As long as multiple programs use the same locations for the same attributes, you can use the same VAO. To make this possible, you may want to specify the attribute location for each program by using the layout (location=...) directive the vertex shader, or by calling glBindAttribLocation() before linking the program.
Is there a way to pretty print the OpenGL state machine?
There are glGet*() calls that let you retrieve pretty much all of the current OpenGL state. Not convenient, but it's all available. Many platforms/vendors also provide developer tools that allow you to look at OpenGL state at a given point in your program execution.
Suppose someone gives me a VAO, and I have to draw it. Is there a way to know if I should be calling glDrawArrays or glDrawElements?
This is an unusual scenario. Most of the time, you create the VAO, so you know how to draw it. Or if somebody else created it, you would ask them to draw it. But if you really need it, you can get the currently bound element array buffer with glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ...).
the VAO table can be found in the State Tables section of the spec
in psuedo code it looks like:
struct VAO{
GL_INT element_array_binding; //IBO used for glDrawElements and friends
char* label;//for debugging
struct{//per attribute values
bool enabled; //whether to use a VBO for it
//corresponding to the values passed into glVertexAttribPointer call
int size;
unsigned int stride;
GL_ENUM type;
bool normalized;
bool integer; //unconverted integers
bool long; //double precision
void* offset;
int bufferBinding;//GL_ARRAY_BUFFER bound at time of glVertexAttribPointer call
int attributeDiviser; //as used for instancing
} attributes[MAX_VERTEX_ATTRIBS];
};
Notably absent is the program state (which one is bound, the uniform values etc.)
Here is the formal declaration for glBufferData which is used to populate a VBO:
void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
What is confusing, however, is that you can have multiple VBOs, but this function does not require a handle to a particular VBO, so how does it know which VBO you are intending?
The target parameter can be either GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER but my understanding is that you can have more than one of each of these.
The same is true of the similar glBufferSubData method, which is intended to be called subsequent times on a VBO -- how does it know which VBO to handle?
This is a common pattern in OpenGL to bind object to a target and perform operations on it by issuing function calls without a handle. The same applies to the textures.
OpenGL operations that use a buffer object, make use of the buffer that has been bound by the most recent call to glBindBuffer on the used target.
glBindBuffer is a function that exposes the given buffer as bound. Such a glBufferData access it then by side-effect, through the currently bound buffer object.