Advertisement

OpenGL why unbind VAO

Started by January 12, 2017 07:29 AM
5 comments, last by noizex 7 years, 10 months ago

While reading other peoples code I'm confused as to why a programmer will have to unbind VAO before the game loop, then having to bind and unbinding the VAO repeatedly every frame. Whats the point in doing this?

For example, basic lighting for a scene:




GLuint lightVAO;

glGenVertexArrays(1, &lightVAO);

glBindVertexArray(lightVAO);



glBindBuffer(GL_ARRAY_BUFFER, VBO);



glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);

glEnableVertexAttribArray(0);

glBindVertexArray(0);
 

GAME LOOP:


glBindVertexArray(lightVAO);

glDrawArrays(GL_TRIANGLES, 0, 36);

glBindVertexArray(0);

Because if you keep that last VAO bound over to next frame, and then do some operations on buffers using glBindBuffer() (but without binding appropriate VAO, because you don't have to) you'll be overwriting your currently bound VAO state, which in most cases may cause nasty and hard to track disasters :)

Edit: Though now that I think about it, I'm not so sure. I think I had issue with overriding VAO state when I kept VAO bound between frames so I started to reset it. At some point I was convinced that only glVertexAttribPointer() and friends affect VAO state, and these require glBindBuffer to work with. But I _think_ had cases where glBindBuffer (because I was uploading new data) somehow messed my other VAO state. So I can't give you 100% guarantee that what I say is correct, but I think it may be a good practice to know that VAO is enabled when it's needed and when you're done it's 0.

Edit2: I did a small mistake, it was ELEMENT_ARRAY_BUFFER binding that was the problem, so if you keep VAO bound and somewhere you manipulate some index buffer by binding it, you may override the one pointed to by currently bound VAO. It isn't affected by just binding GL_ARRAY_BUFFER, as I previously speculated.


Where are we and when are we and who are we?
How many people in how many places at how many times?
Advertisement
There's no good reason to do this. You should know at all times in your program which VAO is currently bound so that you don't repeatedly bind the same VAO. Or if you're just starting out, make those redundant calls to bind the VAO you need every time. Relying on a specific VAO to be bound in functions X, Y and Z becomes a maintainability nightmare later down the road. And there's certainly not any need to unbind VAOs.

If you're using core OpenGL, it's an error to bind the "default VBO" since core GL doesn't have one.

I think it's not about binding VAO redundantly (this should be prevented by keeping information about currently bound VAO), but resetting VAO to zero because of the possibility of overriding some loosely bound VAO state by other operation - in my case it was binding index buffer which I wanted to update, completely unrelated to any VAO that would point to this index buffer.

Also, binding 0 to reset vertex array binding is allowed:

glBindVertexArray binds the vertex array object with name array. array is the name of a vertex array object previously returned from a call to glGenVertexArrays, or zero to break the existing vertex array object binding.

It's rendering without VAO that's wrong I think, but having zero bound as VAO after you finish rendering is, in my opinion, a good safety measure. Please correct if I messed something here.


Where are we and when are we and who are we?
How many people in how many places at how many times?
From the GL4.5 spec, in reference to glBindVertexArray:

An INVALID_OPERATION error is generated if array is not zero or a name returned from a previous call to GenVertexArrays, or if such a name has since been deleted with DeleteVertexArrays.


My bad. I misread the text :) I'm sure it wasn't allowed somewhere but maybe I remembered wrong.

There is normally absolutely no need to unbind.

This is something that you see with increased regularity in recent tutorials, and - IMO - it is a sign of a poor tutorial that demonstrates incomplete understanding of how the API is designed to work.

Unbinding is the same symptom as resetting state after drawing, and indicates an underlying design problem. Instead of resetting state after drawing, you should be setting state before drawing.

If you're modifying buffer objects and you're using pre-DSA OpenGL, then you should be binding VAO 0 before doing any modifications, rather than unbinding after drawing.

A good maxim is that if an operation you're currently doing has a state dependency, and unless you've explicitly set the required state yourself before doing the operation, then you're at risk of inherting state from a prior operation. So based on that, don't write dependencies or assumptions into your code. Instead of unbinding after operations, explicitly bind before operations and you will never go wrong.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Advertisement

If you're modifying buffer objects and you're using pre-DSA OpenGL, then you should be binding VAO 0 before doing any modifications, rather than unbinding after drawing.

That would work too, I suppose. Thanks for suggestion!


Where are we and when are we and who are we?
How many people in how many places at how many times?

This topic is closed to new replies.

Advertisement