Page 1 of 1

GLSL mod() function acting up?

Posted: Fri Jul 28, 2017 11:36 am
by majaha
Hi guys, I'm trying to write some shaders here, but I'm running into some funny behaviour with the glsl mod() function. I was hoping someone with more knowledge of Videocore than me could tell me what's going on here.

The code below is run over the whole screen a la shadertoy.com, and explains itself in the comments:

Code: Select all

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec3 green = vec3(0., 1., 0.);
    vec3 red = vec3(1., 0., 0.);
    
    // a = 1.0, b = 2.0
    float a = 1.;
    float b = a + a;

    // split the screen into 4 parts.
    if (fragCoord.x < 1920./4.) {
	
	// shows green, so b == 2.
	if (b == 2.) {
	    fragColor.rgb = green;
	} else {
	    fragColor.rgb = red;
	}

	
    } else if (fragCoord.x < 2.*1920./4.) {
	
	// shows green, so mod(2., 2.) == 0
	if (mod(2., 2.) == 0.) {
	    fragColor.rgb = green;
	} else {
	    fragColor.rgb = red;
	}
	
    } else if (fragCoord.x < 3.*1920./4.) {

	// shows red, so mod(b, 2.) != 0, even though b == 2.
	if (mod(b, 2.) == 0.) {
	    fragColor.rgb = green;
	} else {
	    fragColor.rgb = red;
	}

    } else {

	// shows green, so mod(b, 2.) == 2
	if (mod(b, 2.) == 2.) {
	    fragColor.rgb = green;
	} else {
	    fragColor.rgb = red;
	}

	// so maybe this has to do with == being more about closeness
	// than exact equality? I don't know.
	
    }
	
}
Is it just me or does this make no sense? I'm aware of floating point inaccuracy, but as I understand it the values 1.0 and 2.0 can both be represented exactly. I'm using highp floats.
It works as expected on shadertoy.com too. What's going on?

Re: GLSL mod() function acting up?

Posted: Fri Jul 28, 2017 11:55 am
by PeterO
It would help if you actually told us what the problem is :roll:
What do expect to see and what do you actually see ?

PeterO

PS: It would also help if you post a complete example that demonstrates the problem. Just the shader source code isn't very helpful.

PeterO

Re: GLSL mod() function acting up?

Posted: Fri Jul 28, 2017 3:24 pm
by Paeryn
It looks like it's probably a precision issue with the reciprocal function (divisions are generally done as a multiplication by the reciprocal). Manually writing my own mod() as (x-y*floor(x/y)) causes my_mod(2.0, 2.0) == 2.0 as well. Further testing shows floor(b / b) == 0.0 where we know it should really be 1.0 so multiplying values by their own reciprocal can come out slightly under 1.0. and floor() returning 0 will cause mod to effectively return the first parameter.

Code: Select all

float mod2(float x) {
  return x - 2.0 * floor(x / 2.0);  // bugs out if x == 2.0
}

float mod2(float x) {
  return x - 2.0 * floor(x * 0.5); // fine
}
Though I am surprised the glsl compiler didn't rewrite the / 2.0 into * 0.5

Re: GLSL mod() function acting up?

Posted: Fri Jul 28, 2017 4:51 pm
by majaha
Thank you for your investigation Paeryn, it seems you're right about division/reciprocal being the problem.
I wonder if this is a hardware issue or if it's the sort of thing that can be fixed in drivers?

Re: GLSL mod() function acting up?

Posted: Fri Jul 28, 2017 6:20 pm
by PeterO
I was taught to never use tests for equality with any forms of folating point numbers.
PeterO