Uniform (GLSL): Difference between revisions

From OpenGL Wiki
Jump to navigation Jump to search
m More explicitly explanation for the name
 
(38 intermediate revisions by 5 users not shown)
Line 1: Line 1:
A '''uniform''' is a global [[GLSL]] variable declared with the "uniform" storage qualifier. These act as parameters that the user of a shader program can pass to that program. They are stored in a [[GLSL Objects|program object]].
{{shader float}}


Uniforms are so named because they do not change from one execution of a shader program to the next within a particular rendering call. This makes them unlike shader stage inputs and outputs, which are often different for each invocation of a program stage.
A '''uniform''' is a global [[Shader]] variable declared with the "uniform" [[Type Qualifier (GLSL)#Storage qualifier|storage qualifier]]. These act as parameters that the user of a shader program can pass to that program. Their values are stored in a [[GLSL Objects|program object]].
 
Uniforms are so named because they do not change from one shader invocation to the next within a particular rendering call thus their value is ''uniform'' among all invocations. This makes them unlike shader stage inputs and outputs, which are often different for each invocation of a shader stage.


== GLSL definition and behavior ==
== GLSL definition and behavior ==
Line 7: Line 9:
Uniform variables must be defined in GLSL at global scope.
Uniform variables must be defined in GLSL at global scope.


Uniforms can be of any type, or any aggregation of types. The following is all legal GLSL code:
Uniforms can be of any [[Data Type (GLSL)|type, or any aggregation of types]]. The following are all legal GLSL code:


<source lang=glsl>
<source lang=glsl>
Line 23: Line 25:
</source>
</source>


Uniforms are implicitly constant; attempting to change them will result in a compiler error. Similarly, you cannot pass a uniform as an <code>out</code> or <code>inout</code> parameter to a function.
Uniforms are implicitly constant, within the shader (though they are not [[Constant Expression]]s). Attempting to change them with shader code will result in a compiler error. Similarly, you cannot pass a uniform as an {{code|out}} or {{code|inout}} [[Function Parameter|parameter to a function]].


Uniforms are intended to be set by the user. However, you can initialize them to a default value using standard GLSL initalizer syntax:
Uniforms are intended to be set by the user from OpenGL, rather than within the shader. However, you can initialize them to a default value using standard [[Data_Type_(GLSL)#Constructors_and_initializers|GLSL initalizer syntax]]:


<source lang=glsl>
<source lang=glsl>
Line 31: Line 33:
</source>
</source>


This will cause the uniform to have this vector as its value until the user changes it.
This will cause the uniform to have this vector as its value, until the user changes it.


Dirver bug note: Some drivers do not implement uniform initializers correctly.
{{plat note|Unknown|Some drivers do not implement uniform initializers correctly.}}
 
=== Explicit uniform location ===
{{infobox feature
| name = Explicit Uniform Location
| core = 4.3
| core_extension = {{extref|explicit_uniform_location}}
}}
{{snippet|:Uniform (GLSL)/Explicit Uniform Location}}


== Active uniforms ==
== Active uniforms ==
Line 43: Line 53:
== Implementation limits ==
== Implementation limits ==


The number of active uniforms available is bound by a set of limits. Each shader stage has a limit on the number of available uniforms. The per-stage limits are the constants GL_MAX_VERTEX_UNIFORM_COMPONENTS, GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, and GL_MAX_FRAGMENT_UNIFORM_COMPONENTS. You can query these limits with glGetIntegerv.
The number of active uniforms available is bound by a set of limits. Each shader stage has a limit on the number of available uniforms. The per-stage limits are the constants {{enum|GL_MAX_VERTEX_UNIFORM_COMPONENTS}}, {{enum|GL_MAX_GEOMETRY_UNIFORM_COMPONENTS}}, and {{enum|GL_MAX_FRAGMENT_UNIFORM_COMPONENTS}} (also {{enum|GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS}} and {{enum|GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS}} if {{require|4.0|tessellation_shader}}, and {{enum|GL_MAX_COMPUTE_UNIFORM_COMPONENTS}} if {{require|4.3|compute_shader}}). You can query these limits with {{apifunc|glGet|Integerv}}, but they are all quite generous—at least 1024 in OpenGL 3.0+.


The limit refers to the quantity of space for individual floats, integers, or booleans. A vec3 is expected to take up 3 components. A mat2x4 should take up 8 components.
The limit refers to the quantity of space for individual floats, integers, or booleans. A {{code|vec3}} is expected to take up 3 components. Matrix types will take up ''no more than'' 4 * the smallest count of rows/columns. Thus, a {{code|mat2x3}} will not take up any more than 8 components and may take up less. Arrays of these will take up the array size * that number of components. Double-precision values (from GL 4.0/{{extref|gpu_shader_fp64}}) will take up 2x the space of single-precision equivalents.


Implementation note: OpenGL implementations are allowed to reject shaders for implementation-dependent reasons. So you can have fewer active uniform components by your reckoning and still fail to link due to uniform limits. This is usually on hardware that is inately vector hardware. Pre GeForce 8xxx hardware, and all ATi hardware does this. In this case, you should assume that each separate uniform takes up 4 components, much like it would in D3D. That means a "uniform float" is 4 components, a mat2x4 is 16 components (each row is 4 components), but a mat4x2 is 8 components.
Implementation note: OpenGL implementations are allowed to reject shaders for implementation-dependent reasons. So you can have fewer active uniform components by your reckoning and still fail to link due to uniform limits. This is usually on hardware that is innately vector hardware. Pre-GeForce 8xxx hardware, and all ATi hardware does this. In this case, you should assume that each separate uniform takes up 4 components, much like it would in D3D. That means a "uniform float" is 4 components, a mat2x4 is 16 components (each row is 4 components), but a mat4x2 is 8 components.


ATI/AMD note: The ATI max component values are wrong. To get the actual number of components, you must divide the result from GL_MAX_*_UNIFORM_COMPONENTS by 4.
Do recall that these limits are for active uniforms only. Uniforms that are deemed inactive are not relevant to this limit.


Do recall that these limits are for active uniforms only. Uniforms that are deemed inactive are not relevant to this limit.
The maximum number of uniform locations that can be explicitly assigned in a program is defined by {{enum|GL_MAX_UNIFORM_LOCATIONS}}. This limits the numbers you can use when giving uniforms explicit locations.


== Uniform management ==
== Uniform management ==
Line 59: Line 69:
Therefore, it is a program linker error to have a uniform in a vertex and fragment shader that uses the same name, but has a different type in each shader.
Therefore, it is a program linker error to have a uniform in a vertex and fragment shader that uses the same name, but has a different type in each shader.


Each active uniform has a ''location''. The location is a numeric handle to that uniform; it functions as a shorthand that is faster to search for than the uniform's name. Uniform locations are unique to a specific program. Even if you define the exact same set of uniforms in two different programs, OpenGL does not guarantee that the same uniforms in the two programs will have the same location. So you must keep track of each uniform location for each program.
Each active uniform has a ''location''. The location is a numeric handle to that uniform; it functions as a shorthand that is faster to search for than the uniform's name. Uniform locations are unique to a specific program. If you do not explicitly assign a uniform to a location (via the {{require|4.3|explicit_uniform_location}} feature mentioned above), then OpenGL will assign them arbitrarily. In this case, even if you define the exact same set of uniforms in two different programs, OpenGL does not guarantee that the same uniforms in the two programs will have the same location. So if you do not explicitly define the locations for uniforms, you must keep track of them individually for each program.
 
If you have a uniform name, you can get the uniform location via this function:
 
  GLint glGetUniformLocation(GLuint ''program'', const char *''name'');
 
The ''program'' is the program object name that you want to find a uniform for. This must be a program that has successfully linked. And ''name'' is the name of the uniform you wish to search for. The return value is -1 if ''name'' isn't an ''active'' uniform in the program, ''name'' is the name of a uniform block (see below), or ''program'' isn't a successfully linked program. Otherwise, the return value is the uniform's location.
 
The ''name'' of the uniform does not have to be a simple name. If you want to use a struct of uniforms, each individual field in the struct has a separate location. For example, take this GLSL uniform definition:
 
<source lang=glsl>
struct MyStruct
{
  vec2 firstField;
  vec4 secondField;
  mat2 thirdField;
};
 
uniform MyStruct mainUniform;
</source>
 
The name "mainUniform" does not have a location; calling ''glGetUniformLocation'' on it will return -1. However, each of mainUniform's fields do have a location. So you can call "glGetUniformLocation(program, "mainUniform.secondField");" just fine.
 
Arrays are handled simply. Take this GLSL uniform definition:
 
<source lang=glsl>
uniform vec3 positions[20];
</source>
 
Each individual element in the uniform array has a location. The names of them are "positions[2]", "positions[3]", etc. However, the uniform location for "positions" and "positions[0]" are the same; they point to the first element of the array.
 
If you use the array uniform upload functions on an array location, then the referenced location and those following it will be updated.
 
Arrays of structures are special. Take this as an example:
 
<source lang=glsl>
uniform MyStruct manyStructs[3];
</source>


Struct uniforms, as mentioned above, do not have a location. Therefore, each entry in the array does not have a location; "manyStructs[0]" will return -1. Each struct field of each array element has its own uniform location. So you will need to set "manyStructs[0].firstField" and "manyStructs[1].firstField" separately.
If you have a uniform name, you can get the uniform location via [[Program Introspection]]. The [[Program Introspection#Naming|naming convention for variables]] allows you to get the uniform location of an array (of basic types) as a whole, as well as elements within the array or the elements of structures.


The only thing you can use a uniform location for is to change the uniform's value. This is done with a large set of functions of the form <code>glUniform*</code>, where * defines the type of value to upload. These can upload matrices, vectors, individual values, and arrays of each of these.
For arrays of [[Basic Type (GLSL)|Basic Type]]s, the location of each element in the array will be the location of the array + the array index. However, for structs (or arrays of structs), if the locations were not explicitly specified then the location of any particular element will have no relation to any other element. So you cannot count on the next element being one location index higher than the previous. This is true even for arrays of structs.


However, in order to change a uniform value, you must first bind the program to the context with <code>glUseProgram</code>. The <code>glUniform*</code> functions do not take a program object name; they use the currently bound program.
=== Changing uniform values ===


=== Sampler uniforms ===
The purpose of getting the uniform location is to change the uniform's value. This is done with a large set of functions of the form {{apifunc|glUniform|*}}, where * defines the type of value to upload. These can upload matrices, vectors, individual values, and arrays of each of these.
{{main|GLSL Samplers}}


Uniforms of sampler types are used in GLSL to represent a texture of a particular kind. Therefore, sampler types represent textures. The way a program is associated with textures is somewhat unintuitive. The mapping is done with the rendering context.
However, in order to change a uniform value, you must first bind the program to the context with {{apifunc|glUseProgram}}. The {{apifunc|glUniform|*}} functions do not take a program object name; they use the currently bound program. If you are using {{require|4.1|separate_shader_objects}}, you may use the {{apifunc|glProgramUniform|*}} functions to set uniforms directly on a program, without having to bind the program first.


== Uniform blocks and buffers ==
== Uniform blocks and buffers ==
{{main|Uniform Buffer Objects}}
{{main|Uniform Buffer Objects}}


It is often useful to store a set of uniforms in storage that is separate from the program object. This can allow for fast switching between sets of uniforms, as well as having multiple programs share uniform data. This is done by using GLSL uniform blocks and creating [[Buffer Objects]] for storing that data. Collectively, this concept is called [[Uniform Buffer Objects]].
It is often useful to store a set of uniforms in storage that is separate from the program object. This can allow for fast switching between sets of uniforms, as well as having multiple programs share uniform data. This is done by declaring a group of uniforms to be in an [[Interface Block (GLSL)|Interface Block]], then using storage in a [[Buffer Object]] to store those uniforms. Collectively, this concept is called [[Uniform Buffer Object]]s.


Samplers cannot be part of uniform blocks.
[[Opaque Type|Opaque types]] like [[Sampler (GLSL)|samplers]] cannot be part of uniform blocks.


== Accessing uniform information ==
== Accessing uniform information ==
{{main|Program Introspection}}


If you want to inspect uniforms to get more information out of them (types, array sizes, etc), there is an API to do so.
Information about uniforms, whether global or within [[Buffer Backed Interface Block|interface blocks]], can be queried via the introspection API.
 
All uniforms, whether uniform block names or just uniform names, are assigned an index when the program is linked. This index is ''not'' the same as a uniform location or a uniform block index. You can query the indices for a list of uniform names with this function:
 
  void glGetUniformIndices(GLuint ''program'', GLsizei ''uniformCount'', const char ** ''uniformNames'', GLuint *''uniformIndices'');
 
This will cause the array ''uniformIndices'', which is of size ''uniformCount'' to be filled with the indices for the strings in the ''uniformNames'' list (also of size ''uniformCount''); If a uniform name in the string list doesn't correspond to the name of an active uniform, then the corresponding index in ''uniformIndices'' will be GL_INVALID_INDEX.
 
The uniform indices are between 0 and GL_ACTIVE_UNIFORMS (an integer queried with glGetProgramiv). If you simply want to iterate over all of the available uniforms, you may simply query GL_ACTIVE_UNIFORM and loop over each uniform index on the half-open range [0, GL_ACTIVE_UNIFORMS).
 
Given the index, you can query the name of the uniform with this function:
 
  void glGetActiveUniformName( GLuint ''program'', GLuint ''uniformIndex'', GLsizei ''bufSize'', GLsizei *''length'', char *''uniformName'');
 
This function stores the name in the ''uniformName'' buffer, which is of size ''bufSize'' bytes. The actual length of ''uniformName'' is stored in ''length'' (unless ''length'' is NULL, which is allowed).
 
General information about uniforms can be queried with this function, which can retrieve information for multiple uniforms at once:
 
  void glGetActiveUniformsiv( GLuint ''program'', GLsizei ''uniformCount'', GLconstuint *''uniformIndices'', GLenum ''pname'', GLint *''params'' );
 
The ''uniformIndices'' array is a list of uniform indices ''uniformCount'' in length. These are the uniforms that the user is asking to acquire. ''pname'' is an enum that determines what information to query for the uniforms. ''params'' are the values that get returned; it is an array ''uniformCount'' in length. One value for each uniform index is generated.
 
The possibilities for ''pname'' are:
 
* GL_UNIFORM_TYPE: Retrieves the GLenum for the uniform's type.
* GL_UNIFORM_SIZE: Retrieves the size of the uniform. For arrays, this is the length of the array*. For non-arrays, this is 1.
* GL_UNIFORM_NAME_LENGTH: The length of that uniform's name.
* GL_UNIFORM_BLOCK_INDEX: The uniform block index for this uniform. If this uniform is not in a block, the value will be -1.
* GL_UNIFORM_OFFSET: The byte offset into the beginning of the uniform block for this uniform. If the uniform is not in a block, the value will be -1.
* GL_UNIFORM_ARRAY_STRIDE: The byte stride for elements of the array, for uniforms in a uniform block. For non-array uniforms in a block, this value is 0. For uniforms not in a block, the value will be -1.
* GL_UNIFORM_MATRIX_STRIDE: The byte stride for columns of a column-major matrix or rows for a row-major matrix, for uniforms in a uniform block. For non-matrix uniforms in a block, this value is 0. For uniforms not in a block, the value will be -1.
* GL_UNIFORM_IS_ROW_MAJOR: GL_TRUE if the matrix is row-major and the uniform is in a block. If the uniform is not in a block, the uniform is column-major, or simply not a matrix type, GL_FALSE is returned.
 
<nowiki>*</nowiki>: To facilitate optimizations, OpenGL implementations are allowed to implicitly shrink arrays if they can determine, from the linked program code, that certain array indices cannot be reached. Thus, this value may be smaller than what the shaders originally stated.
 
An older function, superseded by glGetActiveUniformName and glGetActiveUniformsiv also exists.
 
  void glGetActiveUniform( GLuint ''program'', GLuint ''index'', GLsizei ''bufSize'', GLsizei *''length'', GLint *''size'', GLenum *''type'', char *''name'' );


This retrieves the name as in glGetActiveUniformName, but it also retrieves GL_UNIFORM_TYPE in ''type'', GL_UNIFORM_SIZE in ''size'', and GL_UNIFORM_NAME_LENGTH in ''length''.


The length of the longest uniform name in a program can be queried with GL_UNIFORM_MAX_LENGTH through glGetProgramiv. You can use this along with GL_ACTIVE_UNIFORMS to allocate an array of strings that will be sufficiently large enough to hold the string names for a program's uniforms.


[[Category:OpenGL Shading Language]]
[[Category:OpenGL Shading Language]]

Latest revision as of 15:58, 18 May 2020

A uniform is a global Shader variable declared with the "uniform" storage qualifier. These act as parameters that the user of a shader program can pass to that program. Their values are stored in a program object.

Uniforms are so named because they do not change from one shader invocation to the next within a particular rendering call thus their value is uniform among all invocations. This makes them unlike shader stage inputs and outputs, which are often different for each invocation of a shader stage.

GLSL definition and behavior

Uniform variables must be defined in GLSL at global scope.

Uniforms can be of any type, or any aggregation of types. The following are all legal GLSL code:

struct TheStruct
{
  vec3 first;
  vec4 second;
  mat4x3 third;
};

uniform vec3 oneUniform;
uniform TheStruct aUniformOfArrayType;
uniform mat4 matrixArrayUniform[25];
uniform TheStruct uniformArrayOfStructs[10];

Uniforms are implicitly constant, within the shader (though they are not Constant Expressions). Attempting to change them with shader code will result in a compiler error. Similarly, you cannot pass a uniform as an out or inout parameter to a function.

Uniforms are intended to be set by the user from OpenGL, rather than within the shader. However, you can initialize them to a default value using standard GLSL initalizer syntax:

uniform vec3 initialUniform = vec3(1.0, 0.0, 0.0);

This will cause the uniform to have this vector as its value, until the user changes it.

Platform Issue (Unknown): Some drivers do not implement uniform initializers correctly.

Explicit uniform location

Explicit Uniform Location
Core in version 4.6
Core since version 4.3
Core ARB extension ARB_explicit_uniform_location
V · E

Uniforms defined outside of Interface Blocks have a location. This location can be directly assigned in the shader, using this syntax:


layout(location = 2) uniform mat4 modelToWorldMatrix;

Calling glGetUniformLocation(prog, "modelToWorldMatrix") is guaranteed to return 2. It is illegal to assign the same uniform location to two uniforms in the same shader or the same program. Even if those two uniforms have the same name and type, and are defined in different shader stages, it is not legal to explicitly assign them the same uniform location; a linker error will occur.

All non-array/struct types will be assigned a single location. Arrays and structs will be assigned sequentially increasing locations, starting with the given location. Given this:

layout(location = 2) uniform mat4 some_mats[10];

some_mats will be assigned all of the uniform locations on the half-open range [2, 12). This will apply for nested types. Consider the following:

struct Thingy
{
  vec4 an_array[3];
  int foo;
};
layout(location = 2) uniform Thingy some_thingies[6];

Each Thingy takes up 4 uniform locations; the first three going to an_array and the fourth going to foo. Thus, some_thingies takes up 24 uniform locations.

Uploading arrays of uniforms with one of the glUniform*v functions will work. For example, uniform location 2 represents the array `some_thingies[0].an_array`. As such, you can upload an array of vec4s to this array with glUniform4fv(2, 3, ...);.

If two uniforms in a program are given the same explicit location, then they refer to the same uniform. This means they must also match in variable name, type, array-index, qualifiers, etc. The following would be illegal:

layout(location = 2) uniform mat4 some_mats[10];
layout(location = 6) uniform vec4 some_vecs[4];

some_mats takes up 10 uniform locations, from [2, 12). But since some_vecs starts at uniform location 6, it would have the same location as some_mats[4]. But it wouldn't have the same name, or same type, or other characteristics. Even if some_vecs was a mat4, it would not be the same, since they don't have the same name or same array index.

The maximum number of available locations within a single program is GL_MAX_UNIFORM_LOCATIONS, which will be at least 1024 locations. You may not use a uniform location outside of the range [0, GL_MAX_UNIFORM_LOCATIONS), nor may the sequential assignment of uniform locations due to array/struct aggregation go outside of this range.

Active uniforms

GLSL compilers and linkers try to be as efficient as possible. Therefore, they do their best to eliminate code that does not affect the stage outputs. Because of this, a uniform defined in a shader file does not have to be made available in the linked program. It is only available if that uniform is used by code that affects the stage output, and that the uniform itself can change the output of the stage.

Therefore, a uniform that is exposed by a fully linked program is called an "active" uniform; any other uniform specified by the original shaders is inactive. Inactive uniforms cannot be used to do anything in a program.

Implementation limits

The number of active uniforms available is bound by a set of limits. Each shader stage has a limit on the number of available uniforms. The per-stage limits are the constants GL_MAX_VERTEX_UNIFORM_COMPONENTS, GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, and GL_MAX_FRAGMENT_UNIFORM_COMPONENTS (also GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS and GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS if OpenGL 4.0 or ARB_tessellation_shader, and GL_MAX_COMPUTE_UNIFORM_COMPONENTS if OpenGL 4.3 or ARB_compute_shader). You can query these limits with glGetIntegerv, but they are all quite generous—at least 1024 in OpenGL 3.0+.

The limit refers to the quantity of space for individual floats, integers, or booleans. A vec3 is expected to take up 3 components. Matrix types will take up no more than 4 * the smallest count of rows/columns. Thus, a mat2x3 will not take up any more than 8 components and may take up less. Arrays of these will take up the array size * that number of components. Double-precision values (from GL 4.0/ARB_gpu_shader_fp64) will take up 2x the space of single-precision equivalents.

Implementation note: OpenGL implementations are allowed to reject shaders for implementation-dependent reasons. So you can have fewer active uniform components by your reckoning and still fail to link due to uniform limits. This is usually on hardware that is innately vector hardware. Pre-GeForce 8xxx hardware, and all ATi hardware does this. In this case, you should assume that each separate uniform takes up 4 components, much like it would in D3D. That means a "uniform float" is 4 components, a mat2x4 is 16 components (each row is 4 components), but a mat4x2 is 8 components.

Do recall that these limits are for active uniforms only. Uniforms that are deemed inactive are not relevant to this limit.

The maximum number of uniform locations that can be explicitly assigned in a program is defined by GL_MAX_UNIFORM_LOCATIONS. This limits the numbers you can use when giving uniforms explicit locations.

Uniform management

Like regular OpenGL Objects, program objects encapsulate certain state. In this case, this state is a set of uniforms that will be used when rendering with that program. All of the stages within a program object use the same set of uniforms. Thus, if you have a uniform named "projectionMatrix" defined as a mat4 in both the vertex and the fragment stages, then there will be only one uniform of that name exposed by the program object. Changing this uniform will affect both the vertex and fragment stages.

Therefore, it is a program linker error to have a uniform in a vertex and fragment shader that uses the same name, but has a different type in each shader.

Each active uniform has a location. The location is a numeric handle to that uniform; it functions as a shorthand that is faster to search for than the uniform's name. Uniform locations are unique to a specific program. If you do not explicitly assign a uniform to a location (via the OpenGL 4.3 or ARB_explicit_uniform_location feature mentioned above), then OpenGL will assign them arbitrarily. In this case, even if you define the exact same set of uniforms in two different programs, OpenGL does not guarantee that the same uniforms in the two programs will have the same location. So if you do not explicitly define the locations for uniforms, you must keep track of them individually for each program.

If you have a uniform name, you can get the uniform location via Program Introspection. The naming convention for variables allows you to get the uniform location of an array (of basic types) as a whole, as well as elements within the array or the elements of structures.

For arrays of Basic Types, the location of each element in the array will be the location of the array + the array index. However, for structs (or arrays of structs), if the locations were not explicitly specified then the location of any particular element will have no relation to any other element. So you cannot count on the next element being one location index higher than the previous. This is true even for arrays of structs.

Changing uniform values

The purpose of getting the uniform location is to change the uniform's value. This is done with a large set of functions of the form glUniform*, where * defines the type of value to upload. These can upload matrices, vectors, individual values, and arrays of each of these.

However, in order to change a uniform value, you must first bind the program to the context with glUseProgram. The glUniform* functions do not take a program object name; they use the currently bound program. If you are using OpenGL 4.1 or ARB_separate_shader_objects, you may use the glProgramUniform* functions to set uniforms directly on a program, without having to bind the program first.

Uniform blocks and buffers

It is often useful to store a set of uniforms in storage that is separate from the program object. This can allow for fast switching between sets of uniforms, as well as having multiple programs share uniform data. This is done by declaring a group of uniforms to be in an Interface Block, then using storage in a Buffer Object to store those uniforms. Collectively, this concept is called Uniform Buffer Objects.

Opaque types like samplers cannot be part of uniform blocks.

Accessing uniform information

Information about uniforms, whether global or within interface blocks, can be queried via the introspection API.