Name

    EXT_separate_shader_objects

Name Strings

    GL_EXT_separate_shader_objects

Contributors

    Contributors to ARB_separate_shader_objects and 
    ARB_explicit_attrib_location desktop OpenGL extensions from which this 
    extension borrows heavily

Contact

    Benj Lipchak, Apple (lipchak 'at' apple.com)

Status

    Complete

    NOTE: there is an unrelated OpenGL extension also named
    "GL_EXT_separate_shader_objects", found in the OpenGL extension registry
    at http://www.opengl.org/registry/ . These two extensions have similar
    purposes, but completely different interfaces.

Version

    Date: November 08, 2013
    Revision: 7

Number

    OpenGL ES Extension #101

Dependencies

    Requires OpenGL ES 2.0.

    Written based on the wording of the OpenGL ES 2.0.25 Full Specification
    (November 2, 2010).

    Written based on the wording of The OpenGL ES Shading Language 1.0.17
    Specification (May 12, 2009).
    
    OpenGL ES 3.0 affects the definition of this extension.

    NV_non_square_matrices affects the definition of this extension.

Overview

    This extension is a subset of ARB_separate_shader_objects appropriate for
    OpenGL ES, and also tacks on ARB_explicit_attrib_location functionality.

    Conventional GLSL requires multiple shader stages (vertex and fragment) to
    be linked into a single monolithic program object to specify a GLSL shader 
    for each stage.

    While GLSL's monolithic approach has some advantages for optimizing shaders 
    as a unit that span multiple stages, GPU hardware supports a more flexible 
    mix-and-match approach to specifying shaders independently for these 
    different shader stages.  Many developers build their shader content around
    the mix-and-match approach where they can use a single vertex shader with 
    multiple fragment shaders (or vice versa).

    This extension adopts a "mix-and-match" shader stage model for GLSL 
    allowing multiple different GLSL program objects to be bound at once each 
    to an individual rendering pipeline stage independently of other stage 
    bindings. This allows program objects to contain only the shader stages 
    that best suit the application's needs.

    This extension introduces the program pipeline object that serves as a 
    container for the program bound to any particular rendering stage.  It can 
    be bound, unbound, and rebound to simply save and restore the complete 
    shader stage to program object bindings.  Like framebuffer
    and vertex array objects, program pipeline objects are "container"
    objects that are not shared between contexts.

    To bind a program object to a specific shader stage or set of stages, 
    UseProgramStagesEXT is used.  The VERTEX_SHADER_BIT_EXT and 
    FRAGMENT_SHADER_BIT_EXT tokens refer to the conventional vertex and 
    fragment stages, respectively. ActiveShaderProgramEXT specifies the 
    program that Uniform* commands will update.

    While ActiveShaderProgramEXT provides a selector for setting and querying 
    uniform values of a program object with the conventional Uniform* commands,
    the ProgramUniform* commands provide a selector-free way to modify uniforms
    of a GLSL program object without an explicit bind. This selector-free model
    reduces API overhead and provides a cleaner interface for applications.

    Separate linking creates the possibility that certain output varyings of a 
    shader may go unread by the subsequent shader input varyings. In this 
    case, the output varyings are simply ignored. It is also possible input 
    varyings from a shader may not be written as output varyings of a preceding
    shader. In this case, the unwritten input varying values are undefined.

    This extension also introduces a layout location qualifier to GLSL to pre-
    assign attribute and varying locations to shader variables.  This allows 
    applications to globally assign a particular semantic meaning, such as 
    diffuse color or vertex normal, to a particular attribute and/or varying 
    location without knowing how that variable will be named in any particular 
    shader.
    
New Procedures and Functions

    void UseProgramStagesEXT(uint pipeline, bitfield stages,
                             uint program);

    void ActiveShaderProgramEXT(uint pipeline, uint program);

    uint CreateShaderProgramvEXT(enum type, sizei count,
                                 const char **strings);

    void BindProgramPipelineEXT(uint pipeline);

    void DeleteProgramPipelinesEXT(sizei n, const uint *pipelines);

    void GenProgramPipelinesEXT(sizei n, uint *pipelines);

    boolean IsProgramPipelineEXT(uint pipeline);

    void ProgramParameteriEXT(uint program, enum pname, int value);

    void GetProgramPipelineivEXT(uint pipeline, enum pname, int *params);

    void ProgramUniform1iEXT(uint program, int location,
                             int x);
    void ProgramUniform2iEXT(uint program, int location,
                             int x, int y);
    void ProgramUniform3iEXT(uint program, int location,
                             int x, int y, int z);
    void ProgramUniform4iEXT(uint program, int location,
                             int x, int y, int z, int w);

    void ProgramUniform1fEXT(uint program, int location,
                             float x);
    void ProgramUniform2fEXT(uint program, int location,
                             float x, float y);
    void ProgramUniform3fEXT(uint program, int location,
                             float x, float y, float z);
    void ProgramUniform4fEXT(uint program, int location,
                             float x, float y, float z, float w);

    void ProgramUniform1uiEXT(uint program, int location,
                              uint x);
    void ProgramUniform2uiEXT(uint program, int location,
                              uint x, uint y);
    void ProgramUniform3uiEXT(uint program, int location,
                              uint x, uint y, uint z);
    void ProgramUniform4uiEXT(uint program, int location,
                              uint x, uint y, uint z, uint w);

    void ProgramUniform1ivEXT(uint program, int location,
                              sizei count, const int *value);
    void ProgramUniform2ivEXT(uint program, int location,
                              sizei count, const int *value);
    void ProgramUniform3ivEXT(uint program, int location,
                              sizei count, const int *value);
    void ProgramUniform4ivEXT(uint program, int location,
                              sizei count, const int *value);

    void ProgramUniform1fvEXT(uint program, int location,
                              sizei count, const float *value);
    void ProgramUniform2fvEXT(uint program, int location,
                              sizei count, const float *value);
    void ProgramUniform3fvEXT(uint program, int location,
                              sizei count, const float *value);
    void ProgramUniform4fvEXT(uint program, int location,
                              sizei count, const float *value);

    void ProgramUniform1uivEXT(uint program, int location,
                               sizei count, const uint *value);
    void ProgramUniform2uivEXT(uint program, int location,
                               sizei count, const uint *value);
    void ProgramUniform3uivEXT(uint program, int location,
                               sizei count, const uint *value);
    void ProgramUniform4uivEXT(uint program, int location,
                               sizei count, const uint *value);

    void ProgramUniformMatrix2fvEXT(uint program, int location,
                                    sizei count, boolean transpose,
                                    const float *value);
    void ProgramUniformMatrix3fvEXT(uint program, int location,
                                    sizei count, boolean transpose,
                                    const float *value);
    void ProgramUniformMatrix4fvEXT(uint program, int location,
                                    sizei count, boolean transpose,
                                    const float *value);
    void ProgramUniformMatrix2x3fvEXT(uint program, int location,
                                     sizei count, boolean transpose,
                                     const float *value);
    void ProgramUniformMatrix3x2fvEXT(uint program, int location,
                                     sizei count, boolean transpose,
                                     const float *value);
    void ProgramUniformMatrix2x4fvEXT(uint program, int location,
                                     sizei count, boolean transpose,
                                     const float *value);
    void ProgramUniformMatrix4x2fvEXT(uint program, int location,
                                     sizei count, boolean transpose,
                                     const float *value);
    void ProgramUniformMatrix3x4fvEXT(uint program, int location,
                                     sizei count, boolean transpose,
                                     const float *value);
    void ProgramUniformMatrix4x3fvEXT(uint program, int location,
                                     sizei count, boolean transpose,
                                     const float *value);


   void ValidateProgramPipelineEXT(uint pipeline);

   void GetProgramPipelineInfoLogEXT(uint pipeline, sizei bufSize,
                                     sizei *length, char *infoLog);

New Tokens

    Accepted by <stages> parameter to UseProgramStagesEXT:

        VERTEX_SHADER_BIT_EXT                0x00000001
        FRAGMENT_SHADER_BIT_EXT              0x00000002
        ALL_SHADER_BITS_EXT                  0xFFFFFFFF

    Accepted by the <pname> parameter of ProgramParameteriEXT and
    GetProgramiv:

        PROGRAM_SEPARABLE_EXT                0x8258

    Accepted by <type> parameter to GetProgramPipelineivEXT:

        ACTIVE_PROGRAM_EXT                   0x8259

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

        PROGRAM_PIPELINE_BINDING_EXT         0x825A

Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL Operation):

 -- Section 2.10 "Vertex Shaders" (page 26)

    Modify the fourth and fifth paragraphs:

    "To use a vertex shader, shader source code is first loaded into a shader 
    object and then compiled. Alternatively, pre-compiled shader binary code 
    may be directly loaded into a shader object. An OpenGL ES implementation 
    must support one of these methods for loading shaders. If the boolean value
    SHADER_COMPILER is TRUE, then the shader compiler is supported. If the 
    integer value NUM_SHADER_BINARY_FORMATS is greater than zero, then shader 
    binary loading is supported.
    
    A shader object corresponds to a stage in the rendering pipeline referred 
    to as its shader stage or type. A vertex shader object is attached to a 
    program object. The program object is then linked, which generates 
    executable code from the compiled shader object(s) attached to the program. 
    When program objects are bound to a shader stage, they become the current 
    program object for that stage. When the current program object for the 
    vertex stage includes a vertex shader, it is considered the active program 
    object for the vertex stage. The current program object for all stages may
    be set at once using a single unified program object, or the current 
    program object may be set for each stage individually using a separable 
    program object where different separable program objects may be current for
    other stages. The set of separable program objects current for all stages
    are collected in a program pipeline object that must be bound for use.
    When a linked program object is made active for the vertex stage, the 
    executable code for the vertex shaders it contains is used to process 
    vertices."
    
    Modify the last sentence in the sixth paragraph:

    "... A single program object can contain either a vertex shader, a fragment
    shader, or both."

    Modify the seventh paragraph:

    "When the program object currently in use for the vertex stage
    includes a vertex shader, its vertex shader is considered active and
    is used to process vertices. If the current vertex stage program
    object has no vertex shader or no program object is current for the
    vertex stage, the results of vertex shader execution are undefined."

 -- Section 2.10.3 "Program Objects" (page 30) 

    Modify the description of linking failures following the description of
    LinkProgram to read:
    
    "... if <program> is not separable and does not contain both a vertex and a
    fragment shader, ..."

    Modify second paragraph, p. 31:

    "If a program has been successfully linked by LinkProgram, it can be made
    part of the current rendering state for all shader stages with the command

        void UseProgram(uint program);

    If <program> is non-zero, this command will make <program> the current
    program object. This will install executable code as part of the current
    rendering state for each shader stage present when the program was last
    successfully linked. If UseProgram is called with <program> set to zero,
    then there is no current program object. If <program> has not been
    successfully linked, the error INVALID_OPERATION is generated and the
    current rendering state is not modified."

    Insert paragraph immediately after preceding paragraph:

    "The executable code for an individual shader stage is taken from the
    current program for that stage. If there is a current program object
    established by UseProgram, that program is considered current for all
    stages. Otherwise, if there is a bound program pipeline object (section
    2.10.PPO), the program bound to the appropriate stage of the pipeline
    object is considered current. If there is no current program object or
    bound program pipeline object, no program is current for any stage. The
    current program for a stage is considered active if it contains executable
    code for that stage; otherwise, no program is considered active for that
    stage. If there is no active program for the vertex or fragment shader
    stages, the results of vertex and/or fragment processing will be undefined. 
    However, this is not an error."

    Modify fourth and fifth paragraphs, p. 31:

    "If a program object that is active for any shader stage is re-linked
    successfully, the LinkProgram command will install the generated
    executable code as part of the current rendering state for all shader
    stages where the program is active. Additionally, the newly generated
    executable code is made part of the state of any program pipeline for all
    stages where the program is attached.

    If a program object that is active for any shader stage is re-linked
    unsuccessfully, the link status will be set to FALSE, but existing
    executables and associated state will remain part of the current rendering
    state until a subsequent call to UseProgram, UseProgramStagesEXT, or
    BindProgramPipelineEXT removes them from use. If such a program is 
    attached to any program pipeline object, the existing executables and 
    associated state will remain part of the program pipeline object until a 
    subsequent call to UseProgramStagesEXT removes them from use. An 
    unsuccessfully linked program may not be made part of the current rendering 
    state by UseProgram or added to program pipeline objects by 
    UseProgramStagesEXT until it is successfully re-linked. If such a program 
    was attached to a program pipeline at the time of a failed link, its 
    existing executable may still be made part of the current rendering state 
    indirectly by BindProgramPipelineEXT."

    Insert prior to the description of DeleteProgram, p. 31:

    "Program parameters control aspects of how the program is linked,
    executed, or stored. To set a program parameter, call

        void ProgramParameteriEXT(uint program, enum pname, int value);

    <pname> identifies which parameter to set for program object
    <program>. <value> holds the value being set.
    
    If <pname> is PROGRAM_SEPARABLE_EXT, <value> must be TRUE or FALSE
    and indicates whether the <program> can be bound for individual
    pipeline stages via UseProgramStagesEXT after it is next linked."
        
    Modify the last paragraph of the section, p. 31:

    "If <program> is not current for any GL context, is not the active
    program for any program pipeline object, and is not the current
    program for any stage of any program pipeline object, it is deleted
    immediately. Otherwise, <program> is flagged ..."

    Insert at the end of the section, p. 31:

    "The command

        uint CreateShaderProgramvEXT(enum type, sizei count,
                                     const char **strings);

    creates a stand-alone program from an array of null-terminated source 
    code strings for a single shader type.  CreateShaderProgramvEXT
    is equivalent to the following command sequence:

        const uint shader = CreateShader(type);
        if (shader) {
            ShaderSource(shader, count, strings, NULL);
            CompileShader(shader);
            const uint program = CreateProgram();
            if (program) {
                int compiled = FALSE;
                GetShaderiv(shader, COMPILE_STATUS, &compiled);
                ProgramParameteriEXT(program, PROGRAM_SEPARABLE_EXT, TRUE);
                if (compiled) {
                    AttachShader(program, shader);
                    LinkProgram(program);
                    DetachShader(program, shader);
                }
                append-shader-info-log-to-program-info-log
            }
            DeleteShader(shader);
            return program;
        } else {
            return 0;
        }

    The program may not actually link if the output variables in the
    shader attached to the final stage of the linked program take up
    too many locations. If this situation arises, the info log may
    explain this.

    Because no shader is returned by CreateShaderProgramvEXT and the
    shader that is created is deleted in the course of the command
    sequence, the info log of the shader object is copied to the program
    so the shader's failed info log for the failed compilation is
    accessible to the application."

 -- Add new section 2.10.PPO "Program Pipeline Objects" after 2.10.3
    "Program Objects"

    "Instead of packaging all shader stages into a single program object,
    shader types might be contained in multiple program objects each
    consisting of part of the complete pipeline. A program object may
    even contain only a single shader stage. This facilitates greater
    flexibility when combining different shaders in various ways without
    requiring a program object for each combination.

    Program bindings associating program objects with shader types are
    collected to form a program pipeline object.

    The command

        void GenProgramPipelinesEXT(sizei n, uint *pipelines);

    returns <n> previously unused program pipeline object names in
    <pipelines>. These names are marked as used, for the purposes of
    GenProgramPipelinesEXT only, but they acquire state only when they are
    first bound.

    Program pipeline objects are deleted by calling

        void DeleteProgramPipelinesEXT(sizei n, const uint *pipelines);
    
    <pipelines> contains <n> names of program pipeline objects to be
    deleted. Once a program pipeline object is deleted, it has no
    contents and its name becomes unused. If an object that is currently
    bound is deleted, the binding for that object reverts to zero and no
    program pipeline object becomes current. Unused names in <pipelines>
    are silently ignored, as is the value zero.

    A program pipeline object is created by binding a name returned by
    GenProgramPipelinesEXT with the command

        void BindProgramPipelineEXT(uint pipeline);

    <pipeline> is the program pipeline object name. The resulting program
    pipeline object is a new state vector, comprising all the state and with
    the same initial values listed in table 6.PPO.

    BindProgramPipelineEXT may also be used to bind an existing program
    pipeline object. If the bind is successful, no change is made to
    the state of the bound program pipeline object, and any previous
    binding is broken. If BindProgramPipelineEXT is called with <pipeline>
    set to zero, then there is no current program pipeline object.

    If no current program object has been established by UseProgram, the
    program objects used for each shader stage and for uniform updates are
    taken from the bound program pipeline object, if any. If there is a
    current program object established by UseProgram, the bound program
    pipeline object has no effect on rendering or uniform updates. When a
    bound program pipeline object is used for rendering, individual shader
    executables are taken from its program objects as described in the
    discussion of UseProgram in section 2.10.3.

    BindProgramPipelineEXT fails and an INVALID_OPERATION error is
    generated if <pipeline> is not zero or a name returned from a
    previous call to GenProgramPipelinesEXT, or if such a name has since
    been deleted with DeleteProgramPipelinesEXT.

    The executables in a program object associated with one or more
    shader stages can be made part of the program pipeline state for
    those shader stages with the command:

       void UseProgramStagesEXT(uint pipeline, bitfield stages,
                                uint program);

    where <pipeline> is the program pipeline object to be updated,
    <stages> is the bitwise OR of accepted constants representing
    shader stages, and <program> is the program object from which the
    executables are taken. The bits set in <stages> indicate the program
    stages for which the program object named by <program> becomes
    current. These stages may include vertex or fragment indicated by 
    VERTEX_SHADER_BIT_EXT or FRAGMENT_SHADER_BIT_EXT respectively. The 
    constant ALL_SHADER_BITS_EXT indicates <program> is to be made current 
    for all shader stages. If <program> refers to a program object with a valid
    shader attached for an indicated shader stage, this call installs
    the executable code for that stage in the indicated program pipeline
    object state. If UseProgramStagesEXT is called with <program> set to
    zero or with a program object that contains no executable code for the
    given stages, it is as if the pipeline object has no programmable stage
    configured for the indicated shader stages.  If <stages> is not the
    special value ALL_SHADER_BITS_EXT and has a bit set that is not 
    recognized, the error INVALID_VALUE is generated. If the program object 
    named by <program> was linked without the PROGRAM_SEPARABLE_EXT parameter
    set or was not linked successfully, the error INVALID_OPERATION is 
    generated and the corresponding shader stages in the <pipeline> 
    program pipeline object are not modified.

    If <pipeline> is a name that has been generated (without subsequent
    deletion) by GenProgramPipelinesEXT, but refers to a program pipeline
    object that has not been previously bound, the GL first creates a
    new state vector in the same manner as when BindProgramPipelineEXT
    creates a new program pipeline object. If <pipeline> is not a name
    returned from a previous call to GenProgramPipelinesEXT or if such a
    name has since been deleted by DeleteProgramPipelinesEXT, an 
    INVALID_OPERATION error is generated.

    The command

        void ActiveShaderProgramEXT(uint pipeline, uint program);

    sets the linked program named by <program> to be the active program
    (discussed later in the secion 2.10.4) for the program pipeline
    object <pipeline>.  If <program> has not been successfully linked,
    the error INVALID_OPERATION is generated and active program is not
    modified.

    If <pipeline> is a name that has been generated (without subsequent
    deletion) by GenProgramPipelinesEXT, but refers to a program pipeline
    object that has not been previously bound, the GL first creates a
    new state vector in the same manner as when BindProgramPipelineEXT
    creates a new program pipeline object. If <pipeline> is not a name
    returned from a previous call to GenProgramPipelinesEXT or if such a
    name has since been deleted by DeleteProgramPipelinesEXT, an 
    INVALID_OPERATION error is generated.


    Shader Interface Matching

    When linking a non-separable program object with multiple shader types,
    the outputs of one stage form an interface with the inputs of the next
    stage. These inputs and outputs must typically match in name, type,
    and qualification.  When both sides of an interface are contained in
    the same program object, LinkProgram will detect mismatches on an
    interface and generate link errors.

    With separable program objects, interfaces between shader stages may
    involve the outputs from one program object and the inputs from a
    second program object. For such interfaces, it is not possible to
    detect mismatches at link time, because the programs are linked
    separately. When each such program is linked, all inputs or outputs
    interfacing with another program stage are treated as active. The
    linker will generate an executable that assumes the presence of a
    compatible program on the other side of the interface. If a mismatch
    between programs occurs, no GL error will be generated, but some or all
    of the inputs on the interface will be undefined.

    At an interface between program objects, the inputs and outputs are
    considered to match exactly if and only if:

      * For every user-declared input variable declared, there is an output
        variable declared in the previous shader matching exactly in name,
        type, and qualification.

      * There are no user-defined output variables declared without a matching
        input variable declaration.

    When the set of inputs and outputs on an interface between programs
    matches exactly, all inputs are well-defined unless the corresponding
    outputs were not written in the previous shader. However, any mismatch
    between inputs and outputs results in all inputs being undefined except
    for cases noted below. Even if an input has a corresponding output
    that matches exactly, mismatches on other inputs or outputs may
    adversely affect the executable code generated to read or write the
    matching variable.

    The inputs and outputs on an interface between programs need not match
    exactly when input and output location qualifiers (sections 4.3.6.1 and
    4.3.6.2 of the GLSL Specification) are used.  When using location
    qualifiers, any input with an input location qualifier will be
    well-defined as long as the other program writes to an output with the
    same location qualifier, data type, and qualification.  Also, an input
    will be well-defined if the other program writes to an output matching
    the input in everything but data type as long as the output data type  
    has the same basic component type and more components.  The names of 
    variables need not match when matching by location.  For the purposes 
    of interface matching, an input with a location qualifier is considered 
    to match a corresponding output only if that output has an identical 
    location qualifier.

    Built-in inputs or outputs do not affect interface matching.  Any such 
    built-in inputs are well-defined unless they are derived from built-in 
    outputs not written by the previous shader stage.


    Program Pipeline Object State

    The state required to support program pipeline objects consists of
    a single binding name of the current program pipeline object. This
    binding is initially zero indicating no program pipeline object is
    bound.

    The state of each program pipeline object consists of:

    * Three unsigned integers (initially all zero) are  required to hold
      each respective name of the current vertex stage program, current 
      fragment stage program, and active program respectively.
    * A Boolean holding the status of the last validation attempt,
      initially false.
    * An array of type char containing the information log, initially
      empty.
    * An integer holding the length of the information log."

 -- Section 2.10.4 "Shader Variables" subsection "Vertex Attributes"
 
    Change the first sentence of the second full paragraph (p. 34):
    
    "When a program is linked, any active attributes without a binding
    specified either through BindAttribLocation or explicitly set
    within the shader text will be automatically bound to vertex
    attributes by the GL."
    
    Add the following sentence to the end of that same paragraph:
    
    "If an active attribute has a binding explicitly set within the shader text
    and a different binding assigned by BindAttribLocation, the assignment in 
    the shader text is used."

 -- Section 2.10.4 "Shader Variables" subsection "Uniform Variables"

    Replace the paragraph introducing Uniform* (p. 37):

    "To load values into the uniform variables of the active program object, 
    use the commands

        ... 
    
    If a non-zero program object is bound by UseProgram, it is the
    active program object whose uniforms are updated by these commands.
    If no program object is bound using UseProgram, the active program
    object of the current program pipeline object set by 
    ActiveShaderProgramEXT is the active program object. If the current 
    program pipeline object has no active program or there is no current 
    program pipeline object, then there is no active program.
        
    The given values are loaded into the ... "

    Change the last bullet in the "Uniform Variables" subsection (p. 38) to:

    "* if there is no active program in use."

    Add to the end of the "Uniform Variables" subsection (p. 38): 

    To load values into the uniform variables of a program which may not 
    necessarily be bound, use the commands

        void ProgramUniform{1234}{if}EXT(uint program, int location,
                                         T value);
        void ProgramUniform{1234}uiEXT(uint program, int location,
                                       T value);
        void ProgramUniform{1234}{if}vEXT(uint program, int location,
                                          sizei count, const T *value);
        void ProgramUniform{1234}uivEXT(uint program, int location,
                                          sizei count, const uint *value);
        void ProgramUniformMatrix{234}fvEXT(uint program, int location,
                                            sizei count, boolean transpose,
                                            const float *value);
        void ProgramUniformMatrix{2x3,3x2,2x4,
                                  4x2,3x4,4x3}fvEXT(uint program, 
                                                    int location,
                                                    sizei count, 
                                                    boolean transpose,
                                                    const float *value);

    These commands operate identically to the corresponding commands
    above without "Program" in the command name except, rather than
    updating the currently active program object, these "Program"
    commands update the program object named by the initial <program>
    parameter. The remaining parameters following the initial <program>
    parameter match the parameters for the corresponding non-"Program"
    uniform command. If <program> is not the name of a created program
    or shader object, the error INVALID_VALUE is generated. If <program>
    identifies a shader object or a program object that has not been
    linked successfully, the error INVALID_OPERATION is generated.

 -- Section 2.10.5 "Shader Execution" (p. 40) 

    Change the first paragraph:

    "If there is an active program object present for the vertex stage, the 
    executable code for this active program is used to process incoming vertex
    values."

    Change first paragraph of subsection "Validation", p. 41:

    "It is not always possible to determine at link time if a program object 
    can execute successfully, given that LinkProgram can not know the state of 
    the remainder of the pipeline.  Therefore validation is done when the first
    rendering command (DrawArrays or DrawElements) is issued, to determine if 
    the set of active program objects can be executed. If the current set of 
    active program objects cannot be executed, no primitives
    are processed and the error INVALID_OPERATION will be generated."

    Add to the list in the second paragraph of subsection "Validation" (p. 41):

    "* A program object is active for at least one, but not all of the
      shader stages that were present when the program was linked.

    * There is no current unified program object and the current program
      pipeline object includes a program object that was relinked since
      being applied to the pipeline object via UseProgramStagesEXT with the
      PROGRAM_SEPARABLE_EXT parameter set to FALSE."

    Add after the description of ValidateProgram in subsection
    "Validation":

    "Separable program objects may have validation failures that cannot
    be detected without the complete program pipeline. Mismatched
    interfaces, improper usage of program objects together, and the same
    state-dependent failures can result in validation errors for such
    program objects. As a development aid, use the command

        void ValidateProgramPipelineEXT(uint pipeline);
    
    to validate the program pipeline object <pipeline> against the
    current GL state. Each program pipeline object has a boolean status,
    VALIDATE_STATUS, that is modified as a result of validation. This
    status can be queried with GetProgramPipelineivEXT (See section 6.1.8).
    If validation succeeded, the program pipeline object is guaranteed
    to execute given the current GL state. 

    If <pipeline> is a name that has been generated (without subsequent
    deletion) by GenProgramPipelinesEXT, but refers to a program pipeline
    object that has not been previously bound, the GL first creates a
    new state vector in the same manner as when BindProgramPipelineEXT
    creates a new program pipeline object. If <pipeline> is not a name
    returned from a previous call to GenProgramPipelinesEXT or if such a
    name has since been deleted by DeleteProgramPipelinesEXT, an 
    INVALID_OPERATION error is generated.

Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization)

 -- Section 3.8 "Fragment Shaders" (p. 86) 

    Replace the last paragraph with:

    "When the program object currently in use for the fragment stage
    includes a fragment shader, its fragment shader is considered active and
    is used to process fragments. If the current fragment stage program
    object has no fragment shader or no program object is current for the
    fragment stage, the results of fragment shader execution are undefined."
    
Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment 
Operations and the Frame Buffer)

    None

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

    None

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

 -- Section 6.1.8 "Shader and Program Queries"
    
    Add to GetProgramiv description:

    "If <pname> is PROGRAM_SEPARABLE_EXT, TRUE is returned if the program has
    been flagged for use as a separable program object that can be bound
    to individual shader stages with UseProgramStagesEXT."

    Add after GetProgramiv description:

    "The command 

        boolean IsProgramPipelineEXT(uint pipeline);

    returns TRUE if <pipeline> is the name of a program pipeline object.
    If <pipeline> is zero, or a non-zero value that is not the name of a
    program pipeline object, IsProgramPipelineEXT returns FALSE. No error
    is generated if <pipeline> is not a valid program pipeline object
    name.

    The command

        GetProgramPipelineivEXT(uint pipeline, enum pname, int *params);

    returns properties of the program pipeline object named <pipeline>
    in <params>. The parameter value to return is specified by <pname>.

    If <pipeline> is a name that has been generated (without subsequent
    deletion) by GenProgramPipelinesEXT, but refers to a program pipeline
    object that has not been previously bound, the GL first creates a
    new state vector in the same manner as when BindProgramPipelineEXT
    creates a new program pipeline object. If <pipeline> is not a name
    returned from a previous call to GenProgramPipelinesEXT or if such a
    name has since been deleted by DeleteProgramPipelinesEXT, an 
    INVALID_OPERATION error is generated.

    If <pname> is ACTIVE_PROGRAM_EXT, the name of the active program
    object of the program pipeline object is returned.
    
    If <pname> is VERTEX_SHADER, the name of the current program
    object for the vertex shader type of the program pipeline object is
    returned.
       
    If <pname> is FRAGMENT_SHADER, the name of the current program
    object for the fragment shader type of the program pipeline object
    is returned.
       
    If <pname> is VALIDATE_STATUS, the validation status of the
    program pipeline object, as determined by ValidateProgramPipelineEXT
    (see section 2.10.5) is returned.

    If <pname> is INFO_LOG_LENGTH, the length of the info log,
    including a null terminator, is returned. If there is no info log,
    zero is returned."
    
    Change paragraph describing GetShaderInfoLog and GetProgram:

    "A string that contains information about the last compilation
    attempt on a shader object, last link or validation attempt on a
    program object, or last validation attempt on a program pipeline
    object, called the info log, can be obtained with the commands

        void GetShaderInfoLog(uint shader, sizei bufSize,
                              sizei *length, char *infoLog);
        void GetProgramInfoLog(uint program, sizei bufSize,
                              sizei *length, char *infoLog);
        void GetProgramPipelineInfoLogEXT(uint pipeline, sizei bufSize,
                                          sizei *length, char *infoLog);

    These commands return the info log string in <infoLog>. This string
    will be null-terminated. The actual number of characters written
    into <infoLog>, excluding the null terminator, is returned in
    <length>. If <length> is NULL, then no length is returned. The
    maximum number of characters that may be written into <infoLog>,
    including the null terminator, is specified by <bufSize>. The number
    of characters in the info log can be queried with GetShaderiv,
    GetProgramiv, or GetProgramPipelineivEXT with INFO_LOG_LENGTH. If
    <shader> is a shader object, the returned info log will either be an
    empty string or it will contain information about the last compil-
    ation attempt for that object. If <program> is a program object, the
    returned info log will either be an empty string or it will contain
    information about the last link attempt or last validation attempt
    for that object. If <pipeline> is a program pipeline object, the
    returned info log will either be an empty string or it will contain
    information about the last validation attempt for that object.

Additions to Appendix D of the OpenGL ES 2.0 Specification (Shared Objects and 
Multiple Contexts)

    (add sentence to third paragraph, p. 164) Program pipeline objects are not
    shared.

Additions to the OpenGL ES Shading Language Specification, Version 1.0.17

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

        #extension GL_EXT_separate_shader_objects : <behavior>

    where <behavior> is as described in section 3.3.

    A new preprocessor #define is added to the OpenGL ES Shading Language:

        #define GL_EXT_separate_shader_objects 1

 -- Section 4.3.3 "Attribute" (page 30):

    Add new section 4.3.3.1 "Attribute Layout Qualifiers"
    
    "Vertex shaders allow location layout qualifiers on attribute variable
    declarations.  The location layout qualifier identifier for vertex shader 
    attributes is:

      layout-qualifier-id
        location = integer-constant

    Only one argument is accepted.  For example,

      layout(location = 3) attribute vec4 normal;

    establishes that the vertex shader attribute <normal> is copied in from
    vector location number 3.

    If an input variable with no location assigned in the shader text has a
    location specified through the OpenGL ES API, the API-assigned location will
    be used.  Otherwise, such variables will be assigned a location by the
    linker.  See section 2.10.4 of the OpenGL Specification for more details.
    A link error will occur if an attribute variable is declared in multiple
    vertex shaders with conflicting locations.


 -- Section 4.3.5 "Varying" (page 31):

    Add to the end of the section:

    "When an interface between shader stages is formed using shaders from two
    separate program objects, it is not possible to detect mismatches between
    vertex shader varying outputs and fragment shader varying inputs when the 
    programs are linked. When there are mismatches between inputs and outputs 
    on such interfaces, the values passed across the interface will be 
    partially or completely undefined. Shaders can ensure matches across such 
    interfaces either by using varying layout qualifiers (Section 4.3.5.1) or 
    by using identical varying declarations.  Complete rules for interface
    matching are found in the "Shader Interface Matching" portion of section
    2.10.PPO of the OpenGL Specification."

    Add new section 4.3.5.1 "Varying Layout Qualifiers"

    "All shaders allow location layout qualifiers on varying variable
    declarations. The location layout qualifier identifier for varyings is:

        layout-qualifier-id
            location = integer-constant

    Only one argument is accepted. For example,
        layout(location = 3) varying vec4 normal;

    establishes that the shader varying <normal> is assigned to vector
    location number 3.

    If the declared varying is an array of size <n> and each element takes up
    <m> locations, it will be assigned <m>*<n> consecutive locations starting
    with the location specified.  For example,

        layout(location = 6) varying vec4 colors[3];

    will establish that the input <colors> is assigned to vector
    location numbers 6, 7, and 8.

    If the declared varying is an <n>x<m> matrix, it will be assigned multiple 
    locations starting with the location specified. The number of locations 
    assigned for each matrix will be the same as for an <n>-element array of 
    <m>-component vectors. For example,

        layout(location = 9) varying mat4 transforms[2];

    will establish that varying <transforms> is assigned to vector location
    numbers 9-16, with transforms[0] being assigned to locations 9-12 and
    transforms[1] being assigned to locations 13-16.

    The number of varying locations available to a shader is limited to the 
    implementation-dependent advertised maximum varying vector count.
    A program will fail to link if any attached shader uses a location greater
    than or equal to the number of supported locations, unless
    device-dependent optimizations are able to make the program fit within
    available hardware resources.

    A program will fail to link if any two varying variables are assigned to 
    the same location, or if explicit location assignments leave the linker 
    unable to find space for other variables without explicit assignments."

Dependencies on OpenGL ES 3.0

    If OpenGL ES 3.0 isn't present, references to
    ProgramUniform{1234}ui[v] should be ignored. Also, any redundant
    language about explicit shader variable locations set within the
    shader text should also be ignored.

    If neither OpenGL ES 3.0 nor NV_non_square_matrices is present,
    references to ProgramUniformMatrix{2x3,3x2,2x4,4x2,3x4,4x3}fv
    should be ignored.
    
    The behavior of mixing GLSL ES 1.00 shaders with GLSL ES 3.00 shaders
    in the same rendering pipeline is undefined.
    
    If the GL is OpenGL ES 3.0, make the following changes:
    
    Replace this sentence from the first paragraph of section 2.10.PPO Shader 
    Interface Matching:
    
    "These inputs and outputs must typically match in name, type, and 
    qualification."
    
    with the following language:
    
    "An output variable is considered to match an input variable in the
    subequent shader if:

        * the two variables match in name, type, and qualification; or

        * the two variables are declared with the same location layout
          qualifier and match in type and qualification."
    
    Add this paragraph after the first paragraph of section 2.10.PPO:
    
    "Variables declared as structures are considered to match in type if and 
    only if structure members match in name, type, qualification, and 
    declaration order.  Variables declared as arrays are considered to match 
    in type only if both declarations specify the same element type and array 
    size.  The rules for determining if variables match in qualification are
    found in the OpenGL Shading Language Specification."
    
    Replace the last paragraph from section 2.10.PPO:
    
    "Built-in inputs or outputs do not affect interface matching.  Any such 
    built-in inputs are well-defined unless they are derived from built-in 
    outputs not written by the previous shader stage."
    
    with the following new language:
    
    "When using GLSL ES 1.00 shaders, built-in inputs or outputs do not affect 
    interface matching. Any such built-in inputs are well-defined unless they 
    are derived from built-in outputs not written by the previous shader stage.
    
    When using GLSL ES 3.00 shaders in separable programs, gl_Position and 
    gl_PointSize built-in outputs must be redeclared according to Section 7.5 
    of the OpenGL Shading Language Specification. Other built-in inputs or 
    outputs do not affect interface matching. Any such built-in inputs are 
    well-defined unless they are derived from built-in outputs not written by 
    the previous shader stage."
    
    and add to GLSL ES 3.00 new section 7.5, Built-In Redeclaration and 
    Separable Programs:
    
    "The following vertex shader outputs may be redeclared at global scope to
    specify a built-in output interface, with or without special qualifiers:

        gl_Position
        gl_PointSize

      When compiling shaders using either of the above variables, both such
      variables must be redeclared prior to use.  ((Note:  This restriction
      applies only to shaders using version 300 that enable the
      EXT_separate_shader_objects extension; shaders not enabling the
      extension do not have this requirement.))  A separable program object
      will fail to link if any attached shader uses one of the above variables
      without redeclaration."

Dependencies on NV_non_square_matrices

    If NV_non_square_matrices is supported,
    ProgramUniformMatrix{2x3,3x2,2x4,4x2,3x4,4x3}fvEXT is supported in
    OpenGL ES 2.0.

Errors

    UseProgramStagesEXT generates INVALID_OPERATION if the program
    parameter has not been successfully linked.

    UseProgramStagesEXT generates INVALID_VALUE if <stages> has a bit
    set for any other than VERTEX_SHADER_BIT_EXT or 
    FRAGMENT_SHADER_BIT_EXT, unless <stages> is ALL_SHADER_BITS_EXT.

    ActiveShaderProgramEXT generates INVALID_OPERATION if <program>
    has not been successfully linked.

    DrawArrays and DrawElements generate INVALID_OPERATION when a program 
    object with multiple attached shaders is active for one or more, but not 
    all of the shader program types corresponding to the shaders that are
    attached.

New State

    Add to table 6.15 (Program Object State):
    
                                                       Initial
    Get Value           Type  Get Command              Value    Description               Sec   
    ------------------  ----  -----------------------  -------  ------------------------  ------
    PROGRAM_PIPELINE_-  Z+    GetIntegerv              0        Current program pipeline  2.10.PPO
    BINDING_EXT                                                 object binding

    Add new table 6.PPO (Program Pipeline Object State):

                                                            Initial
    Get Value           Type  Get Command                   Value    Description               Sec   
    ------------------  ----  ----------------------------  -------  ------------------------  ------
    ACTIVE_PROGRAM_EXT  Z+    GetProgramPipelineivEXT       0        The program object        2.10.PPO
                                                                     that Uniform* commands
                                                                     update when PPO bound
    VERTEX_SHADER       Z+    GetProgramPipelineivEXT       0        Name of current vertex    2.10.PPO
                                                                     shader program object
    FRAGMENT_SHADER     Z+    GetProgramPipelineivEXT       0        Name of current fragment  2.10.PPO
                                                                     shader program object
    VALIDATE_STATUS     B     GetProgramPipelineivEXT       FALSE    Validate status of        2.10.PPO
                                                                     program pipeline object
                        S     GetProgramPipelineInfoLogEXT  empty    Info log for program      6.1.8
                                                                     pipeline object                                                      
    INFO_LOG_LENGTH     Z+    GetProgramPipelineivEXT       0        Length of info log        6.1.8
                                                    
New Implementation Dependent State

    None

Issues

    See ARB_separate_shader_objects extension specification for issues
    documented while working on the original desktop OpenGL extension.
    
Revision History

    Rev.    Date      Author     Changes
    ----  ----------  ---------  ---------------------------------------------
    1     2011-06-17  Benj       Initial revision for ES based on
                                 ARB_separate_shader_objects extension.

    2     2011-07-22  Benj       Rename APPLE to EXT, specify that PPOs are
                                 not shareable.

    3     2011-07-26  Benj       Add VALIDATE_STATUS to state tables and
                                 GetProgramPipelineivEXT description, remove 
                                 the language erroneously deleting
                                 CURRENT_PROGRAM.

    4     2013-03-07  Jon Leech  Added note about the unrelated OpenGL 
                                 extension of the same name.             

    5     2013-03-25  Benj       Add interactions with OpenGL ES 3.0.
    6     2013-09-20  dkoch      Add interactions with NV_non_square_matrices.
    7     2013-11-08  marka      Clarify ProgramUniform*ui availability.
