PDA

View Full Version : conditional expressions and division by 0

James W. Walker
02-19-2008, 07:16 PM
I understand that all but the most high-end graphics cards do not do true branching, but evaluate both branches and then pick one result. Normally, I can live with that. But I've run into a case where evaluating the wrong branch causes a division by 0, crashing the driver, and I don't know how to fix it.

The specific expression is

(q <= 0.0)? v : floor( v * q + vec3(0.5) ) / q

where q is a uniform float and v is a local vec3. Any ideas?

Korval
02-19-2008, 07:59 PM
Actually, I'd be a bit concerned that a divide-by-zero is crashing something. It should come up with garbage, not crash.

However, you could add to 'q' something suitably insignificantly small for whatever the values of 'q' are. That shouldn't through off the computation too much, and it would keep you from dividing by zero. Just make sure it isn't too small; GPUs are only required to have 24-bits of precision and none of them handle denormalized floats.

Ilian Dinev
02-20-2008, 01:38 PM
Don't forget the case of q== -epsilon :)
So, one way is:
(q <= 0.0)? v : floor( v * q + vec3(0.5) ) / ((abs(q)+0.0001)

and the other is a trick to the compiler, producing slower code and requiring Shader3 gpu:
vec3 result;
for(;;){
if(q<=0.0){ result=v; break; }else{result = floor( v * q + vec3(0.5) ) / q; break;}
}

Could it be that your shader is actually being emulated? PerfHUD might be doing this afaik. (can't install perfhud on my win2k to test..)

James W. Walker
02-20-2008, 02:41 PM

I suppose it's possible. I know how to find out on the Mac, but not on Windows, and the floating point exception happened on Windows. But wait, emulated by what? Apple has a software renderer capable of handling GLSL, but Microsoft doesn't.

PerfHUD might be doing this afaik. (can't install perfhud on my win2k to test..)

I don't know what PerfHUD is, so I suppose that means I'm not using it.

Thanks for the suggestions, but I decided to use different shader code depending on whether q is zero or not, eliminating the branch.

CaptainZ
02-20-2008, 02:58 PM
Here is what you can do to avoid that division by 0:

float safeq = (q <= 0.0) ? 1.0 : q;

then your expression use safeq instead of q in the result part:

(q <= 0.0)? v : floor( v * safeq + vec3(0.5) ) / safeq