As I said in this news, I’ll test as soon as possible the GL_ARB_get_program_binary extension with an OpenGL 2 context. Well, it’s done!
NVIDIA driver R259.09 exposes this extension for an OpenGL 4 context but also for an OpenGL 2 context. So let’s see to what an ascii GLSL shader looks like.
Here is the GLSL vertex shader:
void main() { gl_Position = gl_Vertex; };
and here is the pixel shader:
void main() { gl_FragColor=vec4(1.0, 0.4, 1.0, 1.0); };
And here is the binary representation of this very simple GLSL shader:
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00000000 01 00 00 00 00 00 00 00 08 00 00 00 44 50 00 03 ............DP.. 00000010 01 2B 06 00 00 00 00 24 38 06 00 00 C8 91 13 07 .+.....$8...È‘.. 00000020 B0 C4 12 07 00 00 00 00 00 00 00 00 00 00 00 00 °Ä.............. 00000030 00 00 00 00 00 00 00 00 50 01 86 01 00 00 00 00 ........P.†..... 00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060 00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF ........ÿÿÿÿÿÿÿÿ 00000070 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000080 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000090 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 000000A0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 000000B0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 000000C0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 000000D0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 000000E0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 000000F0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000100 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000110 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000120 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000130 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000140 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000150 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000160 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000170 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000180 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 00000190 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 000001A0 FF FF FF FF FF FF FF FF 00 00 00 00 01 00 00 00 ÿÿÿÿÿÿÿÿ........ 000001B0 48 96 12 07 0A 00 00 00 00 BE 13 07 09 00 00 00 H–.......¾...... 000001C0 00 00 00 00 01 00 00 00 D8 C1 12 07 0C 00 00 00 ........ØÁ...... 000001D0 18 C2 12 07 0B 00 00 00 01 00 00 00 78 96 12 07 .Â..........x–.. 000001E0 01 00 00 00 28 BE 13 07 0D 00 00 00 A0 BE 13 07 ....(¾...... ¾.. 000001F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000220 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000230 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000250 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000270 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000280 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000290 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 000002D0 00 00 00 00 01 00 00 00 38 06 00 00 01 01 00 00 ........8....... 000002E0 09 00 00 00 00 00 00 00 01 00 00 00 52 8B 00 00 ............R‹.. 000002F0 00 00 00 00 67 6C 5F 56 65 72 74 65 78 00 00 00 ....gl_Vertex... 00000300 00 00 0B 00 00 00 00 00 00 00 01 00 00 00 52 8B ..............R‹ 00000310 00 00 01 00 00 00 04 00 00 00 01 00 00 00 00 00 ................ 00000320 00 00 00 00 00 00 67 6C 5F 50 6F 73 69 74 69 6F ......gl_Positio 00000330 6E 00 0C 00 00 00 00 00 00 00 00 00 00 00 00 00 n............... 00000340 00 00 67 6C 5F 46 72 61 67 43 6F 6C 6F 72 00 82 ..gl_FragColor.‚ 00000350 01 00 00 21 21 4E 56 76 70 35 2E 30 0A 23 20 63 ...!!NVvp5.0.# c 00000360 67 63 20 76 65 72 73 69 6F 6E 20 33 2E 30 2E 30 gc version 3.0.0 00000370 30 30 31 2C 20 62 75 69 6C 64 20 64 61 74 65 20 001, build date 00000380 4A 75 6C 20 32 34 20 32 30 31 30 0A 23 20 63 6F Jul 24 2010.# co 00000390 6D 6D 61 6E 64 20 6C 69 6E 65 20 61 72 67 73 3A mmand line args: 000003A0 20 0A 23 76 65 6E 64 6F 72 20 4E 56 49 44 49 41 .#vendor NVIDIA 000003B0 20 43 6F 72 70 6F 72 61 74 69 6F 6E 0A 23 76 65 Corporation.#ve 000003C0 72 73 69 6F 6E 20 33 2E 30 2E 30 2E 31 0A 23 70 rsion 3.0.0.1.#p 000003D0 72 6F 66 69 6C 65 20 67 70 35 76 70 0A 23 70 72 rofile gp5vp.#pr 000003E0 6F 67 72 61 6D 20 6D 61 69 6E 0A 23 76 61 72 20 ogram main.#var 000003F0 66 6C 6F 61 74 34 20 67 6C 5F 50 6F 73 69 74 69 float4 gl_Positi 00000400 6F 6E 20 3A 20 24 76 6F 75 74 2E 50 4F 53 49 54 on : $vout.POSIT 00000410 49 4F 4E 20 3A 20 48 50 4F 53 20 3A 20 2D 31 20 ION : HPOS : -1 00000420 3A 20 31 0A 23 76 61 72 20 66 6C 6F 61 74 34 20 : 1.#var float4 00000430 67 6C 5F 56 65 72 74 65 78 20 3A 20 24 76 69 6E gl_Vertex : $vin 00000440 2E 50 4F 53 49 54 49 4F 4E 20 3A 20 41 54 54 52 .POSITION : ATTR 00000450 30 20 3A 20 2D 31 20 3A 20 31 0A 41 54 54 52 49 0 : -1 : 1.ATTRI 00000460 42 20 76 65 72 74 65 78 5F 61 74 74 72 69 62 5B B vertex_attrib[ 00000470 5D 20 3D 20 7B 20 76 65 72 74 65 78 2E 61 74 74 ] = { vertex.att 00000480 72 69 62 5B 30 2E 2E 30 5D 20 7D 3B 0A 4D 4F 56 rib[0..0] };.MOV 00000490 2E 46 20 72 65 73 75 6C 74 2E 70 6F 73 69 74 69 .F result.positi 000004A0 6F 6E 2C 20 76 65 72 74 65 78 2E 61 74 74 72 69 on, vertex.attri 000004B0 62 5B 30 5D 3B 0A 45 4E 44 0A 23 20 31 20 69 6E b[0];.END.# 1 in 000004C0 73 74 72 75 63 74 69 6F 6E 73 2C 20 30 20 52 2D structions, 0 R- 000004D0 72 65 67 73 0A 00 00 00 00 47 01 00 00 21 21 4E regs.....G...!!N 000004E0 56 66 70 35 2E 30 0A 23 20 63 67 63 20 76 65 72 Vfp5.0.# cgc ver 000004F0 73 69 6F 6E 20 33 2E 30 2E 30 30 30 31 2C 20 62 sion 3.0.0001, b 00000500 75 69 6C 64 20 64 61 74 65 20 4A 75 6C 20 32 34 uild date Jul 24 00000510 20 32 30 31 30 0A 23 20 63 6F 6D 6D 61 6E 64 20 2010.# command 00000520 6C 69 6E 65 20 61 72 67 73 3A 20 0A 23 76 65 6E line args: .#ven 00000530 64 6F 72 20 4E 56 49 44 49 41 20 43 6F 72 70 6F dor NVIDIA Corpo 00000540 72 61 74 69 6F 6E 0A 23 76 65 72 73 69 6F 6E 20 ration.#version 00000550 33 2E 30 2E 30 2E 31 0A 23 70 72 6F 66 69 6C 65 3.0.0.1.#profile 00000560 20 67 70 35 66 70 0A 23 70 72 6F 67 72 61 6D 20 gp5fp.#program 00000570 6D 61 69 6E 0A 23 76 61 72 20 66 6C 6F 61 74 34 main.#var float4 00000580 20 67 6C 5F 46 72 61 67 43 6F 6C 6F 72 20 3A 20 gl_FragColor : 00000590 24 76 6F 75 74 2E 43 4F 4C 4F 52 20 3A 20 43 4F $vout.COLOR : CO 000005A0 4C 30 5B 30 5D 20 3A 20 2D 31 20 3A 20 31 0A 4F L0[0] : -1 : 1.O 000005B0 55 54 50 55 54 20 72 65 73 75 6C 74 5F 63 6F 6C UTPUT result_col 000005C0 6F 72 30 20 3D 20 72 65 73 75 6C 74 2E 63 6F 6C or0 = result.col 000005D0 6F 72 3B 0A 4D 4F 56 2E 46 20 72 65 73 75 6C 74 or;.MOV.F result 000005E0 5F 63 6F 6C 6F 72 30 2C 20 7B 31 2C 20 30 2E 34 _color0, {1, 0.4 000005F0 30 30 30 30 30 30 31 2C 20 30 2C 20 30 7D 2E 78 0000001, 0, 0}.x 00000600 79 78 78 3B 0A 45 4E 44 0A 23 20 31 20 69 6E 73 yxx;.END.# 1 ins 00000610 74 72 75 63 74 69 6F 6E 73 2C 20 30 20 52 2D 72 tructions, 0 R-r 00000620 65 67 73 0A 00 00 00 00 00 00 00 00 00 00 00 00 egs............. 00000630 00 00 00 00 00 00 00 00 ........
And here is the code I used to generate this binary shader:
PFNGLGETPROGRAMIVPROC glGetProgramiv = 0; glGetProgramiv = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress("glGetProgramiv"); typedef void * (WINAPI * PFNGLGETPROGRAMBINARYPROC) (unsigned int, size_t, size_t *, GLenum *, void *); PFNGLGETPROGRAMBINARYPROC glGetProgramBinary = 0; glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)wglGetProcAddress("glGetProgramBinary"); if (glGetProgramBinary && glGetProgramiv) { static char *vertexShader=\ "void main()" "{" "gl_Position = gl_Vertex;" "}"; static char *fragmentShader=\ "void main()" "{" "gl_FragColor=vec4(1.0, 0.4, 1.0, 1.0);" "}"; int p = glCreateProgram(); int v = glCreateShader(GL_VERTEX_SHADER); glShaderSource(v, 1, &vertexShader, 0); glCompileShader(v); glAttachShader(p,v); int f = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(f, 1, &fragmentShader, 0); glCompileShader(f); glAttachShader(p,f); glLinkProgram(p); glUseProgram(p); #define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE #define GL_PROGRAM_BINARY_FORMATS 0x87FF GLint formats = 0; glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &formats); GLint *binaryFormats = new GLint[formats]; glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, binaryFormats); #define GL_PROGRAM_BINARY_LENGTH 0x8741 GLint len=0; GLint progId = gpu->getGpuShaderData()->m_program_id; glGetProgramiv(progId, GL_PROGRAM_BINARY_LENGTH, &len); u8* binary = new u8[len]; glGetProgramBinary(progId, len, NULL, (GLenum*)binaryFormats, binary); glUseProgram(0); FILE* fp = fopen("shader.bin", "wb"); fwrite(binary, len, 1, fp); fclose(fp); delete [] binary; // Don't forget the destruction of the GLSL shader... // ... }
Humm… It looks like the beginning is simply a binary header, and that the code is in fact an NVvp5.0 ARB assembly stored in text format at the end, no ?
Finally!! It’s about time.
…After shouting for years on the OpenGL board!
It will be very interesting to see timings of loading precompiled shader and loading shader with compilation in realtime.
Might be good to look at what the Cg toolkit produces in binary as I’m sure they will be related.
#cgc version 3.0.0001, build date Jul 24 2010
# command line args:
#vendor NVIDIA Corporation
#version 3.0.0.1
#profile gp5vp
There you go.
That is what you need to run Cg with to get the same or similar output.
The binary API have been design for caching purposes.
Loading can fail for any reason and it is not attended to be use for shipping within a software release.
@Christophe: I have a feeling that you’re right, although i can’t see any solid proof (yet). 🙂
I guess the best practice is still to compile shaders during the first run of the application, then to save them in compiled format in a cache dir or whatever and only recompile them upon forced cache rebuild or hardware change, etc.
Not that i don’t realize this thread is year old … but you’re doing it wrong.
glGetProgramBinary() *writes* to binaryFormats, there is no need to call
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &formats);
glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, binaryFormats);
It is sufficient to allocate space for a single binary format (or just use plain scalar variable).
On the other hand, you *must* store the binary format that is returned so it can be passed to glProgramBinary() once the program is loaded.
The only reason why this works is the implementation actually only defines a single binary format, so you can’t go wrong … but in the future, there might be more formats and your code will cease wokring. Read the specs!
Did you try that on a Radeon as well?
On a nVidia card it’s compiled to a NVvp5.0 assembly, what does it get compiled to on a Radeon?