gepatto
Posts: 6
Joined: Tue Feb 24, 2015 10:25 am
Location: Breda, Netherlands

OpenGLES2 freeze in part of shader it shouldn't be reaching

Fri Aug 11, 2017 2:41 pm

Hi Folks,

I have a weird problem with a shader I'm debugging for openFL running on the raspberry pi.

OpenGLES freezes ( reboot is needed!) in a part of the shader that it shouldn't be reaching.
I have found a fix but I do not understand why it is working.

This is the fragment shader.

Code: Select all

		precision mediump float
		varying float vAlpha;
		varying mat4 vColorMultipliers;
		varying vec4 vColorOffsets;
		varying vec2 vTexCoord;
		
		uniform bool uColorTransform;
		uniform sampler2D uImage0;
		
		void main(void) {
			
			vec4 color = texture2D (uImage0, vTexCoord);
			
			if (color.a == 0.0) {
				
				gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0);
				
			} else if (uColorTransform) {
				
				color = vec4 (color.rgb / color.a, color.a);
				color = vColorOffsets + (color * vColorMultipliers);
				
				gl_FragColor = vec4 (color.rgb * color.a * vAlpha, color.a * vAlpha);
				
			} else {
				
				gl_FragColor = color * vAlpha;
				
			}
			
		}
and here's the vertex shader:

Code: Select all

attribute float aAlpha;
		attribute mat4 aColorMultipliers;
		attribute vec4 aColorOffsets;
		attribute vec4 aPosition;
		attribute vec2 aTexCoord;
		varying float vAlpha;
		varying mat4 vColorMultipliers;
		varying vec4 vColorOffsets;
		varying vec2 vTexCoord;
		
		uniform mat4 uMatrix;
		uniform bool uColorTransform;
		
		void main(void) {
			
			vAlpha = aAlpha;
			vTexCoord = aTexCoord;
			
			if (uColorTransform) {
				
				vColorMultipliers = aColorMultipliers;
				vColorOffsets = aColorOffsets;
				
			}
			
			gl_Position = uMatrix * aPosition;
			
		}
the uColorTransform is set to true when we are using a colorTransform in the code and the vColorMultipliers is a mat4 filled with values.
But when uColorTransform = false It shouldn't be reaching that part of the shader, but it still freezes!
I know color.a is the culprit, If I comment it out or check for a value > 0.0 the freeze is gone, even though it's never getting to that part of the shader.

So by changing the uColorTransfrom part to

Code: Select all

	else if (uColorTransform) {
				color = vec4 (color.rgb / color.a, color.a);
				color = vColorOffsets + (color * vColorMultipliers);
				
				if(color.a > 0.0){
					gl_FragColor = vec4 (color.rgb * color.a * vAlpha, color.a * vAlpha);
				}
	}

I can fix it. But I really want to understand what is happening.
Is this caused by an optimisation or am I missing something else?

Kind Regards
Patrick

User avatar
paddyg
Posts: 2161
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: OpenGLES2 freeze in part of shader it shouldn't be reaching

Tue Aug 15, 2017 11:44 am

Hi, I've found that things like if and for don't run the way you might expect from normal CPU code (in this version of GLSL anyway). So in a fractal shader, say, it doesn't seem to possible to speed the code up by trying to break out of the loop early. Also ifs seem to slow the code down quite a lot as does dividing. Using min, max, clamp, mix, step, smoothstep in convoluted ways often seems to be significantly faster!!
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

LdB
Posts: 827
Joined: Wed Dec 07, 2016 2:29 pm

Re: OpenGLES2 freeze in part of shader it shouldn't be reaching

Tue Aug 15, 2017 12:56 pm

Your code is a problem on any C/C++ plus many other compilers like GLSL, you may want to review what literal 0.0 gets converted too.
Hint 0.0f, 0.0 & 0.0lf are all different :-)

So your if test compares 0.0 in one precision to the literal translation of 0.0 and on many CPU's those two things are not the same. That will fail on many many CPU's because of slight epsilon errors.

If you haven't heard it before don't ever compare floating points unless they are the same precision. If you really want to do it, define some small value epsilon value and add +- to the compare.

It happens on a great number of GLSL systems and is usually asked this way
https://stackoverflow.com/questions/175 ... il-in-glsl

So nothing to do with the PI or the shader it is your code and it needs correction.

Given the shader compiler is definitely aware of different precisions (its quite advanced GPU and allowed that in GLES2) I would be very very careful using any literal value naked.

jeremythorne
Posts: 1
Joined: Thu Aug 17, 2017 2:48 pm

Re: OpenGLES2 freeze in part of shader it shouldn't be reaching

Thu Aug 17, 2017 7:29 pm

The raspberry pi GPU is a SIMD device (single instruction multiple data). When it is executing a fragment shader it is trying to run the same code for multiple pixels at the same time. When it encounters an if statement, potentially the if statement could be true for some pixels and false for others. If the GPU branched then different pixels would need to execute different instructions which it can't handle. Instead it records the evaluation of the if statement in condition flags. Then it runs the code for both the if and the else clauses (which is when it hits your bug) and finally it chooses which set of results to keep based on the condition flags.

Return to “OpenGLES”

Who is online

Users browsing this forum: No registered users and 1 guest