Skip to content

Instantly share code, notes, and snippets.

@shole
Created November 9, 2017 21:17
Show Gist options
  • Save shole/51328d41bb5d747c2ed01520680c0dda to your computer and use it in GitHub Desktop.
Save shole/51328d41bb5d747c2ed01520680c0dda to your computer and use it in GitHub Desktop.
Branchless shader logic
/*
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