# DX11 - Weird shader behavior with and without branching

I have found problem in my shader code, which I dont´t know how to solve.

I want to rewrite this code without "ifs"

tmp = evaluate and result is 0 or 1 (nothing else)
if (tmp == 1) val = X1;
if (tmp == 0) val = X2;


I rewite it this way, but this piece of code doesn ´t word correctly

tmp = evaluate and result is 0 or 1 (nothing else)
val = tmp * X1
val = !tmp * X2


However if I change it to:

tmp = evaluate and result is 0 or 1 (nothing else)
val = tmp * X1
if (!tmp) val = !tmp * X2


It works fine... but it is useless because of "if", which need to be eliminated

I honestly don´t understand it Posted Image . I tried compilation with NO and FULL optimalization, result is same

• How about some screenshots? What exactly is the problem? This looks like over micro-optimization. Apr 23, 2012 at 9:37
• I don't know what is operators precedence in HLSL, but can you try: val = (!tmp) * X2 ? Apr 23, 2012 at 9:52

Your problem is: !1 == -2, not !1 == 0.

val = tmp * X1;
val += (1 - tmp) * X2;


This works because:

1 * x = x

(1 - 1) * x =
0    * x = 0

-----------

0 * x = 0

(1 - 0) * x =
1    * x = x


As suggested by Nathan, to make the code more compact you can use lerp. The equation for lerp is (a * (1 - c)) + (b * c) which is identical to the equation you see above. Thus the code would become:

val = lerp(X2, X1, tmp);

• Smells like premature optimization though. Apr 23, 2012 at 10:36
• You could also write val = lerp(X2, X1, tmp), slightly more compact. Jun 26, 2012 at 21:40
• @NathanReed I didn't even realise that it was effectively the same equation as a lerp. Many thanks. Jun 28, 2012 at 10:11

I'd advise to just write it with regular branching in your shader code. The D3D shader compiler is extremely good at taking code like this and converting it to a non-branching equivalent in bytecode, and can also detect cases (they're rare but they do happen) where a branching solution is actually faster than a non-branching one. You definitely shouldn't assume that just because your HLSL code uses branching it means that the generated shader will also branch - have a look at the asm version of your shader in PIX and you may be in for an eye-opener - they can often be quite different.

It will also be much more maintainable going forward than if you do anything tricksy to avoid branches in HLSL code.

• +1 on this. I was suprised when I looked at my shaders how few of my branches ended up as branches in the generated code. Jun 27, 2012 at 10:56
• This is actually the definition of why premature optimization is evil - not because it's premature and not because it's optimization, but because it's trying to second-guess what the compiler/environment will do and creating a mess (maybe a small mess, but still a mess) while doing so. Jun 27, 2012 at 12:11