Occasionally Miranda has long frames, one of the big culprits for that is glLinkProgram which takes 50ms per call, sometimes even longer. That's three frames worth just for a single OpenGL call and because of the way Miranda manages materials, it can happen any time. The solution for this in OpenGL 4.1 and above (or if your OpenGL supports ARB_get_program_binary) is glProgramBinary and glGetProgramBinary. These two functions allow you to save and load the compiled version of shaders completely bypassing calls to glLinkProgram. Binary shaders are hardware specific, so they can't be distributed with the game and they have to be discarded if the OpenGL driver is updated, but once they are compiled, Miranda uses the compiled shaders every single time - no more slow calls to glLinkProgram.
Put a cache on top of glProgramBinary and glGetProgramBinary which expires old entries and you have a compiled shader cache. Should glProgramBinary fail for any reason, the shader can be compiled and linked as usual.
// Load a cached program into the GPU.
bool ShaderCacheEntry::LoadProgram( GLuint program )
glProgramBinary( program, mBinaryFormat, mBinary, mBinarySize );
glGetProgramiv( program, GL_LINK_STATUS, &success );
return success == GL_TRUE;
// Save a linked program to the cache.
void ShaderCacheEntry::SaveProgram( GLuint program )
GLsizei bin_size = -1;
mBinaryFormat = -1;
// get the length of the binary code to be retrieved
glGetProgramiv( program, GL_PROGRAM_BINARY_LENGTH, &bin_size );
// retrieve binary code & code format
mBinary = static_cast( Memory::Allocate( bin_size, SHADER_CACHE_ENTRY_POOL ) );
glGetProgramBinary( program, bin_size, &mBinarySize, &mBinaryFormat, mBinary );
// This is the data that must be saved in the cache.
GLenum mBinaryFormat; // Binary format of program
GLsizei mBinarySize; // Size of program.
byte* mBinary; // Program
// Loading a shader program from the cache.
mProgramObject = glCreateProgram();
glTransformFeedbackVaryings( mProgramObject , mPrograms[ program - 1 ].GetNumVaryings(), mPrograms[ program - 1 ].GetVaryings(), GL_INTERLEAVED_ATTRIBS );
shaderCacheEntry.LoadProgram( mProgramObject );
// Saving a linked program object into the cache
glLinkProgram( mPrograms[ program - 1 ].GetHardwareProgram()->GetGlProgramId() );
glGetProgramiv( mPrograms[ program - 1 ].GetHardwareProgram()->GetGlProgramId(), GL_LINK_STATUS, &status );
// Make sure that link status is good before attempting to save program to cache.
if ( status == GL_TRUE )
shaderCacheEntry.SaveProgram( mPrograms[ program - 1 ].GetHardwareProgram()->GetGlProgramId() );
... insert shader into cache ...
We were unable to retrieve our session cookie from your web browser. If pressing F5 once to reload this page does not get rid of this message, please read this to learn more.
You will not be able to post until you resolve this problem.