Am I allowed to bind a single opengl buffer to multiple indexed targets (of the SSBO target) simultaneously?
For instance, suppose my shader has two different uniform blocks with different binding indexes. If the information I need is located in the same buffer, am I allowed to use glBindBufferRange, and bind different ranges of the same buffer to these two binding indexes, simultaneously?
Another use case I see is, for instance, if I have a shader with two uniform blocks, again with different binding indexes, but this time, the only data member both uniform blocks have is an open array (with unspecified size). Am I allowed to use glBindBuffer to bind the same buffer to both uniform blocks, and guarantee by code, to only access the array indexes within the proper range in the buffer?
I believe it's fine to do so.
§6.1 (...) While a buffer object is bound, GL operations on the target to which it is bound
affect the bound buffer object, and queries of the target to which a buffer object is
bound return state from the bound object. Operations on the target also affect any
other bindings of that object
emphasis mine - which would directly suggest it's OK.
§6.1.1. (...) Each target represents an indexed array of buffer object binding points, as well
as a single general binding point that can be used by other buffer object manipulation
functions, such as BindBuffer or MapBuffer. Both commands bind the
buffer object named by buffer to both the general binding point, and to the binding
point in the array given by index. If the binds are successful no change is made
to the state of the bound buffer object, and any previous bindings to the general
binding point or to the binding point in the array are broken
What I'd distill from that is that it's not explicitely forbidden to bind a buffer range to multiple places, and as such, I'd assume it's allowed. It won't break the other bindings in that array, which means the previously bound ranges should stay unchanged and valid.
That being said, if the ranges overlap and you're writing to them, you might need barriers.
Related
OpenGL 4.3 and OpenGL ES 3.1 added several alternative functions for specifying vertex arrays: glVertexAttribFormat, glBindVertexBuffers, etc. But we already had functions for specifying vertex arrays. Namely glVertexAttribPointer.
Why add new APIs that do the same thing as the old ones?
How do the new APIs work?
glVertexAttribPointer has two flaws, one of them semi-subjective, the other objective.
The first flaw is its dependency on GL_ARRAY_BUFFER. This means that the behavior of glVertexAttribPointer is contingent on whatever was bound to GL_ARRAY_BUFFER at the time it was called. But once it is called, what is bound to GL_ARRAY_BUFFER no longer matters; the buffer object's reference is copied into the VAO. All this is very unintuitive and confusing, even to some semi-experienced users.
It also requires you to provide an offset into the buffer object as a "pointer", rather than as an integer byte offset. This means that you perform an awkward cast from an integer to a pointer (which must be matched by an equally awkward cast in the driver).
The second flaw is that it conflates two operations that, logically, are quite separate. In order to define a vertex array that OpenGL can read, you must provide two things:
How to fetch the data from memory.
What that data looks like.
glVertexAttribPointer provides both of these simultaneously. The GL_ARRAY_BUFFER buffer object, plus the offset "pointer" and stride define where the data is stored and how to fetch it. The other parameters describes what a single unit of data looks like. Let us call this the vertex format of the array.
As a practical matter, users are far more likely to change where vertex data comes from than vertex formats. After all, many objects in the scene store their vertices in the same way. Whatever that way may be: 3 floats for position, 4 unsigned bytes for colors, 2 unsigned shorts for tex-coords, etc. Generally speaking, you have only a few vertex formats.
Whereas you have far more locations where you pull data from. Even if the objects all come from the same buffer, you will likely want to update the offset within that buffer to switch from object to object.
With glVertexAttribPointer, you can't update just the offset. You have to specify the whole format+buffer information all at once. Every time.
VAOs mitigate having to make all those calls per object, but it turns out that they don't really solve the problem. Oh sure, you don't have to actually call glVertexAttribPointer. But that doesn't change the fact that changing vertex formats is expensive.
As discussed here, changing vertex formats is pretty expensive. When you bind a new VAO (or rather, when you render after binding a new VAO), the implementation either changes the vertex format regardless or has to compare the two VAOs to see if the vertex formats they define are different. Either way, it's doing work that it doesn't need to be doing.
glVertexAttribFormat and glBindVertexBuffer fix both of these problems. glBindVertexBuffer directly specifies the buffer object and takes the byte offset as an actual (64-bit) integer. So there's no awkward use of the GL_ARRAY_BUFFER binding; that binding is solely used for manipulating the buffer object.
And because the two separate concepts are now separate functions, you can have a VAO that stores a format, bind it, then bind vertex buffers for each object or group of objects that you render with. Changing vertex buffer binding state is cheaper than vertex format state.
Note that this separation is formalized in GL 4.5's direct state access APIs. That is, there is no DSA version of glVertexAttribPointer; you must use glVertexArrayAttribFormat and the other separate format APIs.
The separate attribute binding functions work like this. glVertexAttrib*Format functions provides all of the vertex formatting parameters for an attribute. Each of its parameters have the exact same meaning as the parameters from the equivalent call to glVertexAttrib*Pointer.
Where things get a bit confusing is with glBindVertexBuffer.
Its first parameter is an index. But this is not an attribute location; it is merely a buffer binding point. This is a separate array from attribute locations with its own maximum limit. So the fact that you bind a buffer to index 0 means nothing about where attribute location 0 gets its data from.
The connection between buffer bindings and attribute locations is defined by glVertexAttribBinding. The first parameter is the attribute location, and the second is the buffer binding index to fetch that attribute's location with. Since the function's name starts with "VertexAttrib", you should consider this to be part of the vertex format state and thus is expensive to change.
The nature of offsets may be a bit confusing at first as well. glVertexAttribFormat has an offset parameter. But so too does glBindVertexBuffer. But these offsets mean different things. The easiest way to understand the difference is by using an example of an interleaved data structure:
struct Vertex
{
GLfloat pos[3];
GLubyte color[4];
GLushort texCoord[2];
};
The vertex buffer binding offset specifies the byte offset from the start of the buffer object to the first vertex index. That is, when you render index 0, the GPU will fetch memory from the buffer object's address + the binding offset.
The vertex format offset specifies the offset from the start of each vertex to that particular attribute's data. If the data in the buffer is defined by Vertex, then the offset for each attribute would be:
glVertexAttribFormat(0, ..., offsetof(Vertex, pos)); //AKA: 0
glVertexAttribFormat(1, ..., offsetof(Vertex, color)); //Probably 12
glVertexAttribFormat(2, ..., offsetof(Vertex, texCoord)); //Probably 16
So the binding offset defined where vertex 0 is in memory, while the format offsets define where the each attribute's data comes from within a vertex.
The last thing to understand is that the buffer binding is where the stride is defined. This may seem odd, but think about it from the hardware perspective.
The buffer binding should contain all of the information needed by the hardware to turn a vertex index or instance index into a memory location. Once that's done, the vertex format explains how to interpret the bytes in that memory location.
This is also why the instance divisor is part of the buffer binding state, via glVertexBindingDivisor. The hardware needs to know the divisor in order to convert an instance index into a memory address.
Of course, this also means that you can no longer rely on OpenGL to compute the stride for you. In the above cast, you simply use sizeof(Vertex).
Separate attribute formats completely covers the old glVertexAttribPointer model so well that the old function is now defined entirely in terms of the new:
void glVertexAttrib*Pointer(GLuint index, GLint size, GLenum type, {GLboolean normalized,} GLsizei stride, const GLvoid * pointer)
{
glVertexAttrib*Format(index, size, type, {normalized,} 0);
glVertexAttribBinding(index, index);
GLuint buffer;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, buffer);
if(buffer == 0)
glErrorOut(GL_INVALID_OPERATION); //Give an error.
if(stride == 0)
stride = CalcStride(size, type);
GLintptr offset = reinterpret_cast<GLintptr>(pointer);
glBindVertexBuffer(index, buffer, offset, stride);
}
Note that this equivalent function uses the same index value for the attribute location and the buffer binding index. If you're doing interleaved attributes, you should avoid this where possible; instead, use a single buffer binding for all attributes that are interleaved from the same buffer.
I think what glBindBuffer(target, buffer) do is to store the buffer's address on the target, which is a special address.
But I found the glBindBufferBase(target, index, buffer). I think target should be a array, this operation stores the buffer address to the array according to the index.
If what I thought is right, then the glBindBuffer is equivalent to glBindBufferBase(target, someindex, buffer)?
Maybe someindex is 0?
They're not used for the same purpose.
glBindBuffer is used to bind a buffer to a specific target so that all operations which modify that target are mapped to that buffer afterwards.
glBindBufferBase is used for a totally different purpose, it's used bind a buffer to a specific binding point in an indexed array (when data is not supposed to be directly modified but rather used). While this may seem convoluted it's really easy to see. Assume you want to pass an uniform block to your shader, then you have a table which maps named buffers to specific indices in an array which are then mapped to bindings in a shader like in the following figure:
so glBindBufferBase is creating the arrows on the right in which you specify the index, while glBindBuffer is just binding the buffer to the specific target.
You would then use glGetUniformBlockIndex to get the correct index in the shader which is then linked to the binding point (the left arrows) through glUniformBlockBinding.
I was looking for ways to associate attributes with arbitrary groupings of verticies, at first instancing appeared to be the only way for me to accomplish this, but then I stumbled up this question and this answer states :
However what is possible with newer versions of OpenGL is setting the rate at which a certain vertex attribute's buffer offset advances. Effectively this means that the data for a given vertex array gets duplicated to n vertices before the buffer offset for a attribute advances. The function to set this divisor is glVertexBindingDivisor.
(emphasis mine)
Which to me seems as if the answer is claiming I can divide on the number of vertices instead of the number of instances. However, when I look at glVertexBindingDivisor's documentation and compare it to glVertexAttribDivisor's they both appear to refer to the division taking place over instances and not vertices. For example in glVertexBindingDivisor's documentation it states:
glVertexBindingDivisor and glVertexArrayBindingDivisor modify the rate at which generic vertex attributes advance when rendering multiple instances of primitives in a single draw command. If divisor is zero, the attributes using the buffer bound to bindingindex advance once per vertex. If divisor is non-zero, the attributes advance once per divisor instances of the set(s) of vertices being rendered. An attribute is referred to as instanced if the corresponding divisor value is non-zero.
(emphasis mine)
So what is the actual difference between these two functions?
OK, first a little backstory.
As of OpenGL 4.3/ARB_vertex_attrib_binding (AKA: where glVertexBindingDivisor comes from, so this is relevant), VAOs are conceptually split into two parts: an array of vertex formats that describe a single attribute's worth of data, and an array of buffer binding points which describe how to fetch arrays of data (the buffer object, the offset, the stride, and the divisor). The vertex format specifies which buffer binding point its data comes from, so that multiple attributes can get data from the same array (ie: interleaving).
When VAOs were split into these two parts, the older APIs were re-defined in terms of the new system. So if you call glVertexAttribPointer with an attribute index, this function will set the vertex format data for the format at the given index, and it will set the buffer binding state (buffer object, byte offset, etc) for the same index. Now, these are two separate arrays of VAO state data (vertex format and buffer binding); this function is simply using the same index in both arrays.
But since the vertex format and buffer bindings are separate now, glVertexAttribPointer also does the equivalent of saying that the vertex format at index index gets its data from the buffer binding at index index. This is important because that's not automatic; the whole point of vertex_attrib_binding is that a vertex format at one index can use a buffer binding from a different index. So when you're using the old API, it's resetting itself to the old behavior by linking format index to binding index.
Now, what does all that have to do with the divisor? Well, because that thing I just said is literally the only difference between them.
glVertexAttribDivisor is the old-style API for setting the divisor. It takes an attribute index, but it acts on state which is part of the buffer binding point (instancing is a per-array construct, not a per-attribute construct now). This means that the function assumes (in the new system) that the attribute at index fetches its data from the buffer binding point at index.
And what I just said is a bit of a lie. It enforces this "assumption" by directly setting the vertex format to use that buffer binding point. That is, it does the same last step as glVertexAttribPointer did.
glVertexBindingDivisor is the modern function. It is not passed an attribute index; it is passed a buffer binding index. As such, it does not change the attribute's buffer binding index.
So glVertexAttribDivisor is exactly equivalent to this:
void glVertexAttribDivisor(GLuint index, GLuint divisor)
{
glVertexBindingDivisor(index, divisor);
glVertexAttribBinding(index, index);
}
Obviously, glVertexBindingDivisor doesn't do that last part.
So what is the actual difference between these two functions?
Modern OpenGL has two different APIs for specifying vertex attribute arrays and their properties. The traditional glVertexAttribArray and friends, where glVertexAttribDivisor is also part of.
With ARB_vertex_attrib_binding (in core since GL 4.3), a new API was introduced, which separates the vertex format from the pointers. It is expected that switching the data pointers is fast, while switching the vertex format can be more expensive. The new API allows to explictely control both aspects separately, while the old API always sets both at once.
For the new API, a new layer of introduction was introduced: the buffer binding points. (See the OpenGL wiki for more details.) glVertexBindingDivisor specifies the attribute instancing divisor for such a binding point, so it is the conceptual equivalent of the glVertexAttribDivisor function for the new API.
I was reading the documentation on glBindBuffer when I saw this:
Likewise, the GL_UNIFORM_BUFFER, GL_ATOMIC_COUNTER_BUFFER and GL_SHADER_STORAGE_BUFFER buffer binding points may be used, but do not directly affect uniform buffer, atomic counter buffer or shader storage buffer state, respectively.
What does "do not directly affect uniform buffer, atomic counter buffer or shader storage buffer state" mean?
I bound a buffer to the generic GL_SHADER_STORAGE_BUFFER binding point, and when querying for the state of SHADER_STORAGE_BUFFER_BINDING, the previously bound buffer name is returned.
On this site describing the shader_storage_buffer_object extension, it states that SHADER_STORAGE_BUFFER_BINDING is part of the shader storage buffer state.
Therefore I believe that using glBindBuffer on a generic binding point (such as GL_SHADER_STORAGE_BUFFER) does indeed affect the shader storage buffer state.
Yes obviously, if you bind the buffers to the context, you can query those bind points. But the point the docs is trying to get across is that those binding points don't mean anything.
Consider GL_COPY_READ_BUFFER. Binding to this target means something. If you call glCopyBufferSubData, it will use the buffer bound to GL_COPY_READ_BUFFER as the source buffer for that copy operation.
By contrast, there is no OpenGL operation that will use the buffer bound to GL_SHADER_STORAGE_BUFFER for any actual OpenGL operations. Sure, you can query it, but that's all you can do with it. If you want to use a buffer for actual storage buffer operations, you must use glBindBufferRange/Base or equivalent functions.
I'm curious about the *BlockBinding argument used in several of OpenGLs buffer object related functions.
For example the uniformBlockBinding parameter in glUniformBlockBinding, storageBlockBinding in glShaderStorageBlockBinding, and the corresponding index parameter in glBindBufferRange and glBindBufferBase.
I know that calls to glUniformBlockBinding and glShaderStorageBlockBinding aren't necessary if binding points are set in the shaders using layout qualifiers such as:
layout (binding = 0) blockName {...}
and from testing around on my machine I've noticed three things:
1) setting binding points with glUniformBlockBinding and glShaderStorageBlockBinding override binding points set in the shader using layout qualifiers.
2) block indices returned from glGetUniformBlockIndex and glGetProgramResourceIndex are ordered 0 to n for each block of the same type. For example if the shader contains 3 uniform blocks and 2 buffer blocks the indices returned would be [0,1,2] and [0,1] respectively.
3) binding points, set either way, do not conflict across types. For example, setting a uniform block to binding = 0 and a buffer block to binding = 0 is completely safe.
With these assumptions in mind (please correct me if any aren't necessarily true and are simply coincidence), are there any reasons why I shouldn't just have my code automatically set the *BlockBinding argument to the corresponding block index and save myself the trouble of ever specifying them manually via gl*BlockBinding or with layout qualifiers.
I once had the same question. After some exploration, and especially reading the authoritative source of information on GL: https://www.khronos.org/opengl/wiki/Uniform_Buffer_Object]
I'm pretty sure this is why the separation between block index and binding point.
Think of a GL render context as a port, and a glsl program object as a ship. The binding points are harbors of the port and block indices are doors to ship's storage compartments. A ship needs to dock at the port with one of its door aligned with a specific harbor to load cargo onto the ship (or the other way around). Similarly, a block index needs to be associated with a binding point for the data to be transferred between the shader's blocks and the context's buffers.
Due to this design, the block indices and binding points are independent entities. Therefore it's not safe to simply equating binding point to block index, as that may unintentionally overrides binding points (that may have been docked by other ships).
Your observations can be also explained:
The block indices and binding points start counting from 0 contiguously (as what you observed in (2)).
Each type of buffers (since they reside on the context) have a set of binding points that are separate from the other types (hence your observation 3).
As to your observation 1, yes, setting the association on the application side preempts the hard-coded binding in the shader.
With these assumptions in mind (please correct me if any aren't necessarily true and are simply coincidence), are there any reasons why I shouldn't just have my code automatically set the *BlockBinding argument to the corresponding block index and save myself the trouble of ever specifying them manually via gl*BlockBinding or with layout qualifiers.
Because that would be completely useless.
The block index is arbitrarily assigned to a particular block. One one platform, a particular block's index could be 0, while another sorts the names such that it's index 2. So your code will have to query the block indices for each block you plan to use.
Whereas if you specify what binding indices to use for a particular block, you don't have to query anything. Your code knows that binding index 0 is where your matrices go, binding index 1 is where your lighting data goes, etc.
What's worse is that you may have multiple shaders that use the same block. But they're highly unlikely to have the same block index. Whereas if you assign them a binding index, you can give them the same binding index. And therefore, you don't have to re-bind buffers between changes to such programs.