Name

    ARB_get_program_binary

Name Strings

    GL_ARB_get_program_binary

Contributors

    Acorn Pooley
    Aske Simon Christensen
    Bruce Merry
    David Garcia
    Eric Werness
    Georg Kolling
    Greg Roth
    Jason Green
    Jeff Bolz
    Jeremy Sandmel
    Joey Blankenship
    Jon Leech
    Mark Callow
    Pat Brown
    Robert Simpson
    Tom Olson

Contact

    Benj Lipchak, APPLE (lipchak 'at' apple.com)
    Greg Roth, NVIDIA (groth 'at' nvidia.com)
    Piers Daniell, NVIDIA (pdaniell 'at' nvidia.com)

Notice

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

Status

    Complete. Approved by the ARB on June 9, 2010.
    Approved by the Khronos Board of Promoters on July 23, 2010.

Version

    Last Modified Date: July 5, 2016
    Revision: #9

Number

    ARB Extension #96

Dependencies

    OpenGL 3.0 is required.

    Written based on the wording of the OpenGL 3.2 compatibility specification.

Overview

    This extension introduces new commands to retrieve and set the binary
    representation of a program object.  GetProgramBinary allows an
    application to cache compiled and linked programs to avoid compiling and
    linking when used again. This may even allow the GL itself to act as an
    offline compiler.  The resulting program binary can be reloaded into the
    GL via ProgramBinary.  This is a very useful path for applications that
    wish to remain portable by shipping pure GLSL source shaders, yet would
    like to avoid the cost of compiling their shaders at runtime.  Instead an
    application can supply its GLSL source shaders during first application run,
    or even during installation.  The application then compiles and links its
    shaders and reads back the program binaries.  On subsequent runs, only the
    program binaries need be supplied.

    ProgramBinary may also accept binaries in vendor-specific formats
    produced by specialized offline compilation tools. This extension does not
    add any such formats, but allows for them in further extensions. Though the
    level of optimization may not be identical -- the offline shader compiler
    may have the luxury of more aggressive optimization at its disposal --
    program binaries generated online by the GL are interchangeable with those
    generated offline by an SDK tool.

IP Status

    No known IP claims.

New Procedures and Functions

    void GetProgramBinary(uint program, sizei bufSize, sizei *length,
                          enum *binaryFormat, void *binary);

    void ProgramBinary(uint program, enum binaryFormat,
                       const void *binary, sizei length);

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

New Tokens

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

        PROGRAM_BINARY_RETRIEVABLE_HINT             0x8257

    Accepted by the <pname> parameter of GetProgramiv:

        PROGRAM_BINARY_LENGTH                       0x8741

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

        NUM_PROGRAM_BINARY_FORMATS                  0x87FE
        PROGRAM_BINARY_FORMATS                      0x87FF

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

    Update section 2.14 "Vertex Shaders", insert before the last sentence of
    the third paragraph:


    "... which generates executable code from all the compiled shader objects
    attached to the program. Alternatively, pre-compiled program binary code
    may be directly loaded into a program object. When a linked program object
    is used..."

    Add the following paragraphs above the description of DeleteProgram, p. 86:

    To set a program object parameter, call

        void ProgramParameteri(uint program, enum pname, int value)

    <pname> identifies which parameter to set for <program>. <value> holds the
    value being set.

    If <pname> is PROGRAM_BINARY_RETRIEVABLE_HINT, <value> must be TRUE or
    FALSE, and indicates whether a program binary is likely to be retrieved
    later, as described for ProgramBinary in section 2.14.3. This hint will
    not take effect until the next time LinkProgram or ProgramBinary has
    been called successfully.

    Add section 2.14.3, Program Binaries

    "The command

        void GetProgramBinary(uint program, sizei bufSize, sizei *length,
                              enum *binaryFormat, void *binary);

    returns a binary representation of the program object's compiled and
    linked executable source, henceforth referred to as its program binary.
    The maximum number of bytes that may be written into <binary> is specified
    by <bufSize>.  If <bufSize> is less than the number of bytes in the program
    binary, then an INVALID_OPERATION error is thrown.  Otherwise, the actual
    number of bytes written into <binary> is returned in <length> and its
    format is returned in <binaryFormat>.  If <length> is NULL, then no
    length is returned.

    The number of bytes in the program binary can be queried by calling
    GetProgramiv with <pname> PROGRAM_BINARY_LENGTH.  When a program object's
    LINK_STATUS is FALSE, its program binary length is zero, and a call
    to GetProgramBinary will generate an INVALID_OPERATION error.

    The command

        void ProgramBinary(uint program, enum binaryFormat,
                           const void *binary, sizei length);

    loads a program object with a program binary previously returned from
    GetProgramBinary.  This is useful for future instantiations of the GL to
    avoid online compilation, while still using OpenGL Shading Language source
    shaders as a portable initial format.  <binaryFormat> and <binary> must be
    those returned by a previous call to GetProgramBinary, and <length> must
    be the length of the program binary as returned by GetProgramBinary or
    GetProgramiv with <pname> PROGRAM_BINARY_LENGTH. Loading the program
    binary will fail, setting the LINK_STATUS of <program> to FALSE, if
    these conditions are not met.

    Loading a program binary may also fail if the implementation determines
    that there has been a change in hardware or software configuration from
    when the program binary was produced such as having been compiled with
    an incompatible or outdated version of the compiler. In this case the
    application should fall back to providing the original OpenGL Shading
    Language source shaders, and perhaps again retrieve the program binary
    for future use.

    A program object's program binary is replaced by calls to LinkProgram or
    ProgramBinary. Where linking success or failure is concerned,
    ProgramBinary can be considered to perform an implicit linking operation.
    LinkProgram and ProgramBinary both set the program object's LINK_STATUS
    to TRUE or FALSE, as queried with GetProgramiv, to reflect success or
    failure and update the information log, queried with GetProgramInfoLog, to
    provide details about warnings or errors.

    A successful call to ProgramBinary will reset all uniform variables to
    their initial values. The initial value is either the value of the
    variable's initializer as specified in the original shader source, or 0
    if no initializer was present.

    Additionally, all vertex shader input and fragment shader output
    assignments that were in effect when the program was linked before saving
    are restored when ProgramBinary is called.

    If ProgramBinary fails to load a binary, no error is generated, but any
    information about a previous link or load of that program object is
    lost. Thus, a failed load does not restore the old state of <program>.
    The failure does not alter other program state not affected by linking
    such as the attached shaders, and the vertex attribute and fragment data
    location bindings as set by BindAttribLocation and BindFragDataLocation.

    Queries of values NUM_PROGRAM_BINARY_FORMATS and PROGRAM_BINARY_FORMATS
    return the number of program binary formats and the list of program binary
    format values supported by an implementation.  The <binaryFormat> returned
    by GetProgramBinary must be present in this list.

    Any program binary retrieved using GetProgramBinary and submitted using
    ProgramBinary under the same configuration must be successful. Any
    programs loaded successfully by ProgramBinary must be run properly with
    any legal GL state vector.

    If a GL implementation needs to recompile or otherwise modify program
    executables based on GL state outside the program, GetProgramBinary is
    required to save enough information to allow such recompilation.

    To indicate that a program binary is likely to be retrieved,
    ProgramParameteri should be called with <pname>
    PROGRAM_BINARY_RETRIEVABLE_HINT and <value> TRUE. This setting will not
    be in effect until the next time LinkProgram or ProgramBinary has been
    called successfully. Additionally, GetProgramBinary calls may be
    deferred until after using the program with all non-program state
    vectors that it is likely to encounter. Such deferral may allow
    implementations to save additional information in the program binary
    that would minimize recompilation in future uses of the program binary."

    Modify Section 2.14.8, Required State

    Add the following bullet to the state required per program object:

      * boolean holding the hint to the retrievability of the program binary,
      initially FALSE.


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

    Modify section 6.1.16, Shader and Program Objects

    Add to the end of the description of GetProgramiv, p. 385:

    If <pname> is PROGRAM_BINARY_RETRIEVABLE_HINT, the current value of
    whether the binary retrieval hint is enabled for <program> is returned.

GLX Protocol

    None.

Errors

    An INVALID_VALUE error is generated if the <program> argument to
    GetProgramBinary, ProgramBinary, or ProgramParameteri is not the name of
    a program object previously created with CreateProgram.

    An INVALID_ENUM error is generated if the <pname> argument to
    ProgramParameteri is not PROGRAM_BINARY_RETRIEVABLE_HINT.

    An INVALID_VALUE error is generated if the <value> argument to
    ProgramParameteri is not TRUE or FALSE.

    An INVALID_OPERATION error is generated if GetProgramBinary is called
    when the program object, <program>, does not contain a valid program
    binary as reflected by its LINK_STATUS state, or if <bufSize> is not big
    enough to contain the entire program binary.

New State

    (table 6.42, Program Object State) add the following:

    Get Value                       Type  Get Command      Initial Value  Description                      Section
    -------------                   ----  -----------      -------------  -----------                      -------
    PROGRAM_BINARY_LENGTH           Z+    GetProgramiv     0              Length of program binary         2.14.3
    PROGRAM_BINARY_RETRIEVABLE_HINT Z     GetProgramiv     FALSE          Retriavable binary hint enabled  2.14.3
    -                               Z1    GetProgramBinary N/A            Binary representation of program 2.14.3

    (table 6.51, Implementation Dependent Values) add the following:

    Get Value                       Type    Get Command          Minimum Value  Description                        Section
    -------------                   ----    -----------          -------------  -----------                        -------
    PROGRAM_BINARY_FORMATS          0* x Z  GetIntegerv          N/A            Enumerated program binary formats  2.14.3
    NUM_PROGRAM_BINARY_FORMATS      Z       GetIntegerv          0              Number of program binary formats   2.14.3

Sample Usage

    void retrieveProgramBinary(const GLchar* vsSource, const GLchar* fsSource,
                               const char* myBinaryFileName,
                               GLenum* binaryFormat)
    {
        GLuint        newFS, newVS;
        GLuint        newProgram;
        const GLchar* sources[1];
        GLint         success;

        GLint   binaryLength;
        void*   binary;
        FILE*   outfile;

        //
        //  Create new shader/program objects and attach them together.
        //
        newVS = glCreateShader(GL_VERTEX_SHADER);
        newFS = glCreateShader(GL_FRAGMENT_SHADER);
        newProgram = glCreateProgram();
        glAttachShader(newProgram, newVS);
        glAttachShader(newProgram, newFS);

        //
        //  Supply GLSL source shaders, compile, and link them
        //
        sources[0] = vsSource;
        glShaderSource(newVS, 1, sources, NULL);
        glCompileShader(newVS);

        sources[0] = fsSource;
        glShaderSource(newFS, 1, sources, NULL);
        glCompileShader(newFS);

        glProgramParameteri(newProgram, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
        glLinkProgram(newProgram);
        glGetProgramiv(newProgram, GL_LINK_STATUS, &success);

        if (!success)
        {
            //
            // Fallback to simpler source shaders?  Take my toys and go home?
            //
        }

        glUseProgram(newProgram);

        //
        // Perform rendering and state changes likely to be encountered.
        //
        DoRendering(newProgram);

        //
        //  Retrieve the binary from the program object
        //
        glGetProgramiv(newProgram, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
        binary = (void*)malloc(binaryLength);
        glGetProgramBinary(newProgram, binaryLength, NULL, binaryFormat, binary);

        //
        //  Cache the program binary for future runs
        //
        outfile = fopen(myBinaryFileName, "wb");
        fwrite(binary, binaryLength, 1, outfile);
        fclose(outfile);
        free(binary);

        //
        // Clean up
        //
        glDeleteShader(newVS);
        glDeleteShader(newFS);
        glDeleteProgram(newProgram);
    }

    void loadProgramBinary(const char* myBinaryFileName, GLenum binaryFormat,
                           GLuint progObj)
    {
        GLint   binaryLength;
        void*   binary;
        GLint   success;
        FILE*   infile;

        //
        //  Read the program binary
        //
        infile = fopen(myBinaryFileName, "rb");
        fseek(infile, 0, SEEK_END);
        binaryLength = (GLint)ftell(infile);
        binary = (void*)malloc(binaryLength);
        fseek(infile, 0, SEEK_SET);
        fread(binary, binaryLength, 1, infile);
        fclose(infile);

        //
        //  Load the binary into the program object -- no need to link!
        //
        glProgramBinary(progObj, binaryFormat, binary, binaryLength);
        free(binary);

        glGetProgramiv(progObj, GL_LINK_STATUS, &success);

        if (!success)
        {
            //
            // Something must have changed since the program binaries
            // were cached away.  Fallback to source shader loading path,
            // and then retrieve and cache new program binaries once again.
            //
        }
    }

Issues

    1. Do we need to consider state dependencies when using this extension?

    RESOLVED: A little. A program binary retrieved with GetProgramBinary
    can be expected to work regardless of the current GL state in effect at the
    time it was retrieved with GetProgramBinary, loaded with
    ProgramBinary, installed as part of render state with UseProgram, or used
    for drawing with DrawArrays or DrawElements.

    However, in many cases, internal state dependencies affect the way source
    shaders are compiled. State considerations may indicate whether
    optimizations are available or if workarounds are necessary. In
    consideration of these issues, users of this extension should be advised
    that querying the program binary after the full range of state
    configurations have been seen may allow the implementation to include
    optimized versions and avoid recompiles that may affect performance.

    2. How are shader objects involved, if at all?

    RESOLVED: Shader objects play no part in the specification of program
    binaries.  (See also Issue 3.)

    The program binary retrieved by GetProgramBinary is the one installed
    during the most recent call to LinkProgram or ProgramBinary, i.e. the one
    which would go into effect if we were to call UseProgram.  Attaching
    different shader objects after the most recent call to LinkProgram is
    inconsequential.

    3. Should we throw an error as a programming aid if there are shader objects
       attached to the program object when ProgramBinary is called?

    RESOLVED: No, they are irrelevant but harmless, and GL precedent is to throw
    errors on bad state combinations, not on harmless ones.  Besides, the
    programmer should discover pretty quickly that they're getting the wrong
    shader, if they accidentally called ProgramBinary instead of LinkProgram.
    Also, an app may intentionally leave the attachments in place if it for some
    reason is switching back and forth between loading a program object with
    program binaries, and loading it with compiled GLSL shaders.

    4. Where are the binary formats defined and described?

    RESOLVED: This extension provides a common infrastructure for retrieving and
    loading program binaries.  A vendor extension must also be present in order
    to define one or more binary formats, thereby populating the list of
    PROGRAM_BINARY_FORMATS.  The <binaryFormat> returned by
    GetProgramBinary is always one of the binary formats in this list.  If
    ProgramBinary is called with a <binaryFormat> not in this list, the
    implementation will throw an INVALID_ENUM error.

    The beauty of this extension, however, is that an application does not need
    to be aware of the vendor extension on any given implementation.  It only
    needs to retrieve a program binary with an anonymous <binaryFormat> and
    resupply that same <binaryFormat> when loading the program binary.

    5. Under what conditions might a call to ProgramBinary fail?

    RESOLVED: Even if a program binary is successfully retrieved with
    GetProgramBinary and then in a future run the program binary is
    resupplied with ProgramBinary, and all of the parameters are correct,
    the program binary load may still fail.

    This can happen if there has been a change to the hardware or software on
    the system, such as a hardware upgrade or driver update.  In this case the
    PROGRAM_BINARY_FORMATS list may no longer contain the binary format
    associated with the cached program binary, and INVALID_ENUM will be thrown
    if the cached program binary format is passed into ProgramBinary anyway.

    Even if the cached program binary format is still valid, ProgramBinary
    may still fail to load the cached binary.  This is the driver's way of
    signaling to the app that it needs to recompile and recache its program
    binaries because there has been some important change to the online
    compiler, such as a bug fix or a significant new optimization.

    6. Can BindAttribLocation be called after ProgramBinary to remap an
       attribute location used by the program binary?

    RESOLVED: No.  BindAttribLocation only affects the result of a subsequent
    call to LinkProgram.  LinkProgram operates on the attached shader objects
    and replaces any program binary loaded prior to LinkProgram.  So there is no
    mechanism to remap an attribute location after loading a program binary.

    However, an application is free to remap an attribute location prior to
    retrieving the program binary.  By calling BindAttribLocation followed by
    LinkProgram, an application can remap the attribute location.  If this is
    followed by a call to GetProgramBinary, the retrieved program binary will
    include the desired attribute location assignment.

    7. How does this spec differ from the OES_get_program_binary and why?

    To better facilitate state-dependent optimizations and workarounds, a hint
    is provided to ensure that the implementation includes any state-based
    variants it might encounter. These dependencies also encourage the
    programmer to retrieve binary programs late in the execution, after
    relevant state changes have already occurred.

    There are other areas where language was clarified, but this is meant to
    be consistent with the intent of the original specification and not to
    alter previously established behavior.

    8. How does ProgramBinary interact with uniform values, including
       shader-specified defaults?

    RESOLVED: All uniforms specified in the binary are reset to their shader-
    specified defaults, or to zero if they aren't specified, when the program
    binary is loaded. The spec language has been updated to specify this
    behavior.

    9. Should ProgramBinary be expected to load a previously saved program
       binary even if non-program state has changed enough such that a
       recompile is needed by the GL implementation.

    RESOLVED: Yes. Given the same configuration, for example hardware, driver
    version, etc., the GL implementation should save as much data as it needs
    with the program binary such that if a recompile is necessary it has all
    the data it needs to do this. Only if the configuration changes, it is
    acceptable to fail ProgramBinary.

    The application may use the PROGRAM_BINARY_RETRIEVABLE_HINT hint to
    indicate to the GL implementation that this program will likely be saved
    with GetProgramBinary at some point. This will give the GL implementation
    the opportunity to track any state changes made to the program before
    being saved such that when it is loaded again a recompile can be avoided.

Revision History
    09 07/05/2016 Fix missing GL_ prefix in example code.

    08 10/08/2013 Change GLvoid -> void (Bug 10412).

    07 06/14/2012 Clean up descriptions of "failed binary", add errors,
                  and move HINT description back to ProgramParameteri.

    06 07/19/2010 Fixed a teenie typo with OES left on ProgramBinaryOES in
                  issue #3.

    05 05/26/2010 Modifications based on feedback from Pat Brown and the
                  ARB f2f.

    04 05/17/2010 Restore the old "int" type for the length parameter
                  to ProgramBinary since matching the ratified GLES is more
                  important in this case.

    03 05/10/2010 Various minor cleanup based on feedback from Bruce.

    02 04/09/2010 Converted to ARB version for inclusion in OpenGL 4.1.

    01 01/11/2010 Initial EXT version.
