majaha
Posts: 2
Joined: Thu Jul 27, 2017 9:06 pm

GLSL mod() function acting up?

Fri Jul 28, 2017 11:36 am

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?

User avatar
PeterO
Posts: 4294
Joined: Sun Jul 22, 2012 4:14 pm

Re: GLSL mod() function acting up?

Fri Jul 28, 2017 11:55 am

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
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
Paeryn
Posts: 2212
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: GLSL mod() function acting up?

Fri Jul 28, 2017 3:24 pm

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
She who travels light — forgot something.

majaha
Posts: 2
Joined: Thu Jul 27, 2017 9:06 pm

Re: GLSL mod() function acting up?

Fri Jul 28, 2017 4:51 pm

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?

User avatar
PeterO
Posts: 4294
Joined: Sun Jul 22, 2012 4:14 pm

Re: GLSL mod() function acting up?

Fri Jul 28, 2017 6:20 pm

I was taught to never use tests for equality with any forms of folating point numbers.
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),Aeromodelling,1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

Return to “OpenGLES”