6
votes

Updating a VBO (especially its size) via glBufferData() can potentially change it's physical memory address, though not its buffer object name as set by glGenBuffers(). A VBO is linked to a VAO via a call to glVertexAttribPointer(), where information about the VBO (buffer object name? Memory address?) is stored in the VAO. The VAO becomes available for update and drawing when it is bound via glBindVertexArray(). Does GL recompute the VBO address at that time? The VAO may or may not be bound when a VBO it links to gets updated via glBufferData().

Depending on when the buffer object name is translated to a physical memory address, I can imagine that the VAO could be updated for the changed VBO merely by binding the VAO again after changing the VBO; or, it may be necessary to more thoroughly update the VAO with another call to glVertexAttribPointer().

So part of this question is: what information about the VBO is stored in the VAO? If it is just the buffer object name, then it shouldn't be necessary to call glVertexAttribPointer() again after changing the VBO contents.

Perhaps such details are not part of the API specification, and so the only safe practice is to update a VAO via glVertexAttribPointer() after every update of a linked VBO.

1
I don't think you have to change the VAO at all if you don't change the buffer name. I'm doing pretty much what you describe and it works fine. However, I can't find any clear answer in the documentation either.vesan
@vesan Thanks for checking the documentation for me. I'm awash in the sheer volume of insufficiently organized OpenGL documentation. If it's not specified in writing, I'm uncomfortable counting on it, especially because I can imagine reasons for implementing in either of two possible ways:PaulQ
First, the way everyone seems to think it goes would be that the GL only keeps one copy of the absolute address of the vbo, in the context, not in the vao. The vao only gets the name of the buffer object, and a relative offset into it. The absolute address is only computed from that info and the context's vbo starting address when you call for a glDraw* command.PaulQ
The second possibility is that for speed purposes, the absolute address of the vbo plus offset is stored in the vao when you call glVertexAttribPointer(), so that it's more quickly available when you bind the vao. But perhaps this will never be done in an implementation because it would still have to be copied out of the vao on binding; so why not just keep it in the context, and point to it with the vao. But they could. Another possibility would be to compute the address on binding the vao.PaulQ

1 Answers

8
votes

You do not have to worry about that because VBOs never expose the underlying server memory space to you. Vertex attribute pointers are relative to the beginning of the object bound to GL_ARRAY_BUFFER at the time you set them.

Even if you re-allocate the buffer by calling glBufferData (...) (this creates a new data store, rather than updating it as your question suggests), your vertex attribute pointers are not going to be invalidated. This is because they are literally offsets into a named buffer's memory rather than arbitrary addresses; it takes two pieces of information (buffer name and offset) to establish a vertex pointer.


UPDATE: (Citing implementation details)

The following is from GL_ARB_vertex_attrib_binding:

Modify Section 2.9.6, "Vertex Arrays in Buffer Objects"

When an array is sourced from a buffer object, the vertex attribute's VERTEX_ATTRIB_BINDING indicates which vertex buffer binding is used. The sum of the attribute's VERTEX_ATTRIB_RELATIVE_OFFSET and the vertex buffer binding's VERTEX_BINDING_OFFSET is used as the offset (in basic machine units) of the first element in that buffer's data store.

    bindingIndex = VERTEX_ATTRIB_BINDING[attribIndex];
    buffer = VERTEX_BINDING_BUFFER[bindingIndex];

    if (buffer->name != 0) {
        address = buffer->baseAddress + 
                  VERTEX_BINDING_OFFSET[bindingIndex] + 
                  VERTEX_ATTRIB_RELATIVE_OFFSET[attribIndex];
    }

This code is from an extension / version of OpenGL (4.3) that is not part of the original discussion, but I thought it worth mentioning since for all intents and purposes this is how vertex attribute pointers worked under the hood anyway. The new API gives you the freedom to specify vertex attribute format independent of the vertex buffer (it does not care what is bound to GL_ARRAY_BUFFER at the time you setup the attribute format).

The address is computed indirectly when a command sources array memory (e.g. glDrawArrays (...)).