NVidia: OK, ATI X1650: OK, ATI 2600: Oh hell!

I wrote my shaders with an Nvidia card, and users have tested on a number of these cards without incident. There was a problem on some old ATI cards, so I tested with one, made some minor changes, and it ran fine.

Then I tried testing with an ATI 2600. Literally every shader I have run, even simple ones that blend two textures, are completely broken. I mean, it is to the point where I just want to tell everyone “screw ATI, their stuff doesn’t work”. I mean, this is bad. So bad, and maddening because everything runs fine on their older card/driver. And everything compiles fine!

Have you guys experienced anything like this?

Do you want to post some of these broken shaders for us to look at? Do the ATI driver report any problems when compiling - or is it only runtime issues?

Can you post a link to your app?

It’s hard because I use defines to create a bunch of different shaders out of just a couple of files.

But everything compiles fine. So I don’t even know where to start.

This is my main vert and frag shader files:

main.vert:

//uniform vec4 mappingaxes[2];
//uniform vec2 mappingscale;
varying vec3 T,B,N;
varying vec3 ModelVertex;
varying vec3 EyeVec;
varying vec3 BumpVector;

uniform float distancefade;

float BumpAvg;

#ifdef LW_LIGHTS

void light(in int i, in vec3 normal, in vec3 ecPosition3)
{
	float nDotVP;       // normal . light direction
	float attenuation;  // computed attenuation factor
	float d;            // distance from surface to light source
	vec3  VP;           // direction from surface to light position
	float spotDot;

	// Compute vector from surface to light position
	VP = vec3 (gl_LightSource[i].position) - ecPosition3;
	
	// Compute distance between surface and light position
	d = length(VP);
	attenuation = clamp( 1.0-(d/gl_LightSource[i].linearAttenuation), 0.0, 1.0 );
	
	// Normalize the vector from surface to light position
	VP = normalize(VP);
	
	#ifdef LW_BUMPMAP
		nDotVP =1.0;
	#else
		nDotVP = max(0.0, dot(normal, VP));
	#endif
	
	// Spot attenuation
	spotDot = dot( -VP, gl_LightSource[i].spotDirection);
        if (spotDot < gl_LightSource[i].spotCosCutoff)
        {
	    attenuation = 0.0;
        }

	float spotAttenuation = min( 1.0 - (spotDot - gl_LightSource[i].spotExponent) / (gl_LightSource[i].spotCosCutoff - gl_LightSource[i].spotExponent) ,1.0);
	if (gl_LightSource[i].spotCutoff==180.0)
	{
		spotAttenuation=1.0;
	}
	attenuation *= spotAttenuation;

	// Point & spot lights
	gl_FrontColor += 2.0 * gl_LightSource[i].diffuse * nDotVP * attenuation * gl_LightSource[i].position.w;
	
	#ifdef LW_BUMPMAP
		float bumpcontributor;
		bumpcontributor = attenuation * gl_LightSource[i].diffuse.w;
		BumpVector += (VP * gl_LightSource[i].position.w * bumpcontributor);
	#endif
	
	// Directional lights
	gl_FrontColor += 2.0 * gl_LightSource[i].diffuse * max(0.0, dot( normal, vec3( gl_LightSource[i].position ) )) * (1.0-gl_LightSource[i].position.w);
	
	#ifdef LW_BUMPMAP
		BumpVector += (vec3( gl_LightSource[i].position ) * (1.0 - gl_LightSource[i].position.w));
		BumpAvg += (1.0 - gl_LightSource[i].position.w);
	#endif
}

#endif


void main(void) {
	
	gl_FrontColor=gl_Color;
	float alpha = gl_Color.w * distancefade;
	gl_Position = ftransform();
	
	//======================================
	// Texcoords
	//======================================
	//#ifdef LW_BASETEXTURE
		gl_TexCoord[0]=gl_MultiTexCoord0;// + gl_ObjectPlaneS[0];
		gl_TexCoord[2]=gl_MultiTexCoord0;// + gl_ObjectPlaneT[0];
		
		//======================================
		// Auto-generated texcoords for brushes
		//======================================
		//#ifdef LW_BRUSHTEXCOORDS
		//	gl_TexCoord[0].s=(( gl_Vertex.x*mappingaxes[0].x + gl_Vertex.y*mappingaxes[0].y + gl_Vertex.z*mappingaxes[0].z + mappingaxes[0].w ) * mappingscale.x);
		//	gl_TexCoord[0].t=(( gl_Vertex.x*mappingaxes[1].x + gl_Vertex.y*mappingaxes[1].y + gl_Vertex.z*mappingaxes[1].z + mappingaxes[1].w ) * mappingscale.y);
		
	//#endif
	
	
	//======================================
	// Lightmap texcoords
	//======================================
	#ifdef LW_LIGHTMAP
		gl_TexCoord[1]=gl_MultiTexCoord1;
	#endif
	
	
	//======================================
	// TBN matrix
	//======================================
	#ifdef LW_BUMPMAP
		T = normalize(gl_NormalMatrix * gl_MultiTexCoord3.xyz);		
		B = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz);
		
		ModelVertex = (gl_ModelViewMatrix * gl_Vertex).xyz;
		#ifdef LW_PARALLAX
			EyeVec = vec3(dot(T,-ModelVertex), dot(B,-ModelVertex), dot(N,-ModelVertex));
		#endif
	#endif
	N = normalize(gl_NormalMatrix * gl_Normal);
	
	//======================================
	// Enable clip planes (only on NVidia cards)
	//======================================
	#ifdef __GLSL_CG_DATA_TYPES
		gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
	#endif
	
	
	//======================================
	// Fog effect
	//======================================	
	gl_FogFragCoord = max(-( gl_ModelViewMatrix * gl_Vertex ).z,0.0);
	
	
	//======================================
	// Cubemap
	//======================================
	#ifdef LW_CUBEMAP
		vec3 cubecoord;
	//	vec3 cubecoord = transpose(mat3(gl_TextureMatrix[1][0].xyz,gl_TextureMatrix[1][1].xyz,-gl_TextureMatrix[1][2].xyz)) * vec3(gl_ModelViewMatrix * gl_Vertex );


		cubecoord = vec3(gl_ModelViewMatrix * gl_Vertex ) * mat3(gl_TextureMatrix[1][0].xyz,gl_TextureMatrix[1][1].xyz,-gl_TextureMatrix[1][2].xyz);


		cubecoord.y *= -1.0;


	//	
	//	// Reflection
	//	vec3 normal =  transpose(mat3(gl_TextureMatrix[1][0].xyz,gl_TextureMatrix[1][1].xyz,-gl_TextureMatrix[1][2].xyz)) * gl_NormalMatrix * gl_Normal;

		vec3 normal = gl_NormalMatrix * gl_Normal * mat3(gl_TextureMatrix[1][0].xyz,gl_TextureMatrix[1][1].xyz,-gl_TextureMatrix[1][2].xyz);


		cubecoord = reflect( cubecoord , normalize(normal) );
		gl_TexCoord[3] =vec4( cubecoord.x, cubecoord.y, cubecoord.z, 1.0 );
	#endif
	

	//======================================
	// Lights
	//======================================
	#ifdef LW_LIGHTS

		#ifdef LW_BUMPMAP
			BumpVector = vec3(0.0,0.0,0.0);
			BumpAvg = 0.0;
		#endif

		int i;
		vec3 ecPosition3;
		vec4 ecPosition;
		vec3 lnormal;

		lnormal = normalize(gl_NormalMatrix * gl_Normal);
		ecPosition = gl_ModelViewMatrix * gl_Vertex;
		ecPosition3 = (ecPosition.xyz) / ecPosition.w;

		gl_FrontColor = vec4(0.0,0.0,0.0,1.0);
		for(i = 0; i < LW_LIGHTS; i++){
			light(i,lnormal,ecPosition3);
		}
		
		#ifdef LW_BUMPMAP
			BumpVector = normalize(BumpVector);//( BumpVector / BumpAvg );
		#endif
	#else
		// Static lighting bumpvector
		#ifdef LW_BUMPMAP
			BumpVector = gl_MultiTexCoord1.xyz;
		#endif		
	#endif
	
	gl_FrontColor.w = alpha;
	}

main.frag:

#ifdef LW_BASETEXTURE
	uniform sampler2D basetexture;
#endif

#ifdef LW_LIGHTMAP
	uniform sampler2D lightmap;
#endif

#ifdef LW_BUMPMAP
	uniform sampler2D bumpmap;
#endif

#ifdef LW_TEXTURE2
	uniform sampler2D texture2;
#endif

#ifdef LW_CUBEMAP
	uniform samplerCube cubemap;
#endif

uniform sampler2D radiositymap;
uniform vec4 AmbientLight;
varying vec3 T,B,N;
varying vec3 ModelVertex;
varying vec3 EyeVec;
varying vec3 BumpVector;

void main(void) {
	
	vec2 basetexcoord;
	vec4 lightcolor;
	vec4 bumpcolor;
	float alpha;
	vec3 lightdir;
	vec3 normal;	
	vec4 basecolor;	
	float specular=0.0;	
	vec2 coord;
	
	alpha=gl_Color.w;
	basetexcoord=gl_TexCoord[0].xy;
	
	//======================================
	// Parallax Mapping
	//======================================
	#ifdef LW_PARALLAX
		//if (gl_FragCoord.z<0.99) {
			basetexcoord += (texture2D(basetexture,basetexcoord).a * 0.04 - 0.036) * normalize(EyeVec).xy;
		//}
	#endif
	
	
	//======================================	
	// Light color
	//======================================
	#ifdef LW_LIGHTMAP
		coord=gl_TexCoord[1].xy;
		lightcolor = texture2D(lightmap,coord) * 2.0;
	#else
		lightcolor = gl_Color * 1.0;
	#endif
	
	
	//======================================
	// Bumpmap
	//======================================	
	#ifdef LW_BUMPMAP
		#ifdef LW_LIGHTMAP
			lightdir = gl_NormalMatrix * ( ( texture2D(radiositymap,gl_TexCoord[1].xy).xyz - 0.5 ));
		#else
			#ifdef LW_LIGHTS
				lightdir = BumpVector;			
			#else	
				lightdir = gl_NormalMatrix * ((BumpVector-0.5)*2.0);
			#endif
		#endif
		bumpcolor = texture2D(bumpmap,basetexcoord);	
		vec3 halfvec = normalize(normalize(lightdir) + normalize(-ModelVertex));	
		normal = normalize(bumpcolor.xyz - 0.5);
		normal = T * normal.x + B * normal.y + N * normal.z;
		lightcolor = lightcolor * clamp(dot(normal,lightdir),0.0,1.0) * 2.0;
		specular = pow(max(0.0, dot(halfvec,normal)),8.0) * bumpcolor.w * 0.5;
		#ifdef LW_EMBM
			specular = 0.0;
		#endif
	#else
		normal = N;
	#endif
	
	
	//======================================
	// Base color
	//======================================	
	#ifdef LW_BASETEXTURE
		basecolor = texture2D(basetexture,basetexcoord);
		alpha *= basecolor.w;
		//basecolor=vec4(0.5,0.5,0.5,basecolor.w);
	#else
		basecolor=vec4(0.5);
	#endif

	
	//======================================
	// Mix base and light colors
	//======================================
	gl_FragColor = basecolor * lightcolor;
	#ifdef LW_BUMPMAP
		gl_FragColor += specular * lightcolor;
	#endif
	gl_FragColor += basecolor * AmbientLight;
	
	
	//======================================
	// Add cube reflection
	//======================================
	#ifdef LW_CUBEMAP
		#ifdef LW_EMBM		
			vec3 cubecoord = gl_TexCoord[3].xyz;			
			normal *= gl_NormalMatrix;
			cubecoord += vec3(normal.x,-normal.y,-normal.z) * 200.0;
			gl_FragColor = gl_FragColor * alpha + textureCube( cubemap,cubecoord * vec3(1,1,-1) ) * (1.0 - basecolor.w);
		#else
			gl_FragColor = gl_FragColor * alpha + textureCube( cubemap,gl_TexCoord[3].xyz * vec3(1,1,-1) ) * (1.0 - basecolor.w);
		#endif
	#endif
	
	
	//======================================
	// Second Texture
	//======================================
	#ifdef LW_TEXTURE2
		coord = gl_TexCoord[0].xy;
		gl_FragColor += texture2D(texture2,coord );
	#endif
	
	
	//======================================
	// Fog effect
	//======================================	
	float fogeffect = clamp( 1.0 - (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale , 0.0, 1.0 ) * gl_Fog.color.w;
	gl_FragColor = 	gl_FragColor * (1.0 - fogeffect) + gl_Fog.color * fogeffect;
	
	
	//======================================
	// Restore alpha
	//======================================
	gl_FragColor.w=alpha;

	//gl_FragColor = vec4(BumpVector.x*0.5+0.5,BumpVector.y*0.5+0.5,BumpVector.z*0.5+0.5,1.0);
	//gl_FragColor = vec4(normal.x*0.5+0.5,normal.y*0.5+0.5,normal.z*0.5+0.5,1.0);
	
}

http://www.leadwerks.com/post/atitest.zip

Nothing works with this card:

You might want to fix all the OpenGL bugs in the app first before blaming ATI.

I just ran GLIntercept on it and had tons of errors:

GL ERROR - Function glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,-1.000000) generated error GL_INVALID_VALUE
GL ERROR - Function glPushMatrix() generated error GL_STACK_OVERFLOW

These were repeated over and over…

I’ll fix those, but I really don’t think those things will have any effect. A stack overflow doesn’t really matter. And the other one is just from setting a light parameter out of the allowed range.

I uploaded a new version that fixes all GL errors, same link as above, but the appearance is the same. At first I thought that validation error was a problem, but that just happens automatically when the shader is linked. I tried validating the shader after the cubemap sampler uniform had been defined, and it didn’t report any errors.

Here’s what it should look like. There’s some EMBM on the walls and floor, but it is hard to see in a still shot because the scene is not very high contrast:

Probably not your problem, but it is curious that the 3Dlabs shader validator fails on your shaders.
It does not seem to handle your nested #ifdefs too well (not that I can see anything wrong with your code)

AFAIK ATI uses the same open source parser for GLSL as the 3DLabs GLSLValitade tool. So if you can get your shaders to properly compile with GLSLValidate they should also work for ATI. AFAIK the only shortcomming with this tool is that it does not support GLSL 1.2.

[ www.trenki.net | vector_math (3d math library) | software renderer ]

I tested on a 9700 with Cat 7.8
Graphically, it looked correct.
The GLintercept error log shows 200 lines of errors.


GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
GL ERROR - Function glGenerateMipmapEXT generated error GL_INVALID_OPERATION
ShaderGLSLManager::Destructor - OpenGL id 536870913 is still active. (ShaderGLSL Memory leak?)
ShaderGLSLManager::Destructor - OpenGL id 536870914 is still active. (ShaderGLSL Memory leak?)
ShaderGLSLManager::Destructor - OpenGL id 536870915 is still active. (ShaderGLSL Memory leak?)
ShaderGLSLManager::Destructor - OpenGL id 536870916 is still active. (ShaderGLSL Memory leak?)
ShaderGLSLManager::Destructor - OpenGL id 536870917 is still active. (ShaderGLSL Memory leak?)
ShaderGLSLManager::Destructor - OpenGL id 536870918 is still active. (ShaderGLSL Memory leak?)
ShaderGLSLManager::Destructor - OpenGL id 536870919 is still active. (ShaderGLSL Memory leak?)
ShaderGLSLManager::Destructor - OpenGL id 536870920 is still active. (ShaderGLSL Memory leak?)
ShaderGLSLManager::Destructor - OpenGL id 536870921 is still active. (ShaderGLSL Memory leak?)
ShaderGLSLManager::Destructor - OpenGL id 536870922 is still active. (ShaderGLSL Memory leak?)
ShaderGLSLManager::Destructor - OpenGL id 536870923 is still active. (ShaderGLSL Memory leak?)


I don’t think 3DLabs’ GLSLValidate supports defines. The GPU itself compiles them just fine. See the program log file. The validation warning is simply a warning saying that the cubemap sampler has the same value as some 2D samplers, because it was just compiled and hasn’t been set yet.

Strange that the 9700 would give errors the newer cards do not. Yet the 9700 appears graphically correct.

I am in driver hell.

Welcome aboard, can I offer you a drink ?

OK, I know it doesn’t much, but it’s always good to know you’re not alone ! I’ve still to manage to do something with the X2600 test board I have… anyway, good luck !

I requested an ATI developer account 2 days ago, but have not heard back. So that’s it? All that work just to find out that ATI is lying when they say they support OpenGL, and that the company might as well be a front for Microsoft, for all the damage they’re doing to OpenGL and PC gaming?

I requested an ATI developer account 2 days ago, but have not heard back.

That’s fairly normal. It takes longer than 2 days.

and that the company might as well be a front for Microsoft, for all the damage they’re doing to OpenGL and PC gaming?

Accusing ATi of not really supporting OpenGL is fairly reasonable, considering that their implementation is, despite a recent total rewrite, still about as buggy as it gets. Accusing them of being a Microsoft front because of it is silly; it makes more sense to assume that they simply don’t care, or don’t want to put the effort into making a functional implementation.

I suggested they might as well be for the effect they are having. Obviously they are not. But this is bad.

ATI=maybe 50% of PC users. 100% of Mac users.

So this immediately cuts the PC market in half, and eliminates OpenGL’s cross-platform advantage with Apple, at least for anything more than simple FFP stuff.

For the record, and not to diminish the essence of your gripe, but not all macs use ATI.

eliminates OpenGL’s cross-platform advantage with Apple

I believe that ATi’s Mac drivers are actually quite functional.

FWIW, according to this post this post, Apple OpenGL implementation is quite different of the PC jungle :

On the PC, vendors are basically responsible for the whole GL stack; ATI and NVidia have large and hefty implementations of OpenGL that they maintain internally, chocked neck-deep with caveats, gotchas, bugs, and features that the other doesn’t have; there’s very little in the way of “common” implementation between them.

(…)

Apple’s got a different implementation; Apple remains responsible for the majority of the GL implementation, introducing commonality, the shared texture memory environment, and implementing software support for features not implemented by specific hardware; it then provides a set of low-level driver points where hardware manufacturers can polish and shine their implementation.

That explain things… Moreover OpenGL on a Mac is much more central to graphics rendering in general, and has much more importance than on a PC.

If I were you, I would try to find out where the problem is instead of waiting for ATI for fix the issue.
I’m sure there is some uniform or temporary that is filled with zeroes and just not getting updated.
It can be very difficult to track these down.

Where did you get the idea that all Mac users have ATI cards?
Todays Macs are basically PCs with a different BIOS.