5
\$\begingroup\$

I'm developing a little 2D game using OpenGL 4.x and I've also coded a very simple light system which does not take care of shadows. The main concept behind this light system is the frambuffer multiplicative blending. I basically have two framebuffers, one for the normal scene render and the other one for ambient light and the scene light sources. Then, I blend those two framebuffers and I get my final result (which is pretty good, to be honest).

In this model I have 3 different shader programs:

  • One for rendering the normal scene (with texturing and other normal features)
  • One for rendering lights, which compute light halos and other light effects
  • One for blending the two framebuffers together

Now, in my main application loop I have to switch between those three shader programs in order to complete a full rendering cycle. I'm also planning to add more shaders to render different light effects and particles. At the moment I'm in the design phase of my game, so I'm not able to test out the performance of this approach and I have no previous experience with it. And for the same reason I'd like to start with the best approach possibile for this situation.

So my question is: considering your experience, is switching between several shader programs at each frame something good or is it a bad behaviour in a 2D enviroment ? Is using fewer shader programs but with more if statement and more unused uniform variables a better solution?

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

In general, the fewer state changes the better. However, as state changes are unavoidable, there are some ways you can consider how to reduce the number of them.

Group/sort entities by shader/texture/mesh etc, so that you draw a bunch of stuff for each group with as few state changes as possible. To be honest though, as you are in the design phase, I wouldn't worry about this too much.

Get stuff working first, then optimise.

\$\endgroup\$
2
  • \$\begingroup\$ So far I'm already grouping them in chunks of entities which use the same shader (I render nomal Gameobjects first and then process lights). What I'm wondering is if it's more efficient to use a large number (say 6 o 7) number of shaders or to use fewer of them but with more if coded. \$\endgroup\$
    – Andrew
    Commented May 9, 2017 at 14:31
  • \$\begingroup\$ flow control statements carry their own costs. I honestly dont know how they compare to the cost of binding a shader, so you could profile it and see \$\endgroup\$
    – Ian Young
    Commented May 9, 2017 at 14:46
0
\$\begingroup\$

The best way to find out is to try both options and measure performance since this is not as easy to predict as it seems.

But there are a few points to keep in mind. One is that GLSL is not very good at branching. So while setting a uniform and then switch in the shader might look like a good idea because it reduces calling glUseProgram but can result in a worse performance since the graphics card is bad at branching.
Grouping shaders together and switch between these shaders might better. But in the end you should try both options and measure performance. When you decide to use less shaders and set options with uniforms I recommend to sort the vectors or whatever data structure you use by the uniform values and render them then.
But always measure performance in release builds and then decide. Also don't optimize to early. When the shaders are very simple and get more complex later the first performance runs might not be significant for the current system.

In this tutorial the same is said about branching in shader code.

\$\endgroup\$
2
  • \$\begingroup\$ Thank you for pointing out the bad branching performance. Honestly I didn't know about that and I've always assumed that switching a program (which involves several underlaying operations, I guess) would be way more expensive than checking some uniforms with an id statement. I'll try benchmarking to figure out the real performance cost difference. \$\endgroup\$
    – Andrew
    Commented May 9, 2017 at 15:44
  • 1
    \$\begingroup\$ Sorry for the necro, but I think it will help others: Be careful not to make quick assumptions like this for branching performances. You may have bad performances with branching when there is divergence (threads X takes one path and thread Y another) but when there is no divergence, as when your branch depends only on an uniform, it is totaly ok. Thanks for reminding that we always need to test to know what is better :) \$\endgroup\$
    – Lilymonade
    Commented Jun 19, 2019 at 7:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .