25
\$\begingroup\$

I was wondering what state is stored in an OpenGL VAO. I've understood that a VAO contains state related to the vertex specifications of buffered vertices (what attributes are in the buffers, and what buffers are bound, ... ). To better understand the correct usage of VAO's, I'd like to know exactly what state they hold.


How I assume VAO's should be used

From simple examples, I've understood that correct usage of VAO's is as follows:

Setup

Generate VAO
BindVAO
---- Specify vertex attributes
---- Generate VBO's
---- BindVBO's
-------- Buffer vertex data in VBO's
---- Unbind VBO's
Unbind VAO

Rendering

Bind VAO
---- Draw
Unbind VAO

From this, I assume that at least the vertex buffer bindings and the vertex attribute specifications are stored in the VAO. I'm unsure however how this usage pattern extends to situations where (multiple) textures and (multiple) shader programs come into play. Is the active shader program stored in the VAO? And are the texture bindings (with their sampling/ wrapping settings) stored in the VAO as well? Ditto for uniforms?


Therefore, my questions are:

  • What exact state is stored in an OpenGL VAO? (VBO bindings, attribute specifications, active shader program, texture bindings, texture sampling/wrapping settings, uniforms ... ?)
  • How do I correctly use VAO's in a more complex rendering setup where (multiple) textures with associated sampling/wrapping settings, (multiple) shader programs and uniforms are involved?
\$\endgroup\$
  • 1
    \$\begingroup\$ VAO stores data about vertex attribute locations. It also stores IDs of VBOs in which these attributes are contained. You don't need to bind VBO when you draw something, you need to bind it before calling glVertexAttribPointer() when you create VAO. \$\endgroup\$ – HolyBlackCat Apr 30 '15 at 10:36
18
\$\begingroup\$

VAO stores data about vertex attribute locations. (And some other data related to them.)
"VBO bindings, active shader program, texture bindings, texture sampling/wrapping settings, uniforms" are completely unrelated to it.

You may ask why it doesn't remember VBO binding. Because you don't need to bind VBO to draw something, you only need to bind it when creating VAO: When you call glVertexAttribPointer(...), VAO remembers what VBO is currently bound. And VAO will take attributes from these VBOs when you draw it, even if these VBOs are not bound currently.


Also, VAOs and VBOs must be used slighty differently:

This will not work

Generate VAO
BindVAO
---- Specify vertex attributes
---- Generate VBO's
---- BindVBO's
-------- Buffer vertex data in VBO's
---- Unbind VBO's
Unbind VAO

because you need to bind VBO to specify attribute locations.

So, you should do it like this:

Generate VAO
BindVAO
Generate VBO's
BindVBO's
Specify vertex attributes

You can change VBO's data whenever you want, but you must bind it before.

And drawing should look like this:

Bind VAO
Draw


As you may noticed, I removed unbind calls from your lists. They are almost completely useless and they will slightly slow down your program, so I see no reason to call them.

\$\endgroup\$
  • 9
    \$\begingroup\$ "so I see no reason to call them." to prevent accidentally changing them. Especially a problem when using 3rd-party libraries. \$\endgroup\$ – ratchet freak Apr 30 '15 at 11:00
  • \$\begingroup\$ Thank you for the great answer! So in short, the VAO only stores the vertex attribute locations. VBO's are not rebound when binding a VAO, as the VAO knows what buffers to find the attributes in. All other state is contained in the global OpenGL state. \$\endgroup\$ – Jelle van Campen Apr 30 '15 at 14:32
  • \$\begingroup\$ @JellevanCampen Yep, correct. FYI, it also stores off/on state of attributes (gl{Enable|Disable}VertexAttribArray()), their default values (glVertexAttrib*()), their instancing mode (glVertexAttribDivisor()) and probably something else. \$\endgroup\$ – HolyBlackCat Apr 30 '15 at 15:42
  • \$\begingroup\$ @HolyBlackCat are you sure the default state (glVertexAttrib()) is part of VAO state? The OpenGL wiki claims otherwise, saying they are context state. \$\endgroup\$ – rdb Jul 3 '15 at 15:58
  • \$\begingroup\$ @ndb Nope, I'm not sure. I expected them to be a part of VAO state, and I didn't check it. \$\endgroup\$ – HolyBlackCat Jul 4 '15 at 10:58
4
\$\begingroup\$

It only stores the vertex binding and the index buffer binding

That is all the parameters of glVertexAttribPointer plus the buffer bound to Vertex_Array_buffer at the time of the call to glVertexAttribPointer and the bound Element_Array_buffer.

Uniforms are part of the current program.

Everything else is global state.

In doubt you can check the state tables in the spec of the version you are using.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the answer as well! This clears things up for me. \$\endgroup\$ – Jelle van Campen Apr 30 '15 at 14:35
4
\$\begingroup\$

Here is a simple but effective explanation , basically a buffer object has information which can be interpreted as just simply bits of raw data, which on its own mean nothing, so it is PURELY the data which can be looked at any way really

i.e float vbo[]={1.0,2.0,34.0...}

and the way OpenGL was designed to work is that you must DEFINE what the data that your passing to the various shaders is going to look like to the shaders

in that you also have to define how it will read that data, what format it is in, and what to do with it and how it will be used and for what,all of this information is stored in the VAO

for example you can declare data that is stored in an array like this float vbo = {11.0,2.0,3.0,4.0}

what is required next at this point is how to interpret that data from the VBO in the VAO, and what that means is as follows

the VAO can be set to read 2 floats per vertex (which would make it 2 vectors with two dimensions x,y) or you can tell the vao to interpret it as 1 vector with 4 dimensions i.e x,y,z,w etc

but also other attributes of that data is defined and stored in the VAO such as data format(despite that you declared an array of float you can tell the shader to read it in as an integer, with of course the system converting the raw data in the process from float to integer and has its own set of rules what to do in such circumstances)

So basically the VBO is the data, and the VAO stores how to interpret that data, because the shaders and OpenGL server is designed to be very nosey and needs to know everything before it decides how to process it and what to do with it and where to put it

of course its not actually nosey, its actually looking to be most efficient because it needs to store that data on the graphics server memory so that it gets the most efficient and quickest processing(unless it decides that it doesn't need to do this if the data is not to be processed in such a way and used for some other information that isnt accessed often) , and hence why the details of what to do with the data and how to process it is required to be stored in the VAO , so the VAO is like a header and the VBO is like the pure raw data that the header uses and defines(in this case passes to the shader vertex attributes) with the exception that the VBO is not limited only to be used by one VAO, it can be used and reused and bound to many VAO's for example:

what you can do is you can bind one buffer object to VAO1 and also(separately) bind the same buffer object to VAO2 with each interpreting it differently so that if your shader where to process the data, depending on which VAO is the one that is bound it would process the same raw data differently to the frambuffer(drawing pixels to window) resulting in different display of the same data which would be based upon how you defined its use in the VAO

\$\endgroup\$
  • \$\begingroup\$ This is the best answer! \$\endgroup\$ – CodingMadeEasy Jun 29 '17 at 3:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.