Created
November 9, 2017 21:17
-
-
Save shole/51328d41bb5d747c2ed01520680c0dda to your computer and use it in GitHub Desktop.
Branchless shader logic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Branchless shader logic made sane with macros; | |
usage; | |
if (depth>pointdepth){ | |
col=tex2D(_CameraColorTextureP,o.uv); | |
}else{ | |
col=tex2D(_MainTex,o.uv); | |
} | |
col=_IF(_GT(depth,pointdepth), | |
tex2D(_CameraColorTextureP,o.uv), | |
tex2D(_MainTex,o.uv) | |
); | |
or more complex; | |
if ( depth>pointdepth && depth!=1 ){ | |
col=tex2D(_CameraColorTextureP,o.uv); | |
}else{ | |
col=tex2D(_MainTex,o.uv); | |
} | |
col=_IF( _AND( _GT(depth,pointdepth), _NEQ(depth,1) ), | |
tex2D(_CameraColorTextureP,o.uv), | |
tex2D(_MainTex,o.uv) | |
); | |
*/ | |
#define _IF(x,a,b) lerp(b,a,x) | |
/* | |
Originally from: | |
http://theorangeduck.com/page/avoiding-shader-conditionals | |
Avoiding Shader Conditionals | |
Created on March 29, 2013, 2:09 p.m. | |
Having conditionals in shaders can often have a serious performance impact on the code. | |
Compilers can sometimes find clever ways to optimize them away, but if your shader code | |
really does have to branch and perform comparisons the speed can drop off significantly. | |
To avoid these situations I designed a number of functions which allow you to do things | |
often done using conditionals. They perform some comparison and then return 1.0 on true | |
and 0.0 on false. This can be useful, for example, if you want to add a number to another | |
number, but only when some condition is true. | |
if (x == 0) { | |
y += 5; | |
} | |
This can be transformed to the following. | |
y += 5 * when_eq(x, 0) | |
It doesn't cover all cases but most of the time some clever thinking can transform the | |
comparison into this kind of operation. The full set of functions are defined here: | |
*/ | |
inline float4 when_eq(float4 x, float4 y) { | |
return 1.0 - abs(sign(x - y)); | |
} | |
inline float4 when_neq(float4 x, float4 y) { | |
return abs(sign(x - y)); | |
} | |
inline float4 when_gt(float4 x, float4 y) { | |
return max(sign(x - y), 0.0); | |
} | |
inline float4 when_lt(float4 x, float4 y) { | |
return max(sign(y - x), 0.0); | |
} | |
inline float4 when_ge(float4 x, float4 y) { | |
return 1.0 - when_lt(x, y); | |
} | |
inline float4 when_le(float4 x, float4 y) { | |
return 1.0 - when_gt(x, y); | |
} | |
/* | |
These are defined in GLSL, and used on the vec4 types. Using vec4 the comparison is done | |
component-wise, which means you can do four comparisons at once! Similar logic can also be | |
used for any other shading language or vector/float type. The logic behind the functions | |
is fairly simple, and underlies the actual maths behind comparison which computers use. | |
This is exactly the kind of transformation a smart compiler would do to optimize | |
conditionals away from your code naturally. | |
As a bonus here are a set of logical operators you can use together with | |
the outputs from these comparisons. | |
*/ | |
inline float4 and(float4 a, float4 b) { | |
return a * b; | |
} | |
inline float4 or(float4 a, float4 b) { | |
return min(a + b, 1.0); | |
} | |
inline float4 xor(float4 a, float4 b) { | |
return (a + b) % 2.0; | |
} | |
inline float4 not(float4 a) { | |
return 1.0 - a; | |
} | |
/* | |
Macro versions; | |
*/ | |
// ----- Comparators | |
#define _EQ(x,y) (1.0 - abs(sign(x - y))) | |
#define _NEQ(x,y) abs(sign(x - y)) | |
#define _GT(x,y) max(sign(x - y), 0.0) | |
#define _LT(x,y) max(sign(y - x), 0.0) | |
#define _GE(x,y) (1.0 - _LT(x, y)) | |
#define _LE(x,y) (1.0 - _GT(x, y)) | |
// ----- Logic | |
#define _AND(a,b) (a*b) | |
#define _OR(a,b) min(a + b, 1.0) | |
#define _XOR(a,b) ((a + b) % 2.0) | |
#define _NOT(a) (1.0 - a) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment