Difference between revisions of "Program Introspection"

From OpenGL.org
Jump to: navigation, search
(Uniforms and blocks)
(Interface query)
Line 118: Line 118:
  
 
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.
 
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.
 +
 +
=== Interfaces ===
 +
 +
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:
 +
 +
* {{enum|GL_UNIFORM}}: The set of active uniforms in a program. This includes uniforms located in uniform blocks.
 +
* {{enum|GL_UNIFORM_BLOCK}}: The set of active uniform blocks in a program. These resources describe the blocks themselves, not the specific variables within them.
 +
* {{enum|GL_ATOMIC_COUNTER_BUFFER}}: The set of active atomic counters in a program.
 +
* {{enum|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 [[Vertex Attribute|active attributes]]. If the program only contains a [[Compute Shader]], then there are no inputs.
 +
* {{enum|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_Shader#Output_buffers|fragment outputs that get written to individual color buffers.]]
 +
* {{enum|GL_TRANSFORM_FEEDBACK_VARYING}}: The set of active outputs from the last shader stage in the program that can possibly output values for [[Transform Feedback]]. All of the [[Vertex Processing]] shader stages can output transform feedback values. The ones that appear in this interface are from the last shader in the pipeline that can have their outputs be captured by TF.
 +
* {{enum|GL_BUFFER_VARIABLE}}: The set of active buffer variables in the program. These are all of the variables stored within [[Shader Storage Buffer Object|shader storage blocks]] or defined with the [[GLSL_Type_Qualifier#Buffer|{{code|buffer}}]].
 +
* {{enum|GL_SHADER_STORAGE_BLOCK}}: The set of active [[GLSL_Interface_Block#Shader_storage_blocks|shader storage blocks]] Much like the interface for uniform blocks, these resources describe the blocks themselves, not the specific variables within them.
 +
* {{enum|GL_*_SUBROUTINE}}: The set of active [[Shader Subroutine|subroutines]] in the program. The "*" represents the shader stage to query from; unlike other interfaces, this only queries about specific stages.
 +
* {{enum|GL_*_SUBROUTINE_UNIFORM}}: The set of active [[Shader Subroutine|subroutine uniforms]] in the program. Subroutine uniforms behave differently from regular uniforms; they cannot be queried via the {{enum|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 {{apifunc|glGetProgramInterface|iv}}}(GLuint {{param|program}}, GLenum {{param|programInterface}}, GLenum {{param|pname}}, GLint * {{param|params}});
 +
 +
The {{param|programInterface}} is one of the interfaces, as defined above. {{param|pname}} is the particular data you want to query, and it gets written into {{param|params}}. The possible {{param|pname}} values that can be queried from an interface are:
 +
 +
; {{enum|GL_ACTIVE_RESOURCES​}}
 +
: The number of active resources of that interface type.
 +
; {{enum|GL_MAX_NAME_LENGTH​}}
 +
: 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. {{enum|GL_ATOMIC_COUNTER_BUFFER}} are unnamed, so you cannot use this {{param|pname}} with that interface.
 +
{{note|The reason for the last restriction is that {{enum|GL_ATOMIC_COUNTER_BUFFER}} describes the ''buffer binding'', not the counters themselves. The counters are uniforms and thus their names reside there. Just like {{enum|GL_UNIFORM_BLOCK}}s, {{enum|GL_ATOMIC_COUNTER_BUFFER}}s contain {{enum|GL_UNIFORM}}s.}}
 +
; {{enum|GL_MAX_NUM_ACTIVE_VARIABLES​}}
 +
: The largest number of active variables among all resources in this interface. This can only be applied to interfaces that ''contain'' active variables. Namely, {{enum|GL_UNIFORM_BLOCK}}, {{enum|GL_SHADER_STORAGE_BLOCK}}, and {{enum|GL_ATOMIC_COUNTER_BUFFER}}. Thus, if you use {{enum|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 .
 +
; {{enum|GL_MAX_NUM_COMPATIBLE_SUBROUTINES​}}
 +
: The largest number of compatible subroutines among all subroutine variables for that shader stage. This can only be used with the {{enum|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 {{enum|GL_ACTIVE_RESOURCES}} as above and iterate over the resources. Or you can get the resource index by name:
 +
 +
  GLuint {{apifunc|glGetProgramResourceIndex}}(GLuint {{param|program}}, GLenum {{param|programInterface}}, const char * {{param|name}});
 +
 +
Since {{enum|GL_ATOMIC_COUNTER_BUFFER}} resources don't have names, you cannot query their indices by name (you query for the {{enum|GL_UNIFORM}} that references the buffer, then query it's {{enum|GL_ATOMIC_COUNTER_BUFFER_INDEX​}} property.
 +
 +
If the resource named by {{param|name}} is not an active resource, {{enum|GL_INVALID_INDEX}} is returned.
 +
 +
=== Resource properties ===
 +
 +
Once an index for an active resources has been generated, properties from that active resource can be queried. This is done via calls to this function:
 +
 +
  void {{apifunc|glGetProgramResource|iv}}(GLuint {{param|program}}, GLenum {{param|programInterface}}, GLuint {{param|index}}, GLsizei {{param|propCount}}, const Glenum * {{param|props}}, GLsizei {{param|bufSize}}, GLsizei * {{param|length}}, GLint * {{param|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 {{param|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 {{apifunc|glGetProgramResource}}'s reference page, including the list of which interfaces support which properties. So there is no need to repeat it here.
 +
 +
There is one property that cannot be queried from the above function: the resource's name. That must be queried with this function:
 +
 +
  GLuint {{apifunc|glGetProgramResourceName}}(GLuint {{param|program}}, GLenum {{param|programInterface}}, GLuint {{param|index}}, GLsizei {{param|bufSize}}, GLsizei * {{param|length}}, char * {{param|name}});
 +
 +
=== Shortcuts ===
 +
 +
While the above interface is exceedingly comprehensive, it is less than convenient for accessing certain commonly-used information. Specifically, the {{enum|GL_LOCATION}} and {{enum|GL_LOCATION_INDEX}} fields. These fields have special APIs that mimic functions like {{apifunc|glGetAttribLocation}} or {{apifunc|glGetFragDataIndex}}:
 +
 +
  GLint {{apifunc|glGetProgramResourceLocation}}(GLuint {{param|program}}, GLenum {{param|programInterface}}, const char * {{param|name}});
 +
  GLint {{apifunc|glGetProgramResourceLocationIndex}}(GLuint {{param|program}}, GLenum {{param|programInterface}}, const char * {{param|name}});
 +
 +
These functions are equivalent to calling {{apifunc|glGetProgramResourceIndex}} with {{param|name}}, and if it returns a valid index, calling {{apifunc|glGetProgramResource}} with the appropriate field. The {{param|programInterface}} parameter must match with what is allowed for querying those parameters with {{apifunc|glGetProgramResource}}. So the {{code|LocationIndex}} can only be used with the {{enum|GL_PROGRAM_OUTPUT}} interface.
 +
 +
=== Examples ===
 +
 +
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:
 +
 +
<source lang="cpp">
 +
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)
 +
    continue;
 +
 +
  //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.
 +
  std::vector<char> nameData(values[2]);
 +
  glGetProgramResourceName(prog, GL_UNIFORM, unif, nameData.size(), NULL, &nameData[0]);
 +
}
 +
</source>
  
 
{{stub}}
 
{{stub}}

Revision as of 07:24, 5 October 2012

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.

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.

Interfaces

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 counters in a program.
  • 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.
  • GL_TRANSFORM_FEEDBACK_VARYING: The set of active outputs from the last shader stage in the program that can possibly output values for Transform Feedback. All of the Vertex Processing shader stages can output transform feedback values. The ones that appear in this interface are from the last shader in the pipeline that can have their outputs be captured by TF.
  • 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​.
  • 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.
  • 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:

GL_ACTIVE_RESOURCES​
The number of active resources of that interface type.
GL_MAX_NAME_LENGTH​
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 there. Just like GL_UNIFORM_BLOCKs, GL_ATOMIC_COUNTER_BUFFERs contain GL_UNIFORMs.
GL_MAX_NUM_ACTIVE_VARIABLES​
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 .
GL_MAX_NUM_COMPATIBLE_SUBROUTINES​
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 resources has been generated, 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 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​);

Shortcuts

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.

Examples

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)
    continue;
 
  //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.
  std::vector<char> nameData(values[2]);
  glGetProgramResourceName(prog, GL_UNIFORM, unif, nameData.size(), NULL, &nameData[0]);
}