Program Introspection

Revision as of 02:51, 19 October 2012 by Alfonse (Talk | contribs) (Shader storage blocks)

Jump to: navigation, search

Program Introspection is a mechanism for taking a program object and querying information about it, so as to be able to interface and interact with it. For example, if there is a uniform, you may need to query its location so that you can set its value.


The introspection APIs will often handle make a single "variable" definition in GLSL appear as though it were multiple variables. This is done for variables that are not basic types or arrays of basic types (note that in GLSL, "basic types" includes vector and matrix types).

For example, consider the following:

struct A_Struct
  vec4 first;
  vec2 second;
  vec2 third[3];
uniform A_Struct unif;

The struct itself cannot be queried via the introspection API; the struct is just a prototype, an aggregate type definition. The variable unif​ is a uniform​, of type `A_Struct`.

However, if you try to get the uniform location, or any other property, of unif​, you will be unable to do so. As far as the introspection API is concerned, there is no unif​. Because the introspection API is built around basic types, struct aggregates of basic type are not directly visible.

Instead, each sub-element of the struct that is a basic type is visible. So there is a uniform named unif.first​. There is a uniform named unif.second​. And so forth.

This rule is applied recursively. Consider the following:

struct Inner
  vec2 inOne;
  vec4 inTwo;
struct Outer
  vec4 first;
  Inner data;
  vec2 second;
  vec2 third[3];
uniform Outer unif;

The uniforms generated from this are as follows: unif.first​,​,​, etc. There is no​ variable as far as the introspection API is concerned.

Arrays work differently, depending on whether they are arrays of basic types or arrays of aggregates (structs or arrays are aggregates. Arrays of arrays requires either GL 4.3 or the ARB_arrays_of_arrays extension).

An array of basic type represents a single resource:

struct Aggregate
  vec2 main;
  vec2 sec[3];
uniform vec3 anArray[7];
uniform Aggregate unif;

anArray[0]​ is a single resource of type vec3​, which has an array size of 7. There is no resource named anArray[3]​; just for index 0. Similarly, unif.sec[0]​ is a single resource of type vec2​, which has an array size of 3.

Note that the array index can be removed in these cases. Thus the query-by-name APIs will accept either anArray​ or anArray[0]​. However, if you query the name, you will always get the "[]" version.

Arrays of aggregates are more complicated. They work like structs; each individual element is taken as a separate resource. Consider:

struct Aggregate
  vec2 main;
  vec2 sec[3];
uniform Aggregate unifArray[5];

There is no uniform named unifArray​. However, there is a uniform named unifArray[0].main​. There is one named unifArray[2].sec[0]​, which is an array of basic types. There are five of each of these. As before, the bottom-level array can be clipped off: unifArray[2].sec​ is equivalent to unifArray[2].sec[0]​.

These rules are applied recursively up the hierarchy.

Variables declared within an interface block will be prefixed with the block's name only if the block was defined without an instance name.

Members of interface blocks that are declared as arrays of interface blocks do not get the "[#]" notation. The blocks *themselves* will have that notation (where applicable), but the members do not. Each element of a block array is separate, but the queriable properties of the members of those blocks are the same.

Shader storage blocks

Shader storage block
Core in version 4.5
Core since version 4.3

The array rules work slightly differently for shader storage block members. They have the concept of a "top-level array".

When recursively moving through the members of a shader storage block, the first array encountered is considered the "top-level array." This array is considered special, and it has a special size field (separate from the array size) in the query API. Top-level arrays are considered a single resource.

Consider this:

buffer SSBlock
  vec2 first[10];
  vec3 double_dim[2][5];
  vec4 triple_dim[5][4][8];

first[0]​ is a top-level array, with a type of vec2​ and a top-level array size of 10. There is no resource named SSBlock.first[3]​.

double_dim[0][0]​ is a top-level array, with a top-level array size of 2. But it also has a regular array size of size 5, with a type of vec3​. So there is only one resource; there is no double_dim[0][3]​ and so forth, just the base resource.

triple_dim[0][0][0]​ is a top-level array, with a top-level array size of 5. It also has a regular array size of 8. However, there is another resource named triple_dim[0][1][0]​. And two more at that.

In total, the above shader storage block definition has 6 member resources, 4 of which are derived from triple_dim​.

With SS-Blocks, the regular array index comes from the last array index, while the top-level index comes from the first. And the top-level takes priority, so if there is only one array index, it is the top-level array index.

Old style

The APIs in this section represent an older interface to this information. If GL 4.3 or ARB_program_interface_query are not available, you should use them. Be advised that the new APIs are the only way to query the following information:

  • Shader storage block information, as well as the buffer variables stored in them.
  • Fragment shader output variable information, besides the fragment color number and output index. Properties like size, type, etc.
  • Transform Feedback variable information.


If a program has a Vertex Shader, vertex shader inputs, aka Vertex Attributes, can be queried. Vertex attributes can be active or inactive. Attributes that are unused are inactive; they do not have a binding. The number of active attributes in a program can be retrieved with glGetProgramiv with GL_ACTIVE_ATTRIBUTES.

To retrieve information about an attribute, call this function:

 void glGetActiveAttrib( GLuint program​, GLuint index​, GLsizei bufSize​, GLsizei *length​, GLint *size​, GLenum *type​, char *name​ );

The index​ is a number on the half-open range [0, GL_ACTIVE_ATTRIBUTES); it represents a particular active attribute. name​ will be filled in with the name of the attribute; bufSize​ is the size of this character array. If length​ is not NULL, it will be filled in with the number of characters written to name​. The size​ will be filled with the number of elements in the attribute array, if the attribute is an array type. Otherwise, it will be set to 1. The type​ will be set to the OpenGL enumeration for the GLSL type of the attribute.

To get the attribute location (the one used by glVertexAttribPointer, not the index​ field used above), we use this function:

 GLint glGetAttribLocation( GLuint program​, const char *name​ );

If name​ is not an active attribute in program​, the function will return -1.

Fragment Outputs

Fragment color numbers and indices can be queried with these functions:

 GLint glGetFragDataLocation(GLuint program​, const char * name​);
 GLint glGetFragDataIndex(GLuint program​, const char * name​);

Note that you must provide a name for these functions. Unlike with attributes, the old-style query mechanism cannot be used to enumerate the names and properties of fragment shader outputs.

Uniforms and blocks

Active uniforms are uniforms that the shader compiler/linker has determined are in active use by the executable code. Uniforms that are not active cannot be queried.

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 enumerate all of the active uniforms by using glGet with GL_ACTIVE_UNIFORMS. Thus, all active uniform indices will have indices less than this value. You can then loop over this range.

Note: This will iterate over all active uniforms, including those declared in uniform blocks. If you want to iterate over only the active uniforms in the default block (ie: not in a block), then you must skip any uniform who's GL_UNIFORM_BLOCK_INDEX​ is not -1.

However, you can also get uniform indices from string names of the uniforms. This is done 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.

Once you have an 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​, const GLuint *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 array1. 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, which can be used to query information about this block. 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. GL_FALSE is returned if the uniform is column-major, the uniform is not in a block (all non-block matrices are column-major), or simply not a matrix type.
  • GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX: If the uniform defines an atomic counter, then this value will be the index of the buffer that this counter is associated with. Otherwise, it will be -1.
1: 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_ACTIVE_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.

Uniform blocks

The above APIs can query information about uniforms inside or outside of a block, but getting information about the uniform block itself, requires a different set of APIs.

Each active uniform block has an index. As with the uniform API, you can query this in two ways. You can iterate over the active uniform blocks by calling glGetIntegerv(GL_ACTIVE_UNIFORM_BLOCKS) to get the limit to iterate over. Or you can get the index for a uniform block by name with this function:

 void glGetUniformBlockIndex( GLuint program​​, const char *name​​ );

With the index, properties about the block as a while can be queried. The numerical properties can be queried with this function:

 void glGetActiveUniformBlockiv(GLuint program​, GLuint uniformBlockIndex​, GLenum pname​, GLint *params​);

pname​ must be one of these:

  • GL_UNIFORM_BLOCK_BINDING​: The current block binding, as set either within the shader or from glUniformBlockBinding.
  • GL_UNIFORM_BLOCK_DATA_SIZE: The buffer object storage size needed for this block.
  • GL_UNIFORM_BLOCK_NAME_LENGTH: The length of this block's name.
  • GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: The number of active uniforms within this block.
  • GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: params​ will be filled in with the uniform indices of all uniforms that are stored in this block. It will receive GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS number of uniforms.
  • GL_UNIFORM_BLOCK_REFERENCED_BY_*: GL_FALSE if the uniform block is not referenced by an active * shader, where * is the particular shader stage in question. It can be VERTEX_SHADER, FRAGMENT_SHADER, or GEOMETRY_SHADER. If GL 4.0/ARB_tessellation_shader, then it can also be TESS_CONTROL_SHADER or TESS_EVALUATION_SHADER. If GL 4.3/ARB_compute_shader, then COMPUTE_SHADER is also possible.

The name of a block can be queried with this function:

 void glGetActiveUniformBlockName(GLuint program​, GLuint uniformBlockIndex​, GLsizei bufSize​, GLsizei *length​, GLchar *uniformBlockName​);

You can use the GL_UNIFORM_BLOCK_NAME_LENGTH query to get how much space you should reserve.


Atomic counters

Interface query

Interface Query
Core in version 4.5
Core since version 4.3
Core ARB extension ARB_program_interface_query

This new interface provides a uniform mechanism for querying just about everything from a program. At least, you can query everything that external OpenGL code can interface with. You can't query information about number of functions (unless they're subroutines) or global variables or things like that. But uniforms, inputs/outputs, etc? All of those are made available through this consistent interface.

These APIs rely on some new concepts.Each linked program provides a number of interfaces, where each interface represents a set of active resources of some kind. An interface is a conceptual grouping. All of the uniforms, for example, are an interface. The active resources of the uniform interface represents all of the active uniforms in the program. And so forth.

The idea is to take all of the various different functions for introspecting programs and put them in a single interface that is extensible without adding new functions.


An interface represents a particular, named collection of resources that can be queried from a program. Each interface has a particular enumerator dedicated to it. The available interfaces are:

  • GL_UNIFORM: The set of active uniforms in a program. This includes uniforms located in uniform blocks.
  • GL_UNIFORM_BLOCK: The set of active uniform blocks in a program. These resources describe the blocks themselves, not the specific variables within them.
  • GL_ATOMIC_COUNTER_BUFFER: The set of active atomic counter buffers in a program. This describes the buffer bindings, not the actual atomic uniforms.
  • GL_PROGRAM_INPUT: The set of active user-defined inputs to the first shader stage in this program. If the first stage is a Vertex Shader, then this is the list of active attributes. If the program only contains a Compute Shader, then there are no inputs.
  • GL_PROGRAM_OUTPUT: The set of active user-defined outputs from the final shader stage in this program. If the final stage is a Fragment Shader, then this represents the fragment outputs that get written to individual color buffers. If the program only contains a Compute Shader, then there are no outputs.
  • GL_TRANSFORM_FEEDBACK_VARYING: The set of active outputs from the last Vertex Processing shader stage in the program, which can be used as outputs for Transform Feedback.
  • GL_BUFFER_VARIABLE: The set of active buffer variables in the program. These are all of the variables stored within shader storage blocks or defined with the buffer​ qualifier.
  • GL_SHADER_STORAGE_BLOCK: The set of active shader storage blocks. Much like the interface for uniform blocks, these resources describe the blocks themselves, not the specific variables within them.
  • GL_*_SUBROUTINE: The set of active subroutines in the program. The "*" represents the shader stage to query from; unlike other interfaces, this only queries about specific stages. The "*" can be:
  • GL_*_SUBROUTINE_UNIFORM: The set of active subroutine uniforms in the program. Subroutine uniforms behave differently from regular uniforms; they cannot be queried via the GL_UNIFORM interface. As before, the "*" represents the shader stage to query from; unlike other interfaces, this only queries about specific stages.

While the main purpose of the interfaces are to allow you to query information about the resources themselves, there is some per-interface information that is important. This information is usually an aggregate of all of the resources in the interface, such as maximum name length and such.

Per-interface information can be fetched via this function:

void glGetProgramInterfaceiv(GLuint program​, GLenum programInterface​, GLenum pname​, GLint * params​);

The programInterface​ is one of the interfaces, as defined above. pname​ is the particular data you want to query, and it gets written into params​. The possible pname​ values that can be queried from an interface are:

The number of active resources of that interface type.
The length of the longest string name among all resources of that interface type. This is useful for pre-allocating buffers if you are fetching names; you can always allocate the maximum length. As with all OpenGL string length APIs, the length includes the null-terminator. GL_ATOMIC_COUNTER_BUFFER are unnamed, so you cannot use this pname​ with that interface.
Note: The reason for the last restriction is that GL_ATOMIC_COUNTER_BUFFER describes the buffer binding, not the counters themselves. The counters are uniforms and thus their names reside in the GL_UNIFORM interface. Just like GL_UNIFORM_BLOCKs, GL_ATOMIC_COUNTER_BUFFERs contain GL_UNIFORMs.
The largest number of active variables among all resources in this interface. This can only be applied to interfaces that contain active variables. Namely, GL_UNIFORM_BLOCK, GL_SHADER_STORAGE_BLOCK, and GL_ATOMIC_COUNTER_BUFFER. Thus, if you use GL_UNIFORM_BLOCK with this param, you are asking for the maximum number of active variables that any active uniform block has. Again, this is useful for preallocating buffers and so forth.
The largest number of compatible subroutines among all subroutine variables for that shader stage. This can only be used with the GL_*_SUBROUTINE interfaces.

Resource indices

Active resources within an interface have indices. Each interface for a program maintains a separate list of indices. You can get an index for an active resource in one of two ways. You can query the GL_ACTIVE_RESOURCES as above and iterate over the resources. Or you can get the resource index by name:

 GLuint glGetProgramResourceIndex(GLuint program​, GLenum programInterface​, const char * name​);

Since GL_ATOMIC_COUNTER_BUFFER resources don't have names, you cannot query their indices by name (you query for the GL_UNIFORM that references the buffer, then query it's GL_ATOMIC_COUNTER_BUFFER_INDEX​ property.

If the resource named by name​ is not an active resource, GL_INVALID_INDEX is returned.

Resource properties

Once an index for an active resource has been acquired, properties from that active resource can be queried. This is done via calls to this function:

 void glGetProgramResourceiv(GLuint program​, GLenum programInterface​, GLuint index​, GLsizei propCount​, const Glenum * props​, GLsizei bufSize​, GLsizei * length​, GLint * params​);

This function can retrieve multiple properties (though all from the same resource) into a buffer all at once. Most properties will only write one value to params​, but some will write several (in all cases, the length can be queried).

The sheer volume of information that can be queried from this interface is massive. It is all documented on glGetProgramResource's reference page, including the list of which interfaces support which properties. So there is no need to repeat it here.

There are some properties that are notable in that they cannot be queried from the older APIs or that they use different names:

For interfaces that contain other resources (uniform/shader storage blocks and atomic counter buffers), the are used to return a list of the active variables that they contain. The particular interface to use these indices with depends on what is being queried. If GL_UNIFORM_BLOCK or GL_ATOMIC_COUNTER_BUFFER is used, then the indices are indices into the GL_UNIFORM interface. If GL_SHADER_STORAGE_BLOCK is used, then they are indices into the GL_BUFFER_VARIABLE interface.
These are used to detect which shader stages use the variable. All of the variable interfaces (except GL_TRANSFORM_FEEDBACK_VARYING and the subroutine uniforms), can detect where they come from.

There is one property that cannot be queried from the above function: the resource's name. That must be queried with this function:

 GLuint glGetProgramResourceName(GLuint program​, GLenum programInterface​, GLuint index​, GLsizei bufSize​, GLsizei * length​, char * name​);

Only interfaces who's resources have names (ie: not GL_ATOMIC_COUNTER_BUFFER) can be queried this way.


While the above interface is exceedingly comprehensive, it is less than convenient for accessing certain commonly-used information. Specifically, the GL_LOCATION and GL_LOCATION_INDEX fields. These fields have special APIs that mimic functions like glGetAttribLocation or glGetFragDataIndex:

 GLint glGetProgramResourceLocation(GLuint program​, GLenum programInterface​, const char * name​);
 GLint glGetProgramResourceLocationIndex(GLuint program​, GLenum programInterface​, const char * name​);

These functions are equivalent to calling glGetProgramResourceIndex with name​, and if it returns a valid index, calling glGetProgramResource with the appropriate field. The programInterface​ parameter must match with what is allowed for querying those parameters with glGetProgramResource. So the LocationIndex​ can only be used with the GL_PROGRAM_OUTPUT interface.


This system is rather complex. So here is some example code for doing common tasks.

Iteration over all non-block uniform variables, fetching their names, types, and locations:

GLint numUniforms = 0;
glGetProgramInterfaceiv(prog, GL_UNIFORM, GL_ACTIVE_RESOURCES, &numUniforms);
const GLenum properties[4] = {GL_BLOCK_INDEX​, GL_TYPE​, GL_NAME_LENGTH​, GL_LOCATION};
for(int unif = 0; unif < numUniforms; ++unif)
  GLint values[4];
  glGetProgramResourceiv(prog, GL_UNIFORM, unif, 4, properties, 4, NULL, values);
  //Skip any uniforms that are in a block.
  if(properties[0] != -1)
  //Get the name. Must use a std::vector rather than a std::string for C++03 standards issues.
  //C++11 would let you use a std::string directly.
  std::vector<char> nameData(values[2]);
  glGetProgramResourceName(prog, GL_UNIFORM, unif, nameData.size(), NULL, &nameData[0]);
  std::string name(nameData.begin(), nameData.end() - 1);

Here's an example for iterating over all of the uniforms within each block.

GLint numBlocks = 0;
glGetProgramInterfaceiv(prog, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &numBlocks );
const GLenum blockProperties[1] = {GL_NUM_ACTIVE_VARIABLES}
const GLenum activeUnifProp[1] = {GL_ACTIVE_VARIABLES}
const GLenum unifProperties[3] = {GL_NAME_LENGTH​, GL_TYPE​, GL_LOCATION};
for(int blockIx = 0; blockIx < numBlocks; ++numBlocks)
  GLint numActiveUnifs = 0;
  glGetProgramResourceiv(prog, GL_UNIFORM_BLOCK, blockIx, 1, blockProperties, 1, NULL, numActiveUnifs);
  std::vector<GLint> blockUnifs(numActiveUnifs);
  glGetProgramResourceiv(prog, GL_UNIFORM_BLOCK, blockIx, 1, activeUnifProp, numActiveUnifs, NULL, &blockUnifs[0]);
  for(int unifIx = 0; unifIx < numActiveUnifs; ++unifIx)
    GLint values[3];
    glGetProgramResourceiv(prog, GL_UNIFORM, unifIx, 3, unifProperties, 4, NULL, values);
    //Get the name. Must use a std::vector rather than a std::string for C++03 standards issues.
    //C++11 would let you use a std::string directly.
    std::vector<char> nameData(values[0]);
    glGetProgramResourceName(prog, GL_UNIFORM, unifIx, nameData.size(), NULL, &nameData[0]);
    std::string name(nameData.begin(), nameData.end() - 1);