Shader load/unload system (OpenGL)

Started by
5 comments, last by Alberth 3 years, 2 months ago

Hi,
I would like to know how is shader's lifespan handled in game engines. I know that shaders are precompiled, shipped, and then at the end fully compiled on the user's GPU. But when? And how long do they stay compiled?


I have a simple system where shader counts references and when it is not referenced for some time by any mesh then it is deleted.
I think this is quite a good system because some shaders are not used often and they would take up memory on GPU. But I have to recompile the shader again when it is used which takes some time.
How bad is this approach? Should I rather load all shaders at once at the beginning of the program? Wouldn't that take up too much space?

Or there a way so that I can retrieve the compiled shaders before deleting them, storing them on disk, and then just push them back to GPU without compilation when needed?

Any help will be appreciated.

Advertisement

wonka007 said:
I know that shaders are precompiled, shipped, and then at the end fully compiled on the user's GPU. But when? And how long do they stay compiled?

Most modern graphics APIs follow this two step process of compiling into an intermediate binary format on the CPU (usually) which can then be quickly compiled by the graphics driver, depending on the graphics hardware, into the ultimate binary that ends up on the GPU. The exception here is OpenGL, which combines the two steps into one and just compiles shader sources directly into hardware-dependent binaries via the graphics driver.

With regards to game engine design, you usually want to compile your shaders during startup and let the GPU clean up the resources once the graphics context is torn down (at the end of your application's lifecycle). If it's a shader for, say, a screen space effect that will only be played once within your game, it wouldn't be a bad idea to get rid of your shader object after said effect, but usually recompiling shaders takes a considerable amount of game time so you DON'T want to get recompile them often, unless you are absolutely sure it won't be used again at all, or there is no other way other than hot loading the shader in your game. Best practice is to just compile all the shaders your game will need during startup and activate them when necessary, usually using some sort of reference counted resource model to keep track of your compiled shader objects (i.e. shared_ptr in c++ or something like that).

In relation to shaders taking up memory, please remember that shaders are very very small by comparison to most other GPU objects. You likely have individual textures or vertex buffers that are larger than all of your shaders combined.

So don't fret over memory use by shaders. Compile them once and keep them forever.

If you do have a huge amount of shaders, you could consider deferring the compilation to first time each shader is used. Alternatively there are simple techniques to reduce the number of shaders, such as sending uniform values of 0 or 1, or using a 1x1 all-black or all-white texture, that are frequently cheaper than writing yet another shader combination and incurring the cost of a shader change.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Thank you guys for your answers. You are a blessing from the sky.
I will load everything at once (preferably using precompiled shaders) and not care about unloading them for now because I will not have many of them now and I try to make them as generic as possible.

Thank you

I see that you've come to a good conclusion. The shader compile/link time cost is amortized more and more, every time that you use the shader program to draw some geometry.

wonka007 said:
I try to make them as generic as possible.

Perhaps try to make them as generic as needed.

This topic is closed to new replies.

Advertisement