Name

    ARB_shader_subroutine

Name Strings

    GL_ARB_shader_subroutine

Contact

    Jeff Bolz, NVIDIA Corporation (jbolz 'at' nvidia.com)

Contributors

    Barthold Lichtenbelt, NVIDIA
    Bill Licea-Kane, AMD
    Bruce Merry, ARM
    Eric Werness, NVIDIA
    Graham Sellers, AMD
    Greg Roth, NVIDIA
    Nick Haemel, AMD
    Pat Brown, NVIDIA
    Pierre Boudier, AMD
    Piers Daniell, NVIDIA

Notice

    Copyright (c) 2010-2014 The Khronos Group Inc. Copyright terms at
        http://www.khronos.org/registry/speccopyright.html

Status

    Complete. Approved by the ARB at the 2010/01/22 F2F meeting.
    Approved by the Khronos Board of Promoters on March 10, 2010.

Version

    Last Modified Date:         02/28/2014
    Revision:                   19

Number

    ARB Extension #90

Dependencies

    This extension is written against the OpenGL 3.2 core specification and
    version 1.50 of the GLSL specification.

    ARB_gpu_shader5 is required.

    This extension interacts with NV_gpu_program5.

    This extension interacts trivially with EXT_separate_shader_objects.

Overview

    This extension adds support to shaders for "indirect subroutine calls", 
    where a single shader can include many subroutines and dynamically select
    through the API which subroutine is called from each call site. 
    Switching subroutines dynamically in this fashion can avoid the cost of 
    recompiling and managing multiple shaders, while still retaining most of
    the performance of specialized shaders.

IP Status

    No known IP claims.

New Procedures and Functions

    int GetSubroutineUniformLocation(uint program, enum shadertype, 
                                     const char *name);
    uint GetSubroutineIndex(uint program, enum shadertype,
                            const char *name);
    void GetActiveSubroutineUniformiv(uint program, enum shadertype,
                                      uint index, enum pname, int *values);
    void GetActiveSubroutineUniformName(uint program, enum shadertype,
                                        uint index, sizei bufsize,
                                        sizei *length, char *name);
    void GetActiveSubroutineName(uint program, enum shadertype, uint index, 
                                 sizei bufsize, sizei *length, char *name);
    void UniformSubroutinesuiv(enum shadertype, sizei count,
                               const uint *indices);
    void GetUniformSubroutineuiv(enum shadertype, int location,
                                 uint *params);
    void GetProgramStageiv(uint program, enum shadertype, 
                           enum pname, int *values);

New Tokens

    Accepted by the <pname> parameter of GetProgramStageiv: 

        ACTIVE_SUBROUTINES                              0x8DE5
        ACTIVE_SUBROUTINE_UNIFORMS                      0x8DE6
        ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS             0x8E47
        ACTIVE_SUBROUTINE_MAX_LENGTH                    0x8E48
        ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH            0x8E49

    Accepted by the <pname> parameter of GetBooleanv, GetIntegerv,
    GetFloatv, GetDoublev, and GetInteger64v: 

        MAX_SUBROUTINES                                 0x8DE7
        MAX_SUBROUTINE_UNIFORM_LOCATIONS                0x8DE8

    Accepted by the <pname> parameter of GetActiveSubroutineUniformiv:

        NUM_COMPATIBLE_SUBROUTINES                      0x8E4A
        COMPATIBLE_SUBROUTINES                          0x8E4B
        UNIFORM_SIZE
        UNIFORM_NAME_LENGTH
        

Additions to Chapter 2 of the OpenGL 3.2 Specification (OpenGL Operation)

    Add a section "Subroutine Uniform Variables" after Section 2.11.4,
    "Uniform Variables"

    Subroutine uniform variables are similar to uniform variables, except they
    are context state rather than program state. Having subroutine uniforms be
    context state allows them to have different values if the program is used
    in multiple contexts simultaneously.  There is a set of subroutine
    uniforms for each shader stage.

    The command

        int GetSubroutineUniformLocation(uint program, enum shadertype, 
                                         const char *name);
        
    will return the location of the subroutine uniform variable <name> in the
    shader stage of type <shadertype> attached to <program>, with behavior otherwise
    identical to GetUniformLocation.  The value -1 will be returned if <name>
    is not the name of an active subroutine uniform.  Active subroutine
    locations are assigned using consecutive integers in the range from zero
    to the value of ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS minus one for the shader
    stage.  There is an implementation-dependent limit on the number of active
    subroutine uniform locations in each shader stage; a program will fail to
    link if the number of subroutine uniform locations required is greater
    than the value of MAX_SUBROUTINE_UNIFORM_LOCATIONS.  If <program> has not
    been successfully linked, the error INVALID_OPERATION will be generated.
    For active subroutine uniforms declared as arrays, the declared array
    elements are assigned consecutive locations.

    Each function in a shader associated with a subroutine type is considered
    an active subroutine, unless the compiler conclusively determines that the
    function could never be assigned to an active subroutine uniform.  Each
    active subroutine will be assigned an unsigned integer subroutine index
    that is unique to the shader stage.  This index can be queried with the
    command

        uint GetSubroutineIndex(uint program, enum shadertype,
                                const char *name);

    where <name> is the null-terminated name of a function in the shader stage
    of type <shadertype> attached to <program>.  Subroutine indices are assigned using
    consecutive integers in the range from zero to the value of
    ACTIVE_SUBROUTINES minus one for the shader stage.  The value INVALID_INDEX will
    be returned if <name> is not the name of an active subroutine in the
    shader stage.  After the program has been linked, the subroutine index
    will not change unless the program is re-linked.

    There is an implementation-dependent limit on the number of active
    subroutines in each shader stage; a program will fail to link if the
    number of subroutines is greater than the maximum subroutine count
    (the value of MAX_SUBROUTINES).

    Information about active subroutine uniforms can be obtained by calling

        void GetActiveSubroutineUniformiv(uint program, enum shadertype,
                                          uint index, enum pname, int *values);
        void GetActiveSubroutineUniformName(uint program, enum shadertype,
                                            uint index, sizei bufsize,
                                            sizei *length, char *name);

    <program> and <shadertype> specify the program and shader stage.  <index>
    must be an active subroutine uniform index in the range from zero to the
    value of ACTIVE_SUBROUTINE_UNIFORMS minus one for the shader stage.  If <index>
    is greater than or equal to the value of ACTIVE_SUBROUTINE_UNIFORMS, the
    error INVALID_VALUE is generated.

    For GetActiveSubroutineUniformiv, <pname> identifies a property of the
    active subroutine uniform being queried.  If <pname> is
    NUM_COMPATIBLE_SUBROUTINES, a single integer indicating the number of
    subroutines that can be assigned to the uniform is returned in <values>.
    If <pname> is COMPATIBLE_SUBROUTINES, an array of integers is returned in
    <values>, with each integer specifying the index of an active subroutine
    that can be assigned to the selected subroutine uniform.  The number of
    integers returned is the same as the value returned for
    NUM_COMPATIBLE_SUBROUTINES.  If <pname> is UNIFORM_SIZE, a single integer
    is returned in <values>.  If the selected subroutine uniform is an array,
    the declared size of the array is returned; otherwise, one is returned.
    If <pname> is UNIFORM_NAME_LENGTH, a single integer specifying the length
    of the subroutine uniform name (including the terminating null character)
    is returned in <values>.

    For GetActiveSubroutineUniformName, the uniform name is returned as a
    null-terminated string in <name>.  The actual number of characters written
    into <name>, excluding the null terminator is returned in <length>.  If
    <length> is NULL, no length is returned.  The maximum number of characters
    that may be written into <name>, including the null terminator, is
    specified by <bufsize>.  The length of the longest subroutine uniform name
    in <program> and <shadertype> is given by the value of
    ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH, which can be queried with
    GetProgramStageiv.

    The name of an active subroutine can be queried given its subroutine
    index with the command:

        void GetActiveSubroutineName(uint program, enum shadertype,
                                     uint index, sizei bufsize,
                                     sizei *length, char *name);

    <program> and <shadertype> specify the program and shader stage.  <index>
    must be an active subroutine index in the range from zero to the value of
    ACTIVE_SUBROUTINES minus one for the shader stage.  If <index> is greater than
    or equal to the value of ACTIVE_SUBROUTINES, the error INVALID_VALUE is
    generated.  The name of the selected subroutine is returned as a
    null-terminated string in <name>. The actual number of characters written
    into <name>, excluding the null terminator, is returned in <length>. If
    <length> is NULL, no length is returned. The maximum number of characters
    that may be written into <name>, including the null terminator, is
    specified by <bufsize>.  The length of the longest subroutine name in
    <program> and <shadertype> is given by the value of
    ACTIVE_SUBROUTINE_MAX_LENGTH, which can be queried with GetProgramStageiv.

    The command

        void UniformSubroutinesuiv(enum shadertype, sizei count,
                                   const uint *indices);

    will load all active subroutine uniforms for shader stage <shadertype>
    with subroutine indices from <indices>, storing <indices>[i] into the
    uniform at location i.  If <count> is not equal to the value of
    ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the program currently in use at
    shader stage <shadertype>, or if any value in <indices> is greater than or
    equal to the value of ACTIVE_SUBROUTINES for the shader stage, the error
    INVALID_VALUE is generated.  If, for any subroutine index being loaded to
    a particular uniform location, the function corresponding to the
    subroutine index was not associated (as defined in Section 6.1.2 of the
    GLSL spec) with the type of the subroutine variable at that location, then
    the error INVALID_OPERATION is generated. If no program is active for
    the shader stage identified by <shadertype>, the error INVALID_OPERATION
    is generated.

    Each subroutine uniform must have at least one subroutine to assign to the
    uniform.  A program will fail to link if any stage has one or more
    subroutine uniforms that has no subroutine associated with the subroutine
    type of the uniform.

    When UseProgram is called, the subroutine uniforms for all shader stages
    are reset to arbitrarily chosen default functions with compatible
    subroutine types.  When UseShaderProgramEXT is called, the subroutine
    uniforms for the shader stage specified by <type> are reset to arbitrarily
    chosen default functions with compatible subroutine types.


Additions to Chapter 3 of the OpenGL 3.2 Specification (Rasterization)

    None.

Additions to Chapter 4 of the OpenGL 3.2 Specification (Per-Fragment
Operations and the Frame Buffer)

    None.

Additions to Chapter 5 of the OpenGL 3.2 Specification (Special Functions)

    None.

Additions to Chapter 6 of the OpenGL 3.2 Specification (State and
State Requests)

    Add to Section 6.1.15 (Shader and Program Queries)

    The command
    
        void GetUniformSubroutineuiv(enum shadertype, int location, 
                                     uint *params);

    returns the value of the subroutine uniform at location <location> for
    shader stage <shadertype> of the current program.  If <location> is
    greater than or equal to the value of ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS
    for the shader currently in use at shader stage <shadertype>, the error
    INVALID_VALUE is generated.  If no program is active, the error
    INVALID_OPERATION is generated.

    The command

        void GetProgramStageiv(uint program, enum shadertype, 
                               enum pname, int *values);

    returns properties of the program object <program> specific to the
    programmable stage corresponding to <shadertype> in <values>. The
    parameter value to return is specified by <pname>.  If <pname> is
    ACTIVE_SUBROUTINE_UNIFORMS, the number of active subroutine variables in
    the stage is returned.  If <pname> is ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS,
    the number of active subroutine variable locations in the stage is
    returned.  If <pname> is ACTIVE_SUBROUTINES, the number of active
    subroutines in the stage is returned.  If <pname> is
    ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH or ACTIVE_SUBROUTINE_MAX_LENGTH, the
    length of the longest subroutine uniform or subroutine name, respectively,
    for the stage is returned.  The returned name length includes space for a
    null terminator.  If there is no shader of type <shadertype> in <program>,
    the values returned will be consistent with a shader with no subroutines
    or subroutine uniforms.


Modifications to The OpenGL Shading Language Specification, Version 1.50

    Including the following line in a shader can be used to control the
    language features described in this extension:

      #extension GL_ARB_shader_subroutine : <behavior>

    where <behavior> is as specified in section 3.3.

    In section 3.6, p.14 (Keywords)

    Add subroutine to the list of reserved keywords.

    Modify Section 6.1.1 (Function Calling Conventions)

    (modify the last paragraph of the section, p. 66, to forbid potential
    recursion via subroutines) Recursion is not allowed, not even statically.
    Static recursion is present if the static function-call graph of a program
    contains cycles.  This includes all potential function calls through
    variables declared as subroutine uniform (described below).  It is an
    error if a single compilation unit (shader) contains either static
    recursion or the potential for recursion through subroutine variables.

    Add a new Section 6.1.2 (Subroutines)

    Subroutines provide a mechanism allowing shaders to be compiled in a
    manner where the target of one or more function calls can be changed at
    run-time without requiring any shader recompilation.  For example, a
    single shader may be compiled with support for multiple illumination
    algorithms to handle different kinds of lights or surface materials.  An
    application using such a shader may switch illumination algorithms by
    changing the value of its subroutine uniforms.  To use subroutines, a
    subroutine type is declared, one or more functions are associated with
    that subroutine type, and a subroutine variable of that type is declared.
    The function currently assigned to the variable function is then called by
    using function calling syntax replacing a function name with the name of
    the subroutine variable.  Subroutine variables are assigned to specific
    functions only through commands (UniformSubroutinesuiv) in the OpenGL API.

    Subroutine types can be declared using a statement similar to a function 
    declaration, as follows:

        subroutine returnType subroutineTypeName(type0 arg0, type1 arg1,
                                                 ..., typen argn);

    Functions may be associated to subroutine types that have a matching 
    prototype by prepending the subroutine types to the function definition:

        subroutine(subroutineTypeName0, ..., subroutineTypeNameN)
        returnType functionName (type0 arg0, type1 arg1, ..., typen argn)
        ... // function body
    
    Subroutine declarations cannot be prototyped. It is an error to prepend
    subroutine(...) to a function declaration. It is an error to declare
    two distinct functions with the same function name within the same shader
    (i.e. overloaded function names) that are both associated to subroutine
    types.

    Subroutine types share a namespace with standard function names.
    Overloading (section 6.1) is not supported for functions that may be
    associated with subroutine types.  A program will fail to link if any
    shader includes two or more functions with the same name, at least one of
    which is associated with a subroutine type.

    Subroutine variables are required to be "subroutine uniforms", and 
    are declared with a specific subroutine type in a subroutine uniform 
    variable declaration:

        subroutine uniform subroutineTypeName subroutineVarName;

    and are called the same way simple functions are called. Subroutine
    variables may be declared as explicitly-sized arrays, which can be 
    dynamically indexed at use.

    Subroutine variables are associated to functions declared with the
    same subroutine type with the UniformSubroutinesuiv command in the OpenGL
    API. When a subroutine variable (or an element of a subroutine variable
    array) is associated to a particular function, all function calls through
    that variable will call that particular function.

Additions to the AGL/GLX/WGL Specifications

    None.

GLX Protocol

    None.

Errors

    The error INVALID_OPERATION is generated by GetSubroutineUniformLocation
    if the program object identified by <program> has not been successfully
    linked.

    The error INVALID_VALUE is generated by GetActiveSubroutineUniformiv or
    GetActiveSubroutineUniformName if <index> is greater than or equal to the
    value of ACTIVE_SUBROUTINE_UNIFORMS for the shader stage.

    The error INVALID_VALUE is generated by GetActiveSubroutineName if <index>
    is greater than or equal to the value of ACTIVE_SUBROUTINES for the shader
    stage.

    The error INVALID_VALUE is generated by UniformSubroutinesuiv if <count>
    is not equal to the value of ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the
    shader stage <shadertype>.

    The error INVALID_VALUE is generated by UniformSubroutinesuiv if any value
    in <indices> is greater than or equal to the value of ACTIVE_SUBROUTINES
    for the shader stage.

    The error INVALID_OPERATION is generated by UniformSubroutinesuiv if any
    subroutine index in <indices> identifies a subroutine not associated with
    the type of the subroutine uniform variable assigned to the corresponding
    location.

    The error INVALID_OPERATION is generated by UniformSubroutinesuiv if no
    program is active.

    The error INVALID_VALUE is generated by GetUniformSubroutineuiv if
    <location> is greater than or equal to the value of
    ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the shader stage.

    The error INVALID_OPERATION is generated by GetUniformSubroutineuiv if no
    program is active for the shader stage identified by <shadertype>.


New State

    (add to table 6.28, Program Object State, p. 293)

                                                               Initial
    Get Value                     Type        Get Command       Value  Description                  Sec.  
    ---------------------------   ----------  -----------      ------- ---------------------------  ------
    ACTIVE_SUBROUTINE_UNIFORM_    5xZ+        GetProgram-         0    Number of subroutine unif.   2.11.4
      LOCATIONS                               Stageiv                  locations in the shader
    ACTIVE_SUBROUTINE_UNIFORMS    5xZ+        GetProgram-         0    Number of subroutine unif.   2.11.4
                                              Stageiv                  variables in the shader
    ACTIVE_SUBROUTINES            5xZ+        GetProgram-         0    Number of subroutine         2.11.4
                                              Stageiv                  functions in the shader
    ACTIVE_SUBROUTINE_UNIFORM_    5xZ+        GetProgram-         0    Maximum subroutine uniform   2.11.4
      MAX_LENGTH                              Stageiv                  name length
    ACTIVE_SUBROUTINE_MAX_LENGTH  5xZ+        GetProgram-         0    Maximum subroutine name      2.11.4
                                              Stageiv                  length
    NUM_COMPATIBLE_SUBROUTINES    5x0*xZ+     GetActiveSub-       -    Number of subroutines comp-  2.11.4
                                              routineUniformiv         atible with a sub. uniform
    COMPATIBLE_SUBROUTINES        5x0*x0*xZ+  GetActiveSub-       -    List of subroutines comp-    2.11.4
                                              routineUniformiv         atible with a sub. uniform
    UNIFORM_SIZE                  5x0*xZ+     GetActiveSub-       -    Number of elements in sub.   2.11.4
                                              routineUniformiv         uniform array
    UNIFORM_NAME_LENGTH           5x0*xZ+     GetActiveSub-       -    Length of sub. uniform name  2.11.4
                                              routineUniformiv
    -                             5x0*xS      GetActiveSub-       -    Sub. uniform name string     2.11.4
                                              routineUniformName
    -                             5x0*xS      GetActiveSub-       -    Length of subroutine name    2.11.4
                                              routineName
    -                             5x0*xS      GetActiveSub-       -     Subroutine name string      2.11.4
                                              routineName

    (For the above, the "5" is indicates separate state for each of the five
    shader stages in the program.)


New Implementation Dependent State

                                                          Minimum
    Get Value                      Type  Get Command       Value   Description           Sec.   Attrib
    -----------------------------  ----  ---------------  -------  --------------------- ------ ------
    MAX_SUBROUTINES                 Z+   GetIntegerv        256    Maximum number of     2.14.1   -   
                                                                   subroutines per
                                                                   shader stage
    MAX_SUBROUTINE_UNIFORM_         Z+   GetIntegerv       1024    Maximum number of     2.X.5    -
     LOCATIONS                                                     subroutine uniform
                                                                   locations per stage


Dependencies on NV_gpu_program5:

    If NV_gpu_program5 is supported, the following edits are made to extend
    the assembly programming model documented in the NV_gpu_program4 extension
    and extended by NV_gpu_program5.  No "OPTION" line is required; the
    following capability is implied by NV_gpu_program5 program headers such as
    "!!NVfp5.0".

    New Procedures and Functions

    void ProgramSubroutineParametersuivNV(enum target, sizei count, 
                                          const uint *params);
    void GetProgramSubroutineParameteruivNV(enum target, uint index,
                                            uint *param);

    New Tokens

    Accepted by the <pname> parameter of GetProgramivARB: 

        MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV            0x8F44
        MAX_PROGRAM_SUBROUTINE_NUM_NV                   0x8F45

    (Modify "Section 2.14.1" of the ARB_vertex_program specification,
    describing program parameters.)

    Each program target has an associated array of program subroutine
    parameters. Unlike program local parameters, program subroutine parameters
    are context state rather than program state. Program subroutine parameters
    are scalar unsigned integer values that correspond to "SUBROUTINENUM"
    declarations in a program. The number of scalars is given by the
    implementation-dependent value MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV.
    The command

        void ProgramSubroutineParametersuivNV(enum target, sizei count, 
                                              const uint *params);

    updates the values of all program subroutine parameters used by the 
    currently bound program for the given program target <target>. <params> 
    points to an array of <count> values, where the first value is used to 
    update the program subroutine parameter numbered zero and the last value 
    is used to update the program subroutine parameter numbered <count> - 1. 
    The error INVALID_VALUE is generated if <count> is not equal to one plus 
    the maximum program subroutine parameter index used in the currently bound 
    program.

    Program subroutine parameters for a given target are reset to arbitrary 
    defaults when the program string is respecified, and when BindProgram is 
    called to bind a program to that target, even if the specified program is
    already bound. 

    The error INVALID_OPERATION is generated by
    ProgramSubroutineParametersuivNV if, for any number <i> in [0, <count>),
    program.subroutine[<i>] is a live parameter of a certain SUBROUTINETYPE,
    and <params>[<i>] is not a SUBROUTINENUM that was associated to that
    SUBROUTINETYPE as described in Section 2.X.5.

    Modify Section 2.X.2 of NV_gpu_program4, Program Grammar

    If a program begins with a header string defined by GL_NV_gpu_program5, 
    the following modifications apply to the program grammar:

    <FlowInstruction>       ::= <BRAop_instruction>
                              | <FLOWCCop_instruction>
                              | <IFop_instruction>
                              | <REPop_instruction>
                              | <ENDFLOWop_instruction>
                              | <CALI_instruction>

    <namingStatement>       ::= <varMods> <ATTRIB_statement>
                              | <varMods> <PARAM_statement>
                              | <varMods> <TEMP_statement>
                              | <varMods> <OUTPUT_statement>
                              | <varMods> <BUFFER_statement>
                              | <ALIAS_statement>
                              | <SUBROUTINETYPE_statement>
                              | <SUBROUTINE_statement>

    <labelList>             ::= <identifier>
                              | <identifier> "," <labelList>

    <labelInitList>         ::= /* empty */
                              | <labelList>

    <SUBROUTINETYPE_statement> ::= "SUBROUTINETYPE" <establishName> "{" 
                                <labelInitList> "}"

    <progSubroutineParam>   ::= "program" "." "subroutine" <arrayMemAbs>

    <progSubroutineParams>  ::= <progSubroutineParam>
                              | "program" "." "subroutine" <arrayRange>

    <progSubroutineInitList>::= <progSubroutineParams>
                              | <progSubroutineParams> "," 
                                <progSubroutineInitList>

    <SUBROUTINE_statement>  ::= "SUBROUTINE" <establishedName> <establishName> 
                                "=" <progSubroutineParam>
                              | "SUBROUTINE" <establishedName> <establishName> 
                                <optArraySize> "=" "{" <progSubroutineInitList> 
                                "}"

    <CALIop>                ::= "CALI"

    <CALI_instruction>      ::= <CALIop> <opModifiers> <subroutineVarName> 
                                <optArrayMem> <optBranchCond>

    <instLabel>             ::= <identifier>
                              | <identifier> "SUBROUTINENUM" "(" <int> ")"


    Modify Section 2.X.4, Program Execution Environment

    (Update the instruction set table to add CALI)

      Instr-      Modifiers 
      uction  V  F I C S H D  Out Inputs    Description
      ------- -- - - - - - -  --- --------  --------------------------------
      CALI    50 - - - - - -  -   c         indirect subroutine call

    Modify Section 2.X.5 (Program Flow Control) of the NV_gpu_program4
    specification

    (Add after the description of subroutines)

    Subroutines may be called indirectly using the CALI instruction. An 
    "indirect" call will transfer control to one of a set of labels, where
    the specific label that is used in a particular program invocation is
    set through a "subroutine" parameter (see Section 2.14.1).

    Functions that will be used for indirect subroutine calls must all be
    assigned a unique unsigned integer SUBROUTINENUM using the modified
    <instLabel> grammar rule. 

    A <SUBROUTINETYPE_statement> associates one or more subroutine labels with
    a "type". For example:

      SUBROUTINETYPE Hero { batman, robin };

    creates a SUBROUTINETYPE named "Hero" (if it does not already exist) and
    adds the subroutines whose labels are "batman" and "robin" to the
    SUBROUTINETYPE. 

    A "subroutine" parameter is a special type of program parameter whose value
    refers to one of a set of subroutines, selected by the API. A subroutine is
    given a SUBROUTINETYPE when it is declared, and it may refer to any label
    of that type. Continuing this example:

      SUBROUTINETYPE Hero { superman, wolverine };
      SUBROUTINETYPE Hero { batman, robin };
      SUBROUTINETYPE GothamHero { batman, robin };

      # anyHero may "point to" any Hero
      SUBROUTINE Hero anyHero = program.subroutine[0];
      # gothamHero may "point to" any GothamHero
      SUBROUTINE GothamHero gothamHero = program.subroutine[1];

      batman SUBROUTINENUM(0):
        ...
      robin SUBROUTINENUM(1):
        ...
      superman SUBROUTINENUM(2):
        ...
      wolverine SUBROUTINENUM(3):
        ...
      
      main:
      # could call any of the four heros
      CALI anyHero;
      # could call either batman or robin
      CALI gothamHero;

    Program subroutine parameters are assigned to labels by setting the 
    corresponding SUBROUTINENUMs via ProgramSubroutineParametersuivNV. For
    example, 
    
      uint params[2] = {2, 0};
      ProgramSubroutineParametersuivNV(target, 2, params);

    would assign program.subroutine[0] (and therefore "anyHero") to "superman",
    and program.subroutine[1] (and therefore "gothamHero") to "batman".

    All SUBROUTINENUMs must be greater than or equal to zero, and less than the 
    value of MAX_PROGRAM_SUBROUTINE_NUM_NV. A label may be assigned to multiple 
    SUBROUTINETYPEs. A program subroutine parameter may only be assigned to 
    subroutine variables of a single SUBROUTINETYPE.

    Programs that may potentially cause infinite recursion through indirect
    calls will fail to compile.


    Section 2.X.8.Z, CALI:  Indirect Subroutine Call

    The CALI instruction conditionally transfers control to the instruction
    following some label, as described in CAL. The determination of which
    label is used is described in Section 2.X.5 (Program Flow Control).

    Add to Chapter 6 (State and State Requests)

    The command

      void GetProgramSubroutineParameteruivNV(enum target, uint index,
                                              uint *params);

    obtains the current value for the program subroutine parameter numbered
    <index> for the given program target <target>, and places the single 
    unsigned integer value in the array <params>.  The error INVALID_ENUM is 
    generated if <target> specifies a nonexistent program target or a program 
    target that does not support program environment parameters.  The error 
    INVALID_VALUE is generated if <index> is greater than or equal to the
    implementation-dependent number of supported program subroutine parameters
    for the program target.

    Add various new conditions by which a program string would fail to load.

    The error INVALID_ENUM is generated by GetProgramSubroutineParameteruivNV 
    and ProgramSubroutineParametersuivNV if <target> specifies a nonexistent 
    program target.

    The error INVALID_VALUE is generated by GetProgramSubroutineParameteruivNV
    if <index> is greater than or equal to the max number of program subroutine 
    parameters, and by ProgramSubroutineParametersuivNV if <count> is <count>
    is not equal to one plus the maximum program subroutine parameter index used
    in the currently bound program.

    The error INVALID_OPERATION is generated by
    ProgramSubroutineParametersuivNV if, for any number <i> in [0, <count>),
    program.subroutine[<i>] is a live parameter of a certain SUBROUTINETYPE,
    and <params>[<i>] is not a SUBROUTINENUM that was associated to that
    SUBROUTINETYPE as described in Section 2.X.5.

    Add new implementation dependent state
                                                             Minimum
    Get Value                         Type  Get Command       Value   Description           Sec.   Attrib
    --------------------------------  ----  ---------------  -------  --------------------- ------ ------
    MAX_PROGRAM_SUBROUTINE_            Z+   GetProgramivARB   1024    Maximum number of     2.14.1   -   
      PARAMETERS_NV                                                   program subroutine
                                                                      parameters
    MAX_PROGRAM_SUBROUTINENUM_NV       Z+   GetProgramivARB    256    Maximum SUBROUTINENUM 2.X.5    -
                                                                      value


Dependencies on EXT_separate_shader_objects

    If EXT_separate_shader_objects is not supported, remove references to
    UseShaderProgramEXT.

Issues

    (1) What terms should we use to describe the various data types and
    concepts in this specification?

    RESOLVED:  This extension uses mechanisms similar to function pointers in
    C.  We aren't directly exposing function pointers, but are instead using a
    function pointer-like data type.  We are using the term "subroutine" to
    qualify various concepts in this extension.  The function pointer type is
    referred to as a "subroutine type".  Integer indices used to identify
    functions that can be assigned to a function pointer type are referred to
    as "subroutine indices".  Uniforms that can hold function pointer values
    are referred to as "subroutine uniforms".

    We considered using the term "interfaces", but were concerns about
    confusion with object-oriented programming models -- the model we are
    using is not object-oriented.  Referring instead to these limited function
    pointers as "subroutines" avoids this confusion and matches its use in
    similar circumstances. The term is not currently used in any GLSL nor
    OpenGL specification.

    (2) What happens if you try to link a program that has active subroutines
    that have no subroutines that can be assigned ot them?
    
    RESOLVED: Attempting to link a program that calls a function pointer
    with no potential associations produces a link error.

    (3) What happens if the app specifies a bad subroutine index?

    RESOLVED: There are two different forms of invalid subroutine indices --
    ones that correspond to no subroutine, and ones that correspond to a
    subroutine of the wrong type. If the app specifies a number that
    corresponds to no subroutine, an INVALID_VALUE error is generated. If the
    number corresponds to a subroutine of the wrong type, an INVALID_OPERATION
    error is generated.

    (4) What happens if the shaders change without reassigning subroutine
    associations?

    RESOLVED: The subroutine uniforms will revert to a default function of
    of those associated with it in the shader. The default function chosen
    may be implementation dependent.

    (5) How should subroutine parameters be updated?

    RESOLVED: UniformSubroutinesuivARB requires sending all subroutine
    parameters at once so they can be validated in a single burst. This is
    similar to D3D which goes as far as to require setting all of them in the
    same operation that binds the shader.

    (6) Why is the new "subroutine" state owned by the context rather than
    by the assembly program or GLSL program/shader? 

    RESOLVED: We expect that a common usage of this extension 
    would be to create a so-called "uber-shader" -- a program that can 
    support many different state configurations.  If an application uses
    such a program in multiple contexts, it likely it would not want changes
    to linkage for one context to affect the other context.

    (7) Does that mean other types of uniforms also need to be context state?

    RESOLVED: Apps can choose to share or not share numeric uniform types at
    their discretion using UBO, however for more "opaque" uniform types like 
    samplers it may be desirable to have context state. Such a change is
    beyond the scope of this extension. No effort was made to make subroutine
    uniforms generic enough to support other potential usages. Should such
    emerge, they will define their own unique uniform types.

    (8) GLSL allows function name overloading, how can you query a 
    subroutine location in that case?

    RESOLVED:  Disallow overloading of function names used for subroutine
    functions.

    (9) What sort of implementation-dependent limits apply to subroutines?

    RESOLVED:  There is an limit on the number of subroutines per shader stage
    (MAX_SUBROUTINES) and also a limit on the number of subroutine uniform
    locations (MAX_SUBROUTINE_UNIFORM_LOCATIONS).

    (10) How many subroutine variables be used? Should they be allowed as
    function parameters, structure members, and arrays?

    RESOLVED:  Arrays of subroutine uniforms are allowed.  The spec does not
    currently permit them as function parameters or structure members, as it
    requires subroutine variables be declared as uniforms.  Subroutine
    function parameters can be emulated by declaring a uniform array holding
    all possible subroutines that a shader might want to pass as a parameter
    and then passing an integer index to select a subroutine to call.

    (11) Is the "subroutine" keyword necessary when declaring a subroutine
    uniform?

    RESOLVED:  Yes, "subroutine uniform" in the declaration is required.

    (12) Why don't the new tokens and entry points in this extension have
     "ARB" suffixes like other ARB extensions?

     RESOLVED:  Unlike most ARB extensions, this is a strict subset of
     functionality already approved for the OpenGL core.  This extension
     exists only to support that functionality on older hardware that cannot
     implement all the functionality in that OpenGL version.  Since there are
     no possible behavior changes between the ARB extension and core features,
     source code compatibility is improved by not using suffixes on the
     extension.

    (13) Are compilers permitted to eliminate unreferenced elements at the end
    of an array for subroutine uniforms like they can for regular uniforms?

      RESOLVED:  No, because of differences in the uniform loading APIs.
      Consider the following example:

        uniform float array[10];
        // shader only references array[0..5]

      The GL implementation is permitted to treat "array" as having a size of
      6, but may also use the declared size of 10.  An application may have
      built-in knowledge that "array" has a declared length of 10, and might
      call Uniform1f() with a <count> of 10.  The specified behavior for
      Uniform*() APIs is that any values specified that extend beyond the last
      active element of the array are ignored.  As a result, passing "extra"
      elements to Uniform*() causes no problems; applications don't need to
      query the active size of a uniform array to get correct behavior.

      The subroutine uniform loading API is different, as it accepts a single
      array containing the values for every active uniform.  This allows
      applications to specify the values for all subroutine uniforms in a
      single call, instead of multiple calls for regular uniforms.  However,
      this approach doesn't provide a mechanism for discarding unused array
      elements.  If "array" above was a subroutine uniform and the application
      wrote 10 values into the array it would pass to UniformSubroutinesuiv,
      it might overwrite the values of other subroutines or write off the end
      of the array if the compiler only assigned 6 locations for "array".  If
      unused elements could be eliminated, implementations would have to query
      the active size for each subroutine uniform array, even if they knew the
      declared size up-front.  To avoid the need to always query lengths, we
      instead specify that all elements of an active subroutine array are
      active.

Revision History

    Rev.    Date      Author    Changes
    ----  ----------  --------  ----------------------------------------------
    19    02/28/2014  Jon Leech Restrict error for UniformSubroutinesuiv to  
                                the case where no program stage is active for
                                the shader stage identified by <shadertype>
                                (Bug 11306).

    18    02/10/2011  pbrown    Add a clarification to the GLSL spec language
                                prohibiting potential recursion via subroutine
                                uniforms; a program will fail to link if there
                                is any possible combination of subroutine 
                                uniform values that would result in recursion
                                (bug 7327).

    17    03/29/2010  pbrown    Update issues (1) and (10).

    16    03/21/2010  pbrown    Minor clarification in the NV_gpu_program5
                                interaction that no OPTION is required to
                                use subroutines in assembly programs.

    15    02/08/2010  Jon Leech Minor wording changes for consistency with
                                4.0 specification.

    14    01/30/2010  pbrown    Specify that implementations are not permitted
                                to chop unreferenced elements off the end of
                                a subroutine uniform array like they are with
                                regular uniforms (bug 5978).  Minor 
                                clarification on the meaning of "active
                                subroutines".

    13    01/26/2010  pbrown    Assigned enum values for enums added by most
                                recent edits.

    12    01/20/2010  pbrown    Update state tables to classify per-subroutine
                                and per-subroutine uniform state as "5x" to
                                indicate a separate set of values for each
                                shader stage.

    11    01/18/2010  pbrown    Rename GetActiveSubroutineUniformiv.  Add
                                enums to query the longest subroutine uniform
                                and subroutine names in a stage.  Rename enum
                                NUM_COMPATIBLE_SUBROUTINES.  Change error
                                behavior to allow most queries on unlinked
                                programs and ones without the specified stage
                                (except GetSubroutineUniformLocation).  Added
                                errors in UniformSubroutines and
                                GetUniformSubroutineuiv if no program is
                                active.  Minor spec language cleanups.  All
                                based on review comments in bug 5861.

    10    01/15/2010  pbrown    Significant changes to allow for full
                                discoverability of subroutine uniforms,
                                subroutines, and their locations (bug 5861).
                                Rename the term "subroutine number" to "active
                                subroutine index".  Rename GetSubroutineIndex
                                (was GetSubroutineNumber) and the <indices>
                                parameter of UniformSubroutinesuiv.  Fix
                                prototype of GetSubroutineIndex and other APIs
                                to consistently use "uint".  Add APIs to query
                                properties of active subroutine uniforms
                                (name, associated subroutines).  Separate the
                                notion of subroutine uniform indices and
                                locations just like regular uniforms.  Arrays
                                may have one index but multiple locations.
                                Specify that locations are packed in
                                consecutive locations.  Rename
                                GetSubroutineName to GetActiveSubroutineName
                                to match other enumeration APIs.  Add a query
                                for the number of active subroutine uniform
                                locations, and change the implementation limit
                                to be on active locations instead of indices.
                                Clarify that subroutines in a shader need not
                                be active if there is no active uniform that
                                can call them (bug 5859).  Update state tables
                                and some issues.

     9    01/14/2010  pbrown    Add some more text to the introduction to 
                                subroutines in the GLSL spec section.

     8    12/10/2009  groth     ARBify.

     7    12/10/2009  groth     Correct prototypes and clarify/correct errors.
                                Fix a few state retrieval typos.

     6    10/29/2009  groth     Clarify a number of areas in response to
                                feedback from bmerry.

     5    09/24/2009  groth     Fix typo in GLSL example. Assign enums.

     4    09/17/2009  pbrown    Add implementation-dependent limits on
                                subroutines.  Document some of these limits
                                and restrictions on function overloading and
                                subroutine uniforms with no matching function.

     3    09/16/2009  groth     Resolve issues. A few clarifications.
                                rename interface to subroutine.

     2    09/14/2009  groth     EXTify. move asm changes to dependencies.

     1                jbolz     Internal revisions.
