Skip to main content
GameDev.net gamedev.net
🔒 Locked

GLSL Conditional Statement causes performance hit?

Started by elias4444 Aug 10, 2009 at 12:32 PM 11 replies 12.6k views
Original Post
elias4444
elias4444
Just wondering about this one. I've been trying to build some dynamic shaders by placing uniforms in them that can act as "on/off" switches for different functions. One that I recently tried was for the option of doing a 3x3 shadowmap blur. The uniform is a float that I set to 0.0 if I want the function to be performed, or 1.0 if I don't. The code in the shader is straight forward: float sum = 0.0; if (shadowsActive < 1.0) { //// Single Pixel Lookup And sum//// sum = lookup(0.0, 0.0); //// 3x3 /////////////////////////// if (useSoftShadows < 1.0) { sum += lookup(1.0, 0.0); sum += lookup(-1.0, 0.0); sum += lookup(0.0, 1.0); sum += lookup(0.0, -1.0); sum += lookup(1.0, 1.0); sum += lookup(-1.0, 1.0); sum += lookup(-1.0, -1.0); sum += lookup(1.0, -1.0); sum /= 9.0; } } else { sum = 1.0; } The interesting problem is, even if "useSoftShadows" is set to 1.0, I still get the performance hit as if all the lookups were happening (even though they are not, which I've verified). Why is this? And is there a way around this?
nullsquared
nullsquared
Dynamic branching isn't really 100% dynamic.

Fragments are usually processed in groups, which means that even if your branch doesn't have an effect on the final result, it may be computed anyway.
elias4444
elias4444
So what's the best way to build a shader with dynamic components? (Like if you have one branch of code for a spotlight, and another if it's a directional light).
rbarris
rbarris
I wonder if the compiler is trying to flatten the code and is actually running both paths and then selecting one outcome.. I am not quite clear on your statement "as if all the lookups were happening (even though they are not)" - how would you know ?
idinev
idinev
The shader ISA has conditional-move instruction, and the compiler decides that the code-chunk is cheaper than a branch-instruction. There really is no standard way to force the compiler to use your preferred method: dynamic vs conditional-move. Pragmas, toying with a specific version of a compiler (cgc).

In the case of that string of lookup() calls, it's scary that the compiler chose the branch-less method. Point this problem out to the driver-developers, if a newer/older driver does the same.
elias4444
elias4444
I am not quite clear on your statement "as if all the lookups were happening (even though they are not)" - how would you know ?[/QUOTE]

You can see the results on the screen, whether it's actually calling the functions or not.
swiftcoder
swiftcoder
Quote:
Original post by elias4444
You can see the results on the screen, whether it's actually calling the functions or not.
You are testing whether the uniform value of 1.0 is less than the constant 1.0 - I wouldn't like to guarantee that floating-point inaccuracy isn't at work there. Perhaps use 0.5 as the constant to test against? The result should be the same:

if (useSoftShadows < 0.5)


Beyond that, different GLSL implementations have very different compiler and optimisation quality. The only sure way to 'turn off' code in this manner is to use the #ifdef/#endif preprocessor commands to remove the code, and compile one copy of the shader for each set of options.
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
elias4444
elias4444
I tried switching to <0.5, but the same issue persists.

I've heard that it's more performance friendly to build several shaders for multiple render possibilities. I was just hoping to get around it somehow (and avoid writing lots of duplicate code). Especially as the list of supported effects grows (shadow mapping, bump mapping, texturing, multitexturing, spotlights, pointlights, etc.).

zedz
zedz
yes especially on older cards the whole shader will be done for each fragment.

the best method is to have seperate shaders
one for the sotfshadows + one without + instead use the correct shader depending on the material
rbarris
rbarris
Quote:
Original post by elias4444
I am not quite clear on your statement "as if all the lookups were happening (even though they are not)" - how would you know ?[/QUOTE]

You can see the results on the screen, whether it's actually calling the functions or not.


I don't disagree that the final result should be as expected, however it is not uncommon for compilers to emit code which will evaluate both sides of an 'if' and then select one of the result values for output - preserving the semantics of the original code, but executing more code than you might expect at run time. In the example given, I believe the lookups could be getting executed and their results tossed out - they would still exert a time cost even though they did not affect the output. Sometimes referred to as "if-flattening".

IMO GLSL should be extended to allow for explicit hinting from the programmer along the lines of "I really want this if-statement flattened out" vs "I really do not want flattening to happen here because I know one side is much costlier than the other." This came up in GL WG discussions a few months back but I do not know if it is still under consideration.

As an experiment, deliberately hack the side of the if that is doing all the lookups, to do nothing (or just one perhaps) and then run it again (wired to take the non-lookup path). If it gets faster, then that gives you a clue that the lookups are indeed being evaluated no matter what the outcome of the 'if' is.
rbarris
rbarris
@OP - by the way what hardware / OS / driver are you running ?
elias4444
elias4444
Experiment done... yes, they're being evaluated no matter what. Anyone know of a good online tutorial that explains how to build a modular GLSL system?

Edit: I'm on Mac OS X, with an ATI 4870.
swiftcoder
swiftcoder
Quote:
Original post by elias4444
Edit: I'm on Mac OS X, with an ATI 4870.
Well, therein lies your problem.

Apple's GLSL compiler is notoriously bad at optimising - the WINE/CrossOver folks are constantly banging their heads on the wall over it. The driver is also brand new, as the Mac version of the 4870 only shipped a short while ago, so there is some hope it will improve with future updates.
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.