| Name |
| |
| OES_get_program_binary |
| |
| Name Strings |
| |
| GL_OES_get_program_binary |
| |
| Contributors |
| |
| Acorn Pooley |
| Aske Simon Christensen |
| David Garcia |
| Georg Kolling |
| Jason Green |
| Jeremy Sandmel |
| Joey Blankenship |
| Mark Callow |
| Robert Simpson |
| Tom Olson |
| |
| Contact |
| |
| Benj Lipchak, AMD (benj.lipchak 'at' amd.com) |
| |
| Notice |
| |
| Copyright (c) 2007-2013 The Khronos Group Inc. Copyright terms at |
| http://www.khronos.org/registry/speccopyright.html |
| |
| Status |
| |
| Ratified by the Khronos BOP, May 29, 2008. |
| |
| Version |
| |
| Last Modified Date: October 8, 2013 |
| Revision: #14 |
| |
| Number |
| |
| OpenGL ES Extension #47 |
| |
| Dependencies |
| |
| OpenGL ES 2.0 is required. |
| |
| Written based on the wording of the OpenGL ES 2.0 specification. |
| |
| Overview |
| |
| This extension introduces two new commands. GetProgramBinaryOES empowers an |
| application to use the GL itself as an offline compiler. The resulting |
| program binary can be reloaded into the GL via ProgramBinaryOES. 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! |
| 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. |
| |
| Note that an implementation supporting this extension need not include an |
| online compiler. That is, it is not required to support loading GLSL shader |
| sources via the ShaderSource command. A query of boolean value |
| SHADER_COMPILER can be used to determine if an implementation supports a |
| shader compiler. If not, the GetProgramBinaryOES command is rendered |
| virtually useless, but the ProgramBinaryOES command may still be used by |
| vendor extensions as a standard method for loading offline-compiled program |
| binaries. |
| |
| |
| Issues |
| |
| 1. Why introduce a new entrypoint for loading binaries when ShaderBinary |
| is already part of the core spec and permits loading binary shader pairs? |
| |
| RESOLVED: There are several reasons: |
| - Shader objects are taken out of the equation, since they're not |
| relevant to wholesale program object replacement. |
| - Implicit links during retrieval are no longer needed since we don't |
| need to keep shader object state in sync with program object state. |
| - Explicit links during program object reload are no longer needed since |
| the program binary is pre-linked and ready to run. |
| - The number of API calls needed to load program objects is much fewer. |
| - Complex error detection needed by the previous proposal is eliminated. |
| - No change to the retrieval/reload path is needed when new shader stages |
| are introduced by future extensions. |
| - This is a more elegant mapping for what we're trying to achieve! |
| |
| 2. Do we need to consider state dependencies when using this extension? |
| |
| RESOLVED: No more than you do when using GLSL source shaders. A program |
| binary retrieved with GetProgramBinaryOES can be expected to work regardless |
| of the current GL state in effect at the time it was retrieved with |
| GetProgramBinaryOES, loaded with ProgramBinaryOES, installed as part of |
| render state with UseProgram, or used for drawing with DrawArrays or |
| DrawElements. |
| |
| However, some implementations have internal state dependencies that affect |
| both GLSL source shaders and program binaries, causing them to run out of |
| resources when confronted by combinations of certain GL state and certain |
| shader program characteristics. An application need be concerned no more |
| with these issues when using program binaries than when using GLSL source |
| shaders. |
| |
| 3. How are shader objects involved, if at all? |
| |
| RESOLVED: Any shader objects attached to the program object at the time |
| GetProgramBinaryOES or ProgramBinaryOES is called are ignored. (See also |
| Issue 4.) |
| |
| The program binary retrieved by GetProgramBinaryOES is the one installed |
| during the most recent call to LinkProgram or ProgramBinaryOES, 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. |
| |
| 4. Should we throw an error as a programming aid if there are shader objects |
| attached to the program object when ProgramBinaryOES 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 ProgramBinaryOES 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. |
| |
| 5. 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_OES. The <binaryFormat> returned by |
| GetProgramBinaryOES is always one of the binary formats in this list. If |
| ProgramBinaryOES 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. |
| |
| 6. Under what conditions might a call to ProgramBinaryOES fail? |
| |
| RESOLVED: Even if a program binary is successfully retrieved with |
| GetProgramBinaryOES and then in a future run the program binary is |
| resupplied with ProgramBinaryOES, 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_OES 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 ProgramBinaryOES anyway. |
| |
| Even if the cached program binary format is still valid, ProgramBinaryOES |
| 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. |
| |
| 7. Can BindAttribLocation be called after ProgramBinaryOES 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 GetProgramBinaryOES, the retrieved program binary will |
| include the desired attribute location assignment. |
| |
| New Procedures and Functions |
| |
| void GetProgramBinaryOES(uint program, sizei bufSize, sizei *length, |
| enum *binaryFormat, void *binary); |
| |
| void ProgramBinaryOES(uint program, enum binaryFormat, |
| const void *binary, int length); |
| |
| New Tokens |
| |
| Accepted by the <pname> parameter of GetProgramiv: |
| |
| PROGRAM_BINARY_LENGTH_OES 0x8741 |
| |
| Accepted by the <pname> parameter of GetBooleanv, GetIntegerv, and |
| GetFloatv: |
| |
| NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE |
| PROGRAM_BINARY_FORMATS_OES 0x87FF |
| |
| Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL Operation) |
| |
| Update section 2.15, replace first sentence of last paragraph with: |
| |
| "OpenGL ES 2.0 provides interfaces to directly load pre-compiled shader |
| binaries, to directly load pre-linked program binaries, or to load the |
| shader sources and compile them." |
| |
| Add section 2.15.4, Program Binaries |
| |
| "The command |
| |
| void GetProgramBinaryOES(uint program, sizei bufSize, sizei *length, |
| enum *binaryFormat, void *binary); |
| |
| returns the program object's executable, 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 0 is returned in <length>, and 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_OES. When a program |
| object's LINK_STATUS is FALSE, its program binary length is zero, and a call |
| to GetProgramBinaryOES will generate an INVALID_OPERATION error. |
| |
| The command |
| |
| void ProgramBinaryOES(uint program, enum binaryFormat, |
| const void *binary, int length); |
| |
| loads a program object with a program binary previously returned from |
| GetProgramBinaryOES. 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 GetProgramBinaryOES, and <length> must |
| be the length of the program binary as returned by GetProgramBinaryOES or |
| GetProgramiv with <pname> PROGRAM_BINARY_LENGTH_OES. The program binary |
| will fail to load if these conditions are not met. |
| |
| An implementation may reject a program binary if it determines the program |
| binary was produced by 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 |
| ProgramBinaryOES. Either command sets the program object's LINK_STATUS to |
| TRUE or FALSE, as queried with GetProgramiv, to reflect success or failure. |
| Either command also updates its information log, queried with |
| GetProgramInfoLog, to provide details about warnings or errors. |
| |
| If ProgramBinaryOES failed, 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>. |
| |
| Note that ProgramBinaryOES disregards any shader objects attached to the |
| program object, as these shader objects are used only by LinkProgram. |
| |
| 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 GetProgramBinaryOES must be present in this list." |
| |
| GLX Protocol |
| |
| None. |
| |
| Errors |
| |
| INVALID_OPERATION error is generated if GetProgramBinaryOES 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.25, Program Object State) add the following: |
| |
| Get Value Type Get Command Initial Value Description Section |
| ------------- ---- ----------- ------------- ----------- ------- |
| PROGRAM_BINARY_LENGTH_OES Z+ GetProgramiv 0 Length of program binary 2.15.4 |
| |
| (table 6.28, Implementation Dependent Values) add the following: |
| |
| Get Value Type Get Command Minimum Value Description Section |
| ------------- ---- ----------- ------------- ----------- ------- |
| PROGRAM_BINARY_FORMATS_OES 0+*Z GetIntegerv N/A Enumerated program binary formats 2.15.4 |
| NUM_PROGRAM_BINARY_FORMATS_OES Z GetIntegerv 0 Number of program binary formats 2.15.4 |
| |
| (table 6.29, Implementation Dependent Values (cont.)) add the following: |
| |
| Get Value Type Get Command Minimum Value Description Section |
| ------------- ---- ----------- ------------- ----------- ------- |
| Binary format Z1 GetProgramBinaryOES N/A Binary format returned 2.15.2 |
| |
| Sample Usage |
| |
| void retrieveProgramBinary(const GLchar* vsSource, const GLchar* fsSource, |
| const char* myBinaryFileName, |
| GLenum* binaryFormat) |
| { |
| GLuint newFS, newVS; |
| GLuint newProgram; |
| GLchar* sources[1]; |
| GLint success; |
| |
| // |
| // 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); |
| |
| glLinkProgram(newProgram); |
| glGetProgramiv(newProgram, GL_LINK_STATUS, &success); |
| |
| if (success) |
| { |
| GLint binaryLength; |
| void* binary; |
| FILE* outfile; |
| |
| // |
| // Retrieve the binary from the program object |
| // |
| glGetProgramiv(newProgram, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength); |
| binary = (void*)malloc(binaryLength); |
| glGetProgramBinaryOES(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); |
| } |
| else |
| { |
| // |
| // Fallback to simpler source shaders? Take my toys and go home? |
| // |
| } |
| |
| // |
| // 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! |
| // |
| glProgramBinaryOES(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. |
| // |
| } |
| } |
| |
| Revision History |
| |
| #14 10/08/2013 Jon Leech Change GLvoid -> void (Bug 10412). |
| #13 06/02/2008 Benj Lipchak Fix typo: GLint -> int, update status. |
| #12 05/07/2008 Benj Lipchak Add Issue about BindAttribLocation. |
| #11 04/03/2008 Benj Lipchak Fix memory leaks in sample code. |
| #10 03/27/2008 Benj Lipchak Mark spec as ratified by the WG, add |
| new issues, and update sample code. |
| #09 03/13/2008 Benj Lipchak Many minor updates! Most notably, |
| introduce PROGRAM_BINARY_FORMATS_OES |
| and NUM_PROGRAM_BINARY_FORMATS_OES. |
| #08 03/12/2008 Benj Lipchak Rewrite as {Get}ProgramBinaryOES. Add |
| issues section. |
| #07 02/27/2008 Benj Lipchak When <bufSize> is too small, throw |
| error and return 0 in <length>. Limit |
| the allowed reasons for subsequent |
| binary rejection. Rename to OES and |
| GetShaderBinary. Add the LinkProgram |
| error condition. |
| #06 01/10/2008 Benj Lipchak Clarify that GetProgramInfoLog may be |
| called after an implicit link, and |
| clarify that the returned binary pair |
| must be loaded with a single call to |
| ShaderBinary or an error is thrown. |
| #05 01/08/2008 Benj Lipchak Clarify program object state after |
| GetProgramBinaryEXT, fix example code. |
| #04 01/02/2008 Benj Lipchak Split GetProgramBinary into its own |
| multi-vendor extension proposal. |
| #03 11/26/2007 Benj Lipchak Add sample usage and define tokens. |
| #02 10/22/2007 Benj Lipchak Add error conditions. |
| #01 10/14/2007 Benj Lipchak First draft. |