Can OpenGL vertex buffer binding points be reused across different VAOs?
Asked Answered
Q

1

6

Suppose I set up two VAOs, using the new (as of OpenGL 4.3) glBindVertexBuffer mechanism:

glGenVertexArrays(1, &vaoIndex0);
glGenVertexArrays(1, &vaoIndex1);

...

glBindVertexArray(vaoIndex0)
glBindVertexBuffer(bindingIndex0, ...)
glEnableVertexAttribArray(0)
glVertexAttribFormat(0, ...)
glVertexAttribBinding(0, bindingIndex0)
...
glBindVertexArray(0)

...

glBindVertexArray(vaoIndex1)
glBindVertexBuffer(bindingIndex1, ...)
glEnableVertexAttribArray(0)
glVertexAttribFormat(0, ...)
glVertexAttribBinding(0, bindingIndex1)
...
glBindVertexArray(0)

And suppose the two are independent, except insofar as they exist in the same OpenGL context; they bind different buffers and will be used to draw different things.

Does bindingIndex0 need to be different from bindingIndex1? Is there any significance at all in the equality (or inequality) of the two indices?

...

EDIT:

After receiving an answer I began to understand that to someone who actually knows what a "vertex buffer binding point" is, and particularly, what its scope is, my question might seem to be asking something different than what I intended. Maybe a better phrasing would have been "Does one need to go out of one's way to prevent OpenGL vertex buffer binding point indices from being reused, even across multiple VAOs, in order to prevent conflicts?" But anyway, it seems that both questions have now been answered: No you can't reuse the "binding points", and no you don't need to avoid index conflicts in that way.

Quartz answered 23/3, 2015 at 21:6 Comment(0)
M
7

All of these calls modify VAO state. So no, you cannot reuse these settings across VAOs. You can of course set them the same in multiple VAOs, but you have to make the necessary state setup calls once when you set up each VAO.

The bindingIndex0 and bindingIndex1 values you use in your code fragment don't have any special meaning. They just establish the connection between the buffer you bind to the binding index with glBindVertexBuffer(), and the attributes you specify as using that binding index.

The only condition is that the binding index has to be smaller than the value you can query as MAX_VERTEX_ATTRIB_BINDINGS, which is guaranteed to be at least 16. Since these calls modify per-VAO state, you absolutely can use the same binding indices for multiple VAOs.

One way of looking at these newer state setup calls is that they introduce a level of indirection that was not previously available:

  • Without these calls, you establish a direct connection between vertex attribute and buffer, by calling glVertexAttribPointer() while the desired buffer is bound.
  • With these newer calls, a vertex attribute now has a connection to a binding index, which is established with glVertexAttribBinding(). The binding index is then connected to a buffer, which is established with glBindVertexBuffer().

In other words, in old style the connection is:

attribute index --> buffer

new style with these 4.3+ calls:

attribute index --> buffer index --> buffer

One advantage of this new flexibility is that you can bind a new buffer to multiple attributes with a single call. As long as all these attributes have the same buffer index, you need just one call to glBindVertexBuffer() to specify a new buffer for all the attributes.

Semi-formal Definition

The following is not official notation at all. I just made it up. But I thought it might be useful to define the relationships more formally, by writing down some pseudo data structures.

Let's say each VAO contains two arrays to capture the connections explained above:

struct VAO {
    ...
    uint bufferIndexBindings[MAX_VERTEX_ATTRIB_BINDINGS];
    uint attribBufferIndices[MAX_VERTEX_ATTRIBS];
}

The two calls discussed here would then modify this structure like this:

glBindVertexBuffer(uint bindingIndex, uint buffer, ...) {
    CurrentVAO.bufferIndexBindings[bindingIndex] = buffer;
}

glVertexAttribBinding(uint attribIndex, uint bindingIndex) {
    CurrentVAO.attribBufferIndices[attribIndex] = bindingIndex;
}

This state is then used to obtain the buffer for a given attribute with index attribIndex as:

CurrentVAO.bufferIndexBindings[CurrentVAO.attribBufferIndices[attribIndex]]

This also illustrates the indirection I explained above, which shows up here as two levels of lookup into the state tables.

Medellin answered 24/3, 2015 at 2:59 Comment(3)
So, does the "binding point" being indexed by bindingIndex0 not even exist outside its VAO? I'm basically trying to ask about the scope of the meaning of the binding point index. (I had initially assumed that the binding point was owned by the GL context, not by a single VAO, so then I would need to make sure that no two VAOs tried to use the same binding point index. But then it occurred to me that that might not be true, so I asked here to try to confirm.)Quartz
@Quartz I added another section to the answer to explain the relationships in a different way. The binding index is really just an index into a state table that lives in each VAO. It's purely local to the VAO.Medellin
Okay. So my question sort of didn't make sense. You can "reuse" the indices because they're just numbers, and numbers of course are global, but you can't reuse the binding points (and it almost doesn't make sense to ask whether you can) because they are VAO-local. "But I thought it might be useful to define the relationships more formally, by writing down some pseudo data structures" is pretty much what I needed... I wish every OpenGL function documentation page would do that. It's hard to manipulate data structures that nobody ever shows you a definition for.Quartz

© 2022 - 2024 — McMap. All rights reserved.