Sign in to follow this  

AMD GLSL "subtle" or "quiet" error.

This topic is 1271 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

My GLSL shader in my game engine has a very odd bug that my roomate found today. On his AMD graphics card any model that is skinned/animated is invisible. The models show up fine on my Nvidia card so this is ATI specific. The shaders compile fine on his card and there are no errors in the AMD GPU shader analyzer which is very odd.

 

We messed with this for a few hours and I found the block of code that causes the invisible models glitch. It's the part of the GLSL vertex shader that does the rotation for skinned meshes. Something here IS causing the problem. If I comment this out everything renders fine but nothing rotates obviously.

 

Here are all my uniforms, attributes, and varyings in the vertex shader:

uniform bool bRotation;
uniform vec4 modelPosition;
uniform vec4 modelRotation;
uniform float modelScale;
uniform bool bSkin;
uniform vec3 bonesOffset[64];
uniform vec3 bonesPos[64];
uniform vec4 bonesRot[64];
uniform vec4 sunLocation;
uniform vec3 sunDir;

varying vec3 halfVec;
varying vec3 eyeVec;
varying vec3 lightVec;

varying vec4 position;
varying vec3 normal;

attribute vec3 indices;
attribute vec3 weights;
attribute vec3 tangent;

varying vec4 nearShadowCoord;
varying vec4 farShadowCoord;

Here is the part of the vertex shader that is causing the problem:

		//do rotation
		i = 0;
		vec4 v = pos;
		vec4 rot[3];
		vec4 nor[3];
		
		while(i < 3) {
			vec4 r = bonesRot[int(indices[i])];
			rot[i] = vec4(quatRotation(vec3(v.x, v.y, v.z), r), 0.0f);
			nor[i] = vec4(quatRotation(normal, r), 0.0f);
			i++;
		}
		
		//Average the rotations by weight and apply them
		i = 0;
		vec4 final;
		normal = vec3(0.0f,0.0f,0.0f);
		while(i < 3) {
			final.x += (rot[i].x * weights[i]);
			final.y += (rot[i].y * weights[i]);
			final.z += (rot[i].z * weights[i]);
			normal.x += (nor[i].x * weights[i]);
			normal.y += (nor[i].y * weights[i]);
			normal.z += (nor[i].z * weights[i]);
			i++;
		}
		
		pos = final;

And here is the quatRotation() function that is used in the above code on lines 8 and 9:

vec3 quatRotation(vec3 v, vec4 r) {
			float q00 = 2.0f * r.x * r.x;
			float q11 = 2.0f * r.y * r.y;
			float q22 = 2.0f * r.z * r.z;
	
			float q01 = 2.0f * r.x * r.y;
			float q02 = 2.0f * r.x * r.z;
			float q03 = 2.0f * r.x * r.w;
	
			float q12 = 2.0f * r.y * r.z;
			float q13 = 2.0f * r.y * r.w;
	
			float q23 = 2.0f * r.z * r.w;
			vec3 f = vec3(0.0f,0.0f,0.0f);
			f.x = (1.0f - q11 - q22) * v.x + (q01 - q23) * v.y + (q02 + q13) * v.z;
			f.y = (q01 + q23) * v.x + (1.0f - q22 - q00) * v.y + (q12 - q03) * v.z;
			f.z = (q02 - q13) * v.x + (q12 + q03) * v.y + (1.0f - q11 - q00) * v.z;
			return f;
}

I have no idea what's actually wrong with my code. I develop on Nvidia and everything works great. I'm stumped D:

Edited by newObjekt

Share this post


Link to post
Share on other sites

If nothing is rendered, most likely your shader program does not compile on ATI. Nvidia is known for more relaxed enforcement of correct GLSL code, therefor you might have an GLSL specific error which will be accepted by Nvidia but rejected by ATI. Best to log out the error messages after compiling your GLSL code, this will help you to quickly track down your error.

Share this post


Link to post
Share on other sites

If nothing is rendered, most likely your shader program does not compile on ATI. Nvidia is known for more relaxed enforcement of correct GLSL code, therefor you might have an GLSL specific error which will be accepted by Nvidia but rejected by ATI. Best to log out the error messages after compiling your GLSL code, this will help you to quickly track down your error.

 

Good advice in general but the OP has already said:

 

 

The shaders compile fine on his card and there are no errors in the AMD GPU shader analyzer which is very odd.

Share this post


Link to post
Share on other sites

Good advice in general but the OP has already said:

Yes, I know, thought I always recommmend to double check the error messages on the GPU/driver it does not run on.

 

 

 


Something here IS causing the problem.

This must not be the issue. There are really many ways were a shader could break. Eg you use 3*64 registers for your bone data, if you comment out the presented section, the compiler will most likely remove 1*64 registers (for bonerot). This downgrad (~192 register -> ~128 register, try to produce the same effect by cutting down from 64 to 42 registers for all 3 arrays, just for testing purpose) could be enough to get your code running on (really) older hardware with limited registers. I just want to say, that uncommenting some shader code is not always a granted way to pin-down bugs in a shader.

 

Btw, what hardware are you using ?

Edited by Ashaman73

Share this post


Link to post
Share on other sites

Your code makes my eyes hurt :)

        while(i < 3) {
            final.xyz += (rot[i].xyz * weights[i]);
            normal += (nor[i] * weights[i]);
            i++;
        }

Share this post


Link to post
Share on other sites

vec4 final;

 

isnt initialized so probably holds garbage, which you then add to. Plus Im not sure how you use the 4th component of final.

That was it. Some times you overlook the simplest things like that haha. That's kind of embarrassing. I do wonder why AMD let it complie and didn't even try and warn me about it though. I have all the error logging stuff on but the shader compiled without any actual errors.

 

 

 

Your code makes my eyes hurt smile.png

while(i < 3) {
final.xyz += (rot[i].xyz * weights[i]);
normal += (nor[i] * weights[i]);
i++;
}

 

Didn't know you could write it that way. Thanks. I'm sure I can clean things up like that in a few places.

Edited by newObjekt

Share this post


Link to post
Share on other sites

Yeah it's pretty amazing that both nVidia and AMD compiled without errors... Silently initializing to zero (nVidia) is just as bad as not initializing (AMD)...
I wonder if the Khronos GLSL reference compiler produces a warning/error?
On D3D I'm pretty sure an uninitialized variable will cause your shader to flat out fail to compile.
 
[edit] I just ran this test through the reference compiler, which should be the gold standard, the absolute truth:

void main()
{
  mediump vec4 result;// = vec4(0);
  gl_FragColor = result;
}

...and it happily compiles that code without warning you about the uninitialized variable...
 
With the initialization commented out, it produces

0:? Sequence
0:2  Function Definition: main( (void)
0:2    Function Parameters:
0:?     Sequence
0:5      move second child to first child (mediump 4-component vector of float)
0:5        'gl_FragColor' (fragColor mediump 4-component vector of float)
0:5        'result' (mediump 4-component vector of float)
0:?   Linker Objects

And with initialization it produces:

0:? Sequence
0:2  Function Definition: main( (void)
0:2    Function Parameters:
0:4    Sequence
0:4      Sequence
0:4        move second child to first child (mediump 4-component vector of float)
0:4          'result' (mediump 4-component vector of float)
0:4          Constant:
0:4            0.000000
0:4            0.000000
0:4            0.000000
0:4            0.000000
0:5      move second child to first child (mediump 4-component vector of float)
0:5        'gl_FragColor' (fragColor mediump 4-component vector of float)
0:5        'result' (mediump 4-component vector of float)
0:?   Linker Objects

What the hell GL, Y U NO ERROR?

 

[edit #2]

Scanning the spec, the only mention of uninitialized variables that I see is:

Global variables without storage qualifiers that are not initialized in their declaration or by the application will not be initialized by OpenGL, but rather will enter main() with undefined values.

So - uninitialized global variables are explicitly defined by the spec to have garbage values... but uninitialized local variables aren't even mentioned; they're not actually "undefined behavior", but instead they're just "unspecified"!

I assume this means that the vendors can do whatever the hell they want, and still be abiding by the specification... Why not do the right thing(tm)?

Edited by Hodgman

Share this post


Link to post
Share on other sites

It's the old "general rule of OpenGL drivers":

  • AMD doesn't do things it should, and,
  • NVIDIA does things it shouldn't.

In this case AMD should have given you a compiler error or warning, but didn't.  NVIDIA shouldn't have silently initialized, but did.  That, unfortunately, is the reality of the sorry state of OpenGL drivers in 2014.

Share this post


Link to post
Share on other sites


So - uninitialized global variables are explicitly defined by the spec to have garbage values... but uninitialized local variables aren't even mentioned;
Well, this is interesting. In the "Error Handling" section of GLSL 1.10 spec (this is OpenGL 2.0's GLSL) it says:

 

Compilers, in general, accept programs that are ill-formed, due to the impossibility of detecting all ill-formed programs. For example, completely accurate detection of use of an uninitialized variable is not possible.

 

Now, if you go to GLSL 1.20's spec (ie, OpenGL 2.1's GLSL), that sentence is removed. I'm guessing the OP is using GLSL 1.20 given the 'varying' and 'attribute' qualifiers.

Share this post


Link to post
Share on other sites

This topic is 1271 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this