Difference between revisions of "Shader Subroutine"
|Line 91:||Line 91:|
== Runtime selection ==
== Runtime selection ==
== Limitations ==
== Limitations ==
Revision as of 05:23, 31 August 2013
|Core in version||4.5|
|Core since version||4.0|
|Core ARB extension||ARB_shader_subroutine|
Shader Subroutines are special GLSL functions which can have variations. The specific variation that will be called is selected by the OpenGL code.
The general idea is as follows. The shader defines some number of special functions, each of which uses the same function signature. Each such function is called a "subroutine". Each subroutine is associated with one or more "subroutine types". The type represents a specific aggregation of subroutines that could be called, a specific list of variations.
Once a subroutine type is defined, the shader can declare one or more global "variables" of that type. Each variable represents a specific, user-specified, variation of that function to be called. Because these are set from OpenGL code before rendering type, these are called "uniform"s (though they do not work like regular uniforms in most ways). Each variable represents a specific, user-defined selection from among the possible subroutines in a subroutine type. The shader code can call these subroutine uniforms as though they were functions.
The user can query indices and locations for subroutines, types, and subroutine uniforms. These queries allow the user to specify which subroutines are used in which subroutine uniforms.
|This article is a stub. You can help the OpenGL Wiki by expanding it.|
The first step in defining shader subroutines is to define a subroutine type. A subroutine type consists of a named function signature. It represents a specific set of subroutines that can be called.
A subroutine type is declared as follows:
subroutine FuncReturnType SubroutineTypeName(Type0 param0, Type1 param1, ...);
The SubroutineTypeName is the name of the subroutine type defined by this statement. Multiple different named types can use the same function signature.
A specific function definition (and only a function definition. If you use this syntax, the function must have a body) can be associated with one or more subroutine types as follows:
subroutine(SubroutineTypeName) FuncReturnType FunctionName(Type0 param0, Type1 param1, ...);
FunctionName's function signature must exactly match the subroutine type's signature.
GLSL normally allows function overloading. However, subroutine functions cannot be overloaded; you cannot declare a second FunctionName with a different set of parameters. Even if the second function is not a subroutine.
A function can be associated with multiple subroutine types by listing multiple SubroutineTypeNames, separated by commas. Obviously, all of those subroutine types must use the same signature.
The user can call FunctionName exactly as it used to, and it will have the usual behavior. To use it as a subroutine requires calling it in a different way.
A subroutine uniform can be created by using the subroutine keyword with the uniform storage qualifier, as well as a subroutine type as defined above:
subroutine uniform SubroutineTypeName SubroutineUniformName;
Each subroutine uniform represents one of the subroutine variations defined by the SubroutineTypeName. Exactly which subroutine is used for a particular uniform is defined by the user at render time.
Subroutine uniforms cannot be passed around to other GLSL code or used in any way except for the following.
Subroutine uniforms can be arrayed. With OpenGL 4.3 or ARB_arrays_of_arrays, they can even be in arrays of arrays (multidimensional arrays). When an arrayed subroutine uniform is considered active (ie: the shader has determined that it can be called), all of the array elements are active, even if the shader can determine if some of the array elements are not used.
A subroutine function can be called directly by using its function name. But this just does the regular GLSL function call logic. To actually use a subroutine for its intended purpose (switching between different functions without linking the shader), you must call the subroutine uniform. Essentially, you treat SubroutineUniformName as though it were a function who's prototype is defined by SubroutineTypeName:
vec4 ret = SubroutineUniformName(arg0, arg1, ...);
This will invoke the particular subroutine that the user specified before rendering.
Arrayed subroutine uniforms simply use an array index before the call:
vec4 ret = SubroutineUniformName(arg0, arg1, ...);
After linking, each shader stage has two sets of resources that deal with subroutines. These resources are the list of defined subroutine functions and the list of subroutine uniforms. Querying these resources is important for how to actually set these things from shaders. The OpenGL 4.3 or ARB_program_interface_query feature can be used to query these resources. If those are not available, the following dedicated query APIs can be used.
Because the list of subroutine resources (of all kinds) are broken down by shader stage, all functions that query information about them take a shadertype parameter in addition to the program object to query from. The shadertype is the shader stage enumerator name for the stage to query information about.
Each active subroutine (a subroutine function which can be used with a subroutine uniform that itself is active) has an index. There are two ways to get the index for a particular subroutine function. If you have the name of a subroutine, you can query the index with this function:
If name does not name an active subroutine function, then GL_INVALID_INDEX will be returned. Otherwise, it will be the index of the subroutine function.
To iterate through the list of all subroutine functions, you can query the total number of subroutines. This is done via this function:
To query the number of active subroutine functions, pname must be GL_ACTIVE_SUBROUTINES. This stores the number of active subroutine functions as a single integer in values.
To get the name of a subroutine function from an index, pass the index to this function:
bufsize is the total number of bytes that name points to; OpenGL will not write more than this number of bytes. If length is not NULL, the function will write the number of characters written into name.
There is no way to query the length of the name for a specific subroutine function (at least, not with this API. You must use the query API for that). However, you can query the largest subroutine function name used by a shader stage. This is done with glGetProgramStage, using the GL_ACTIVE_SUBROUTINE_MAX_LENGTH enumerator.
The name is the only information that can be queried about a subroutine function directly.
Like regular uniforms, subroutine uniforms have both a location and an index. The location is used when actually selecting which subroutine to use for that uniform, while the index is only used to query information about that uniform.
To iterate through the number of subroutine uniforms for a stage and query information about them, you must first get the number of subroutine uniform indices. This uses glGetProgramStage with GL_ACTIVE_SUBROUTINE_UNIFORMS. The valid indices range from 0 to that value minus one.
Armed with a subroutine uniform index, one can query general information about the subroutine uniform with this function:
pname defines what information is to be set into values:
- GL_NUM_COMPATIBLE_SUBROUTINES: The number of subroutine functions that can be used with this uniform.
- GL_COMPATIBLE_SUBROUTINES: This returns an array of indices for each of the subroutine functions that can be used with this uniform. values must be at least GL_NUM_COMPATIBLE_SUBROUTINES entries in size.
- GL_UNIFORM_SIZE: The number of entries in the subroutine uniform. Subroutine uniforms can be in arrays, so this is the count of array elements. If the subroutine uniform is not an array,
- GL_UNIFORM_NAME_LENGTH: The length of the uniform's name.
To get the subroutine uniform's name, call this function:
The subroutine uniform location is used to know how to assign a subroutine function index to the subroutine uniform when it comes time to render with the shader.
Regular uniform variables are assigned locations arbitrarily. Subroutine uniforms are a bit different. The number of subroutine uniform locations assigned to a particular shader stage can be determined by calling glGetProgramStage with GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS. All subroutine uniform locations less than that number (and >= 0) are active subroutine uniform locations. This is required by the specification.
Because subroutine uniforms can be arrays, there can be more subroutine uniform locations than there are subroutine uniform indices. Each subroutine uniform only counts as one for the index list, but arrayed subroutine uniforms take up multiple locations.
To get a subroutine uniform's location given the name, use this function:
If name names an arrayed subroutine uniform, then the location refers to X consecutive locations starting from the returned location, where X is the array size declared in the shader. If the subroutine uniform is not active, this function will return -1.
|Core in version||4.5|
|Core since version||4.3|
|Core ARB extension||ARB_explicit_uniform_location|
Shader Subroutines use a number of resources that can be automatically assigned to each shader stage at link time. However, the user can explicitly define them within the shader text as well, to avoid having to query them.
Subroutine functions each have a specific index that identifies that particular subroutine among all subroutines in a shader stage. This subroutine can be set from within a shader using the index layout qualifier:
layout(index = 2) subroutine(SubroutineTypeName, ...) ...;
This sets the particular subroutine function definition to index 2. No two subroutine functions may have the same index. Also, this index is subject to the limitations on the number of subroutines in a shader stage.
Each subroutine uniform variable within a shader stage has a particular position in that stage's list of subroutine uniforms. This location in the array can be set using the location layout qualifer:
layout(location = 1) subroutine uniform SubroutineTypeName subroutineVariableName;
This means that array index 1 in the call to glUniformSubroutines refers to the variable subroutineVariableName.
The number of active subroutine uniforms for this shader stage will be the largest location + 1. This means that some "active" uniform locations may be unused. If the above example were the only subroutine uniform, then the number of active subroutine uniforms will be considered to be 2, with location 0 going unusued.
Arrays of subroutine uniforms are always assigned consecutive uniform locations.
If some uniforms are user-assigned and some are linker-assigned, the linker will fill in the unused indices first, before increasing the number of active uniforms. So the number of active subroutine uniforms can be larger than this. The linker will never assign a subroutine uniform to a user-assigned subroutine uniform, even if the user-assigned one is not active.
The linking can fail if user-defined subroutine uniform assignments do not leave enough room for linker-assigned ones. Linker-assigned subroutine uniform locations for arrays must also be consecutively assigned, so if there is insufficient space to assign that many uniform locations, the linking will fail.
The state for the selection of which subroutine functions to use for which subroutine uniforms is not part of the program object. Instead, it is part of the context state, similar to how texture bindings and uniform buffer bindings are part of context state.
For each shader stage, a subroutine index must be set into each subroutine uniform. As previously stated, all active subroutine locations for a stage effectively form an array from 0 to GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS - 1. The API takes advantage of this, requiring that all active subroutine uniform locations to be set on a shader stage in a single call:
A subroutine uniform location is actually an index into the array specified by indices. Each element in this array specifies the subroutine function index to be used by that subroutine uniform.
This function performs validation on indices. It will detect:
- If one of the indices does not specify a valid subroutine function index for that shader stage. This includes subroutine function indices that are larger than the number of active ones or those that (due to explicit specification of subroutine function indices) simply does not represent a valid subroutine function.
- For each indices, if the index does not specify a subroutine function that was defined with the subroutine type for that subroutine uniform.
Note that the subroutine uniform location array can contain locations that do not correspond to an active subroutine uniform location, due to explicit specification of subroutine uniform locations. You can put any index into such a location in the array.