Program Introspection

From OpenGL.org
Revision as of 02:07, 5 October 2012 by Alfonse (Talk | contribs) (Uniforms and 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.

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 these. Be advised that the new APIs provide access to more information than can be queried here.

Attributes

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 query the uniform blocks, get their lists of active uniform indices, and only look at active uniform indices that are not on that list.

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. 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.
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 outside of a block, but getting information about the uniform block itself, or uniforms within the block, 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.

Subroutines

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.