Search code examples
openglshaderopengl-4

Questions about uniform buffer objects


Is it guaranteed that if a uniform block is declared the same in multiple shader programs, say

uniform Matrices
{
    mat4 ProjectionMatrix;
    mat4 CameraMatrix;
    mat4 ModelMatrix;
};

Will it have the same block index returned by glGetUniformBlockIndex(program, "Matrices")?

If the answer is yes, then I'm able to query the index of the block once and use it for all the shader programs that contain that block, right?

Second question: will ProjectionMatrix, CameraMatrix, ModelMatrix, always have the same layout order in memory, respectively? I'm asking this because the tutorial I read uses the next functions

// Query for the offsets of each block variable
const GLchar *names[] = { "InnerColor", "OuterColor",
"RadiusInner", "RadiusOuter" };
GLuint indices[4];
glGetUniformIndices(programHandle, 4, names, indices);
GLint offset[4];
glGetActiveUniformsiv(programHandle, 4, indices,
GL_UNIFORM_OFFSET, offset);

And I'm not sure if that's really needed, as long as I know the uniforms order inside the uniform block..?


Solution

  • will ProjectionMatrix, CameraMatrix, ModelMatrix, always have the same layout order in memory, respectively?

    No. Here's what the standard states (emphasis mine):

    If pname is UNIFORM_BLOCK_DATA_SIZE, then the implementation- dependent minimum total buffer object size, in basic machine units, required to hold all active uniforms in the uniform block identified by uniformBlockIndex is returned. It is neither guaranteed nor expected that a given implementation will arrange uniform values as tightly packed in a buffer object. The exception to this is the std140 uniform block layout, which guarantees specific packing behavior and does not require the application to query for offsets and strides.

    I'm not sure if that's really needed, as long as I know the uniforms order inside the uniform block..?

    So, yes, the author is right in not assuming the layout is contiguous and does what's sensible (guaranteed to work always in all implementations): gets the uniform indices and assigns their values respectively.

    Specifying layout(std140) will do the trick then, right?

    Yes, you can avoid querying the location and uploading data every time by making use of both uniform buffer objects and std140. However, make sure you understand its alignment requirements. This information is detailed in ARB_uniform_buffer_object's specification. For an elaborate treatment with examples see OpenTK's article on Uniform Buffer Objects (UBO) using the std140 layout specification.

    Is it guaranteed that if a uniform block is declared the same in multiple shader programs, will it have the same block index returned by glGetUniformBlockIndex(program, "Matrices")?

    No. I've searched the OpenGL 3.3 specification which gives no such guarantees. From the standard's viewpoint, uniform blocks (default or named) are associated to a program, period. No existence/association of uniform blocks beyond a program is made in the specification.

    Because there is no guarantee that uniform blocks will have the same index in different shader program, that means I need to call glBindBufferBase() everytime I switch programs, right?

    Yes, see ARB_uniform_buffer_object's specification for an example.