I managed to write a shader that clips any rect area on screen , its used for a 2D scrolling list … but have been reading a few things here and there on the net which seem to suggest that using if statements in a fragment can have severe performance costs. Im not clued up enough to understand many of the things mentioned in these things I read such as branching and warp and etc…
so here is my code , could anyone in the know tell me how bad it is. I also read using the discard method is not good because it breaks certain gpu early out optimizations so im just setting alpha to 0 instead. “_Clip” is a vector4 I set from a script acting as a rect x,y,width,height
v2f vert (appdata_t v)
{
v2f o;
o.vertex = mul (UNITY_MATRIX_MVP, v.vertex);
o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
o.screenPos = ComputeScreenPos(o.vertex);
return o;
}
half4 frag (v2f i) : COLOR
{
half4 texcol = tex2D (_MainTex, i.texcoord);
half texalpha = tex2D (_AlphaTex, i.texcoord).r;
texcol.a = (texalpha * _Alpha);
if(i.screenPos.x < _Clip.x){
texcol.a = 0;
};
if(i.screenPos.x > (_Clip.z)){
texcol.a = 0;
};
if(i.screenPos.y < (_Clip.y)){
texcol.a = 0;
};
if(i.screenPos.y > (_Clip.w)){
texcol.a = 0;
};
return texcol ;
}
interesting , this page http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0363d/CJAFCCDE.html
says conditional statements “if/for” on (mali 400) in Pixel processor have low impact on execution speed …
Yes, avoid conditional statements if you can. They’re very slow when it comes to shaders.
You might be better with step(x,y) which returns 1 or 0 depending on whether y is bigger than x.
So you could replace all your conditionals with this line.
texcol.a *= (step(_Clip.x, i.screenPos.x) * step(i.screenPos.x, _Clip.z)) * (step(_Clip.y, i.screenPos.y) * step(i.screenPos.y, _Clip.w));
Although I always get confused as to which way round the x,y go, so it might be this (same as above, but with the values reversed).
texcol.a *= (step(i.screenPos.x, _Clip.x) * step(_Clip.z, i.screenPos.x)) * (step(i.screenPos.y, _Clip.y) * step(_Clip.w, i.screenPos.y));
1 Like
Wow Thanks Farfarer , I did not know about the “step” method. I plugged your first example in and it worked. Seems you still know the order correctly on your first try 
Does that apply right now, though Farfarer? I mean, if you can elegantly avoid branching, I guess it doesn’t really matter, but isn’t the whole problem with conditional statements that all individual threads in a warp group have to execute both branches?
If he’s specifically targeting the Mali 400, that document he linked to is very interesting. At 6.2.2 (optimizing OpenCL code) they mention:
“Mali GPUs do not use warps or wavefronts. Remove any optimizations for these.”
and
“Threads on a Mali GPU are independent and cannot diverge. If your code contains optimizations or workarounds for divergent threads, remove them.”
Besides the problem with warp divergence (which doesn’t appear to apply to the Mali GPUs), is there something else that makes if statements significantly more inefficient than on a CPU?
Well my test device has a mali400 but obviously it not my only target , im just building a regular game which hopefully can reach and perform best on as many devices as possible…
So Im taking to avoiding if statements as the best solution in general?
I posted the link as a point of interest because it contradicts all the other info I read about performance costs of Conditionals in a fragment.
In general, I think you should write your code to be readable, so that when you have to optimize, you can focus on the algorithm, in stead of deciphering work-arounds you put in place as early optimizations.
If you can write easy to read code while avoiding branching, I’d say: go for it.
haha well if I actually knew what branching is in detail and all the ways in which it is used based on the code in the shader then good point … But since I do not know if my original code using the if statements was avoiding this branching problem or any other problem … I posted here to get clarification and learn along the way
Its not a case of early optimization but rather a case of I want to understand it all better. Im still a shader code noob but have started down the rabbit hole and now i am enjoying learning this aspect of programming.
I was under the impression that GPUs like “straight forward” stuff. As in, all linear path calculations.
I’m sure Aras (might’ve been someone else) mentioned a while back that conditionals are only really worthwhile if you’re going to end up saving a substantial amount of operations by not performing the calculations inside the conditional (something like 30+ operations).
I’m guessing it varies greatly between platforms and drivers, though.
Good post as the first answer here outlining that;
http://stackoverflow.com/questions/5340237/how-much-performance-do-conditionals-and-unused-samplers-textures-add-to-sm2-3-p
The slides for the Lecture called “An introduction to GPU programming” by Mike Giles really helped me understand one of the problems with if-statements.
From what I understand, the problem with if statements when programming for GPUs is that in many cases, both sides of the if-statement have to be computed, because the code is processed in large groups (called warps or wavefronts), using the same instructions, but different data (Single Instruction Multiple Data; SIMD).
So, when one part of the threads in a warp needs to run the first branch, and another part needs to run the second branch, both branches will be calculated for both parts. As a result, the shader takes as much time as both of the branches combined.
Apparently, the Mali chip doesn’t use warps, but handles each thread separately. So it doesn’t have to calculate both branches. Then again, it seems to me that you’re also automatically missing possible advantage of SIMD (It is only running code in parallel on the shader core level?).
1 Like