(Tested) Want to See a GLSL Binary Shader (GL_ARB_get_program_binary)?

OpenGL


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...
  // ...
}

9 thoughts on “(Tested) Want to See a GLSL Binary Shader (GL_ARB_get_program_binary)?”

  1. Cyril

    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 ?

  2. susheel

    Finally!! It’s about time.

    …After shouting for years on the OpenGL board!

  3. nap

    It will be very interesting to see timings of loading precompiled shader and loading shader with compilation in realtime.

  4. Leith

    Might be good to look at what the Cg toolkit produces in binary as I’m sure they will be related.

  5. Leith

    #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.

  6. Christophe

    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.

  7. MaNiAc

    @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.

  8. swajnaut

    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!

  9. Gianni

    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?

Comments are closed.