7

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.

kbirk
  • 3,906
  • 7
  • 48
  • 72

2 Answers2

2

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.
danielyan86129
  • 116
  • 1
  • 7
2

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982