During OpenGL initialization, the program is supposed to do something like:
<Get Shader Source Code>
<Attach Source Code To Shader>
static const char * vs_source =
"#version 420 core \n"
"void main(void) \n"
" gl_Position = vec4(0.0, 0.0, 0.0, 1.0); \n"
vertexBuffer << vertexShaderFile.rdbuf();
std::string vertexBufferStr = vertexBuffer.str();
// Warning: safe only until vertexBufferStr is destroyed or modified
const GLchar *vertexSource = vertexBufferStr.c_str();
Program binary formats are not intended to be
transmitted. It is not reasonable to expect different hardware vendors
to accept the same binary formats. It is not reasonable to expect
different hardware from the same vendor to accept the same binary
There is just "store them directly in the executable" or "store them in (a) separate file(s)", with nothing inbetween. If you want a self-contained executeable, putting them into the binary is a good idea. Note that you can add them as resources or tweak your build system to embed the shader strings from separate development files into source files to make development easier (with the possible addition of being able to directly load the separate files in development builds).
Why do you think shipping the shader sources would be a problem? There is simply no other way in the GL. The precompiled binaries are only useful for caching the compilation results on the target machine. With the fast advances of GPU technology, and changing GPU architectures, and different vendors with totally incompatible ISAs, precompiled shader binaries do not make sense at all.
Note that putting your shader sources in the executeable does not "protect" them, even if you encrypt them. A user can still hook into the GL library and intercept the sources you specify to the GL. And the GL debuggers out there do exactly that.
At SIGGRAPH 2016, the OpenGL Architecture Review Board released the
GL_ARB_gl_spirv extension. This will allow a GL inmplementation to use the SPIRV binary intermediate language. This has some potential benefits:
With that scheme, GL is becoming more similar to D3D and Vulkan in that regard. However, it doesn't change the greater picture. The SPIRV bytecode can still be intercepted, disassembled and decompiled. It does make reverse-engineering a little bit harder, but not by much actually. In a shader, you usually can't afford extensive obfuscuation measures, since that dramatically reduces performance - which is contrary to what the shaders are for.
Also keep in mind that this extension is not widely available right now (autumn 2016). And Apple has stopped supporting GL after 4.1, so this extension will probably never come to OSX.