Uniform Buffer Object

From OpenGL Wiki
(Redirected from Uniform Buffer Objects)
Jump to navigation Jump to search
Uniform Buffer Object
Core in version 4.6
Core since version 3.1
Core ARB extension ARB_Uniform_Buffer_Object

A Buffer Object that is used to store uniform data for a shader program is called a Uniform Buffer Object. They can be used to share uniforms between different programs, as well as quickly change between sets of uniforms for the same program object.

The term "Uniform Buffer Object" refers to the OpenGL buffer object that is used to provide storage for uniforms. The term "uniform blocks" refer to the GLSL language grouping of uniforms whose storage come from buffer objects.

Uses[edit]

Uniform buffers have several uses.

Switching between uniform buffer bindings is typically faster than switching dozens of uniforms in a program. Therefore, uniform buffers can be used to quickly change between different sets of uniform data for different objects that share the same program.

Also, uniform buffer objects can typically store more data than non-buffered uniforms. So they can be used to store and access larger blocks of data than unbuffered uniform values.

Lastly, they can be used to share information between different programs. So modifying a single buffer can effectively allow uniforms in multiple programs to be updated.

Shader Specification[edit]

Uniform blocks are a specialized form of buffer-backed interface block.

OpenGL Usage[edit]

Buffer objects are associated with a program's uniform block similarly to the way that texture objects are associated with sampler uniforms. The context has GL_MAX_UNIFORM_BUFFER_BINDINGS binding locations for uniform buffers. This value is usually the sum of the maximum uniform block count for all 3 possible stages. This list of uniform binding locations is analogous to the set of texture image unit binding points.

Each active uniform block in GLSL has a corresponding active uniform block in the linked program. You can get the uniform block index (similar to a uniform location) with this function:

GLuint glGetUniformBlockIndex( GLuint program​, const char *uniformBlockName​ );

The uniformBlockName​ is the name of the uniform block, not the name of the GLSL scope for the uniform. This function returns GL_INVALID_INDEX if the block name could not be found.

The uniform block index is used to set what uniform buffer binding location that this uniform block uses. You can call this function to associate this uniform block with a uniform buffer binding location:

void glUniformBlockBinding( GLuint program​, GLuint uniformBlockIndex​, GLuint uniformBlockBinding​ );

This causes the uniformBlockIndex​ index in the program​ to be bound to the uniform buffer binding location uniformBlockBinding​.

Once the program is bound to the context, all you need to do is bind the appropriate uniform buffer object(s) to those binding locations using glBindBufferRange or glBindBufferBase, as appropriate.

Layout queries[edit]

If you did not use the std140 layout for a block, you will need to query the byte offset for each uniform within the block. The OpenGL specification explains the storage of each of the basic types, but not the alignment between types. Struct members, just like regular uniforms, each have a separate offset that must be individually queried.

Block Layout Query describes what the various pieces of block layout information means. Retrieving this information uses the standard introspection API. This can be done via the old-style API for uniforms or via the newer Program Interface Query API.

Limitations[edit]

Each shader stage has a limit on the number of separate uniform buffer binding locations. These are queried using glGetIntegerv with GL_MAX_VERTEX_UNIFORM_BLOCKS, GL_MAX_GEOMETRY_UNIFORM_BLOCKS, or GL_MAX_FRAGMENT_UNIFORM_BLOCKS.

There is also a limitation on the available storage per uniform buffer. This is queried through GL_MAX_UNIFORM_BLOCK_SIZE. This is in basic machine units (ie: bytes).

If you bind a uniform buffer with glBindBufferRange, the offset field of that parameter must be a multiple of GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT (this is a global value, not a per-program or per-block one). Thus, if you want to put the data for multiple uniform blocks in a single buffer object, you must make sure that the data for each within that block matches this alignment.

Legacy[edit]

An older form of this functionality exists through the EXT_bindable_uniform extension. This extension differs in many substantial ways. Essentially, it is a way of providing buffer object storage for a single uniform. The "single uniform" is allowed to be a struct, array, or array of structs rather than just a single basic type. So one could store multiple component members easily enough.

This extension only provides storage for this uniform; it does not expose layout. Where UBO requires the user to use standard buffer object manipulation to fill the buffer object, bindable uniform uses the same glUniform API to change the values in the bound uniform.

This also means that sharing buffers is not guaranteed. Implementations can still optimize away unused uniforms, so you cannot guarantee that you can share the same buffer object between different programs. The fact that you have to use the program object API to change the buffer object's data also means that you have to use a program object to change the stored uniform data.

Since the same hardware that supports GL_EXT_bindable_uniform is just as capable of supporting UBO, and ARB_uniform_buffer_object is a core extension, you are advised to prefer UBOs over bindable uniform.