I have noticed a strange error in my program, which occurs when I bind a VAO multiple times after calling glVertexArrayVertexBuffer
. In my frame loop, I usually have one VAO for one draw call, but sometimes I would like to use the same VAO for multiple draw calls with different shaders. But this does not work in my implementation:
while(RUN){
updateBuffers();//updates VAO
drawThis();//binds and unbinds VAO
drawThat();//binds and unbinds VAO -> OpenGL Invalid Operation error at draw call
}
Whereas this works:
while(RUN){
updateBuffers();//updates VAO
drawThis();//binds and unbinds VAO
updateBuffers();//updates VAO
drawThat();//binds and unbinds VAO -> works
}
Also this doesn´t work:
updateBuffers();
while(RUN){
drawThis();//OpenGL Invalid Operation error in second frame
}
but this would work
updateBuffers();
glBindVertexArray(VAO);
while(RUN){
drawThis();//only makes the draw call
}
glBindVertexArray(0);
... but that is not an option because I also want to use other VAOs in my frame loop (and I would like to stay flexible with the order).
So what are these functions doing internally?
The draw
functions simply bind a VAO and a shader, make a draw call (usually glDrawElementsInstanced
) and then unbind the shader and the VAO.
The updateBuffers
function usually writes to a buffer object (initialized with glNamedBufferStorage
) through a pointer which maps the entire buffer using the GL_MAP_WRITE_BIT
, GL_MAP_PERSISTENT_BIT
and GL_MAP_COHERENT_BIT
flags. To ensure that I am not overwriting any data that is still being used by the GPU, I always write to a different partition of the buffer. So before each update I increase the write offset by the size of the previous update (or set it to 0 if the update would exceed the storage size).
And because the updated data should be visible to shaders, I have to update the binding points that the shaders bind to, too. I do this by calling glBindBufferRange
for uniform buffers (used by uniform blocks) and glVertexArrayVertexBuffer
for vertex buffers (for vertex attributes) with each update, to make the binding offsets for each buffer start at the position of the updated data.
This always works fine for uniform buffer bindings (offset is updated with glBindBufferRange
) but when I update the binding for a vertex buffer of a VAO (with glVertexArrayVertexBuffer
) and then bind and unbind that VAO more than once before calling glVertexArrayVertexBuffer
again, I get an Invalid Operation
error.
Why does glVertexArrayVertexBuffer
cause a VAO to behave like this? What would be the proper approach to update the offset of a VAOs binding to a vertex buffer?