PDA

View Full Version : VAOs and GL_ARRAY_BUFFER binding



Zildjian
01-29-2012, 05:42 PM
Hi all -- The wiki artical on VAOs (http://www.opengl.org/wiki/Vertex_Array_Object) says the following:


Note: Changing the GL_ARRAY_BUFFER binding does not affect VAO state. This is different from the GL_ELEMENT_ARRAY_BUFFER binding, which is directly part of VAO state.

This seems to contradict the OpenGL spec, section 2.10, which reads:


The buffer objects that are to be used by the vertex stage of the GL are collected together to form a vertex array object.

Unlike the wiki, the spec makes no distinction about buffer bindings, implying all buffer objects related to vertex arrays are part of VAO state. Indeed the spec appears to be correct, as I verified with the following code:



glBindVertexArray( _vaoID );
if( _first )
{
_first = false;

glBindBuffer( GL_ARRAY_BUFFER, _bufID );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (const void*)0 );
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, stride, (const void*)( sizeof( GLfloat ) * 3 ) );
glEnableVertexAttribArray( 1 );
}
glDrawArrays( GL_TRIANGLE_STRIP, 0, 6 );
glBindVertexArray( 0 );


This code draws correctly on the first and subsequent frames, even though GL_ARRAY_BUFFER has different bindings on entry to this code block.

Can someone else confirm the wiki is incorrect? If so, let's go in and correct it (I have never made a change to the wiki and don't know what's involved in that, but I'm willing to make the change if I can do so).

Alfonse Reinheart
01-29-2012, 05:50 PM
This code draws correctly on the first and subsequent frames, even though GL_ARRAY_BUFFER has different bindings on entry to this code block.

There is exactly one GL_ARRAY_BUFFER binding.

You need to understand the difference between GL_ARRAY_BUFFER and the buffer object used by a vertex attribute. They are not the same.

Think of GL_ARRAY_BUFFER as a global GLuint that holds a buffer object. So `glBindBuffer` is implemented as:



GLuint arrayBufferBinding = 0;
void glBindBuffer(GLenum target, GLuint buffer)
{
switch(target)
{
case GL_ARRAY_BUFFER:
arrayBufferBinding = buffer;
}
}


That's all it does. Only calling `glBindBuffer` will not affect anything in the VAO.

What affects the VAO is exactly what the wiki page states: calling glVertexAttribPointer. This function takes whatever is currently bound to GL_ARRAY_BUFFER and puts it in the VAO for that attribute index. So it is the combination of `glBindBuffer` and `glVertexAttribPointer` that sets the buffer for an attribute in a VAO.

The specification is correct as well; you're just misunderstanding it. The spec is talking about the buffer objects as set by `glVertexAttribPointer`, not the GL_ARRAY_BUFFER binding.

Zildjian
01-30-2012, 10:57 AM
Thanks for your reply.

(Yes, I know that only one buffer object can be bound to GL_ARRAY_BUFFER at a time. OpenGL is a state machine. I've been working with OpenGL since 1994; I'm not a newbie :-). This is not the source of my confusion. Sorry if I miscommunicated.)


This function takes whatever is currently bound to GL_ARRAY_BUFFER and puts it in the VAO for that attribute index.

We agree then. Even the wiki says that its VertexAttribute struct pBufferObj field is loaded from the "current GL_ARRAY_BUFFER binding" at the time of the glVertexAttribPointer call. And the spec table 6.4 confirms that the GL_ARRAY_BUFFER per vertex attrib is part of VAO state. Good, it's settled then.

I just don't understand why the wiki says, in a big, hard to miss, "Note:" callout box:


Changing the GL_ARRAY_BUFFER binding does not affect VAO state. This is different from the GL_ELEMENT_ARRAY_BUFFER binding, which is directly part of VAO state.

This is misleading at best. If a VAO is bound, and a buffer is bound to GL_ARRAY_BUFFER, and the app calls glVertexAttribPointer, then OpenGL stores the GL_ARRAY_BUFFER binding in the VAO.

Shouldn't the wiki text be clarified? Perhaps a better version of that note text would be:


(Proposed text) Changing the GL_ELEMENT_ARRAY_BUFFER binding with a call to glBindBuffer affects VAO state. Changing the GL_ARRAY_BUFFER binding affects VAO state only indirectly, as the current GL_ARRAY_BUFFER binding is saved in VAO state at the time of the glVertexAttribPointer call.

Alfonse Reinheart
01-30-2012, 11:19 AM
This is misleading at best. If a VAO is bound, and a buffer is bound to GL_ARRAY_BUFFER, and the app calls glVertexAttribPointer, then OpenGL stores the GL_ARRAY_BUFFER binding in the VAO.

It is not misleading; it is true. It's a common misconception about GL_ARRAY_BUFFER and VAOs that trips a lot of people up. I put that note there so that people would know that binding to GL_ARRAY_BUFFER does not affect VAO state. VAO state is only affected by glEnable/DisableVertexAttribArray and glVertexAttribPointer calls.

The fact that glVertexAttribPointer happens to get its buffer from what is bound to GL_ARRAY_BUFFER does not mean that GL_ARRAY_BUFFER is VAO state.

The bind to GL_ARRAY_BUFFER itself will not affect VAO state; only calling glVertexAttribPointer will affect VAO state.

Dan Bartlett
01-30-2012, 12:56 PM
Also, if you were to use http://www.opengl.org/registry/specs/EXT/direct_state_access.txt you don't need to bind anything to GL_ARRAY_BUFFER at all, you can directly specify the buffer object without previously "latching" it.


void VertexArrayVertexAttribOffsetEXT(uint vaobj, uint buffer,
uint index, int size,
enum type, boolean normalized,
sizei stride, intptr offset);