bcrist
bcrist

Reputation: 1530

Binding to GL_ELEMENT_ARRAY_BUFFER with no VAO bound

The buffer currently bound to the GL_ELEMENT_ARRAY_BUFFER target in OpenGL is part of the state contained in a Vertex Array Object (VAO from here on). According to the OpenGL 4.4 core profile spec then, it would seem that attempting to change or access the GL_ELEMENT_ARRAY_BUFFER while no VAO is bound is an error:

10.4 Vertex Array Objects

... An INVALID_OPERATION error is generated by any commands which modify, draw from, or query vertex array state when no vertex array is bound. This occurs in the initial GL state, and may occur as a result of BindVertexArray or a side effect of DeleteVertexArrays.

This is supported by the OpenGL wiki's Buffer Object page:

GL_ELEMENT_ARRAY_BUFFER​

All rendering functions of the form gl*Draw*Elements*​ will use the pointer field as a byte offset from the beginning of the buffer object bound to this target. The indices used for indexed rendering will be taken from the buffer object. Note that this binding target is part of a Vertex Array Objects state, so a VAO must be bound before binding a buffer here.

Now, it would be nice if this were not the case. It would make it easy to create and manage index buffers separately from any particular VAO. But if just binding a buffer to GL_ELEMENT_ARRAY_BUFFER is verboten when there's no VAO bound, the only alternative is for the class representing an index buffer to bind a dummy VAO when they are created/updated/etc.

Nicol Bolas' excellent OpenGL tutorial says that this type of use is in fact valid:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER): Calling this without a VAO bound will not fail.

This seems to contradict the standard and opengl.org wiki. Is there something in the standard supporting this that I've missed, or is this only referring to compatibility profile contexts where using a VAO is not required?

Upvotes: 2

Views: 1709

Answers (2)

Jack Harwood
Jack Harwood

Reputation: 428

But if just binding a buffer to GL_ELEMENT_ARRAY_BUFFER is verboten when there's no VAO bound, the only alternative is for the class representing an index buffer to bind a dummy VAO when they are created/updated/etc.

New reply to an old question, but a simple way to work with an index buffer without requiring a VAO (or interfering with the currently bound VAO) is to bind the buffer to a target other than GL_ELEMENT_ARRAY_BUFFER.

For example, instead of this:

glBindVertexArray(vaoID);                               // ...Do I even have a VAO yet?
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);   // <- Alters VAO state!
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, ...);

-- one might write this instead:

glBindBuffer(GL_COPY_WRITE_BUFFER, indexBufferID);
glBufferSubData(GL_COPY_WRITE_BUFFER, ...);

(Here I arbitrarily used GL_COPY_WRITE_BUFFER, which exists to provide a temporary target to make copying between buffers easier, but most other targets would be fine as well.)

Upvotes: 1

Andon M. Coleman
Andon M. Coleman

Reputation: 43319

If you have an AMD or NV GPU you can always use the EXT_direct_state_access extension to manipulate a buffer object without binding it (this is purely a driver feature and does not require any special class of hardware). Sadly, Intel, Mesa and Apple have not bothered to implement this extension despite its 5 year existence -- lazy slackers.


Have a look at the following functions, they will make what you are describing a lot easier:

  • glNamedBufferDataEXT (...)
  • glNamedBufferSubDataEXT (...)
  • glMapNamedBufferEXT (...)
  • glUnmapNamedBufferEXT (...)

Now, since adoption of DSA is sparse, you will probably have to write some fallback code for systems that do not support it. You can reproduce the functionality of DSA by writing functions with identical function signatures that use a dummy VAO to bind VBOs and IBOs for data manipulation on systems that do not support the extension. You will have to keep track of what VAO was bound before you use it, and restore it before said function returns to eliminate side-effects.

In a good engine you should shadow the VAO binding state rather than having to query it from GL. That is, instead of using glBindVertexArray (...) directly you implement a system that wraps that call and therefore always knows what VAO is bound to a particular context. In the end, this makes emulating DSA functionality where driver support does not exist a lot more efficient. If you attempt something like this, you need to be aware that glDelete (...) functions implicitly unbind (by binding 0) the object being deleted if it is bound in the current context.

Upvotes: 0

Related Questions