Twitter  Facebook  Google+  YouTube  E-Mail  RSS
The One Man MMO Project
The story of a lone developer's quest to build an online world :: MMO programming, design, and industry commentary
Faster Frames
By Robert Basler on 2016-01-09 02:15:05
Homepage: onemanmmo.com email:one at onemanmmo dot com

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 )
{
GLint success;
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() );
GLint status;
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 ...
}


GlShaders Result: 28 Cached, 0 Compiled, 28 Cache entries.

New Comment

Cookie Warning

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.

Comment (You can use HTML, but please double-check web link URLs and HTML tags!)
Your Name
Homepage (optional, don't include http://)
Email (optional, but automatically spam protected so please do)
What color is a lime? (What's this?)

  Admin Log In



[The Imperial Realm :: Miranda] [Blog] [Gallery] [About]
Terms Of Use & Privacy Policy