Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GLSL(330) modulo returns unexpected value

I am currently working with GLSL 330 and came across some odd behavior of the mod() function. Im working under windows 8 with a Radeon HD 6470M. I can not recreate this behavior on my desktop PC which uses windows 7 and a GeForce GTX 260.

Here is my test code:

float testvalf = -126;
vec2 testval = vec2(-126, -126);

float modtest1 = mod(testvalf, 63.0);   //returns 63
float modtest2 = mod(testval.x, 63.0);  //returns 63
float modtest3 = mod(-126, 63.0);   //returns 0

Edit:

Here are some more test results done after IceCools suggestion below.

int y = 63;
int inttestval = -126;
ivec2 intvectest(-126, -126);
float floattestval = -125.9;


float modtest4 = mod(inttestval, 63); //returns 63
float modtest5 = mod(intvectest, 63); //returns vec2(63.0, 63.0)
float modtest6 = mod(intvectest.x, 63); //returns 63
float modtest7 = mod(floor(floattestval), 63); //returns 63
float modtest8 = mod(inttestval, y); //returns 63
float modtest9 = mod(-126, y); //returns 63

I updated my drivers and tested again, same results. Once again not reproducable on the desktop. According to the GLSL docs on mod the possible parameter combinations are (GenType, float) and (GenType, GenType) (no double, since we're < 4.0). Also the return type is forced to float but that shouldn't matter for this problem.

like image 452
wacki Avatar asked Sep 14 '25 22:09

wacki


1 Answers

I think I have found the answer.

One thing I've been wrong about is that mangsl's keyword for genType doesn't mean a generic type, like in a c++ template.

GenType is shorthand for float, vec2, vec3, and vec4 (see link - ctrl+f genType).

Btw genType naming is like:

genType - floats
genDType - doubles
genIType - ints
genBType - bools 

Which means that genType mod(genType, float) implies that there is no function like int mod(int, float).

All the code above have been calling float mod(float, float) (thankfully there is implicit typecast for function parameters, so mod(int, int) works too, but actually mod(float, float) is called).

Just as a proof:

int x = mod(-126, 63);
Doesn't compile: error C7011: implicit cast from "float" to "int"

It only doesn't work because it returns float, so it works like this:

float x = mod(-126, 63);

Therefore float mod(float, float) is called.

So we are back at the original problem:

  • float division is inaccurate
  • int to float cast is inaccurate
  • It shouldn't be a problem on most GPU, as floats are considered equal if the difference between them is less than 10^-5 (it may vary with hardware, but this is the case for my GPU). So floor(-2.0000001) is -2. Highp floats are far more accurate than this.
  • Therefore either you are not using highp floats (precision highp float; should fix it then) or your GPU has stricter limit for float equality, or some of the functions are returning less accurate value.
  • If all else fails try:

    #extension BlackMagic : enable

like image 118
IceCool Avatar answered Sep 17 '25 20:09

IceCool