Provide GL state for shader precompilation in order to prevent minor hickups.

If I know right OpenGL drivers often lazily compile shader programs based on the actual GL state or recompile the active program on state change. So maybe it is not enough to compile shader programs ahead of time at startup in order to prevent minor hickups when we use them in the actual scene. So I would like to capture the used GL state for the shader program and draw a dummy triangle on startup in order to trigger the compilation of the final program.

Could you please give me some advice how I could save the relevant states in order to pair with my shader collection? Is there any GL library which could help me in persisting state?
What are these relevant states which could trigger/effect the shader (re)compilation? Currently I collect these:

  • blend mode
  • vertex array definition

Probably not worth the effort.

If you really really need this. Then just go with Vulkan or D3D12.

If you run on something like desktop GPUs then shader caches automatically will solve your issues after the application run.

And desktop drivers also will do magic behind your back and you may not get what you want. E.g. they initially create a fast-and-dirty shader to minimize this kind of hickup, and in the background create a more optimized version of often used shaders and when done switch them out.

On the other hand, I’d say that it could definitely be worth the effort if you must have a consistent frame rate with no stuttering, especially if you’re working with an established, non-trivial OpenGL application. I’ve done something like this before myself.

If you’re going to be starting from scratch, sure it’s worth looking at Vulkan (or D3D12 if really want to limit yourself to Windows 10 only) as there you can marry the pipeline state with the shader up-front. But look carefully at that before you jump. There’s a pretty steep difficulty jump from OpenGL to those.

Should you decide to add something like this to an OpenGL application, here are a few thoughts. First, tracking state permutations is just mechanics. Ideally you’ve got some kind of state object (state permutation) defined in your application, and shaders are only rendered with certain state objects active. It may be enough to just cache off which state objects you render each shader permutation with and prerender those.

Also, if you’re not already, I’d get familiar with the shader caching mechanisms built into the GL drivers that you care about. That is, some GL drivers (like NVidia’s) cache compiled shader permutations on disk (not sure if these are stored with state permutations or not). This so that the next time it sees this shader, it can save a lot of time getting you the compiled, optimized shader object you need. Make the most use of this cache. Moreover, if you’re testing a state precompiling mechanism, be sure to delete this on-disk shader cache before running your tests or you’ll drive yourself nuts trying to figure out why your timings aren’t consistent.

One approach which unfortunately isn’t available cross-vendor but is available on NVidia is the State Objects in NV_command_list. This provides for capturing state permutations so that the driver can pre-validate them, avoiding costly frame time lurches at draw time. If you need something more widely supportable then it still helps to read through the extension spec and some of the material that references it (e.g. OpenGL like Vulkan, gl_commandlist_basic/statesystem.hpp, GPU-Driven Large Scene Rendering - NV_command_list as it gives you clues as to what a good starting set of state might be, at least on NVidia. Those states that you don’t use in your program, just ignore. Ideally this will net you a fairly small list to start from.