Strange link problem on some GeForce 8800's

I’ve been running this shader on:
Radeon X850, GeForce 6/7, GeForce 8800 GTS.

Now one of my testers reported a problem on his 8800 GTS.

I get link error, but no information about the reason from the driver. I only have log file. I can’t experiment with the GPU/driver itself, but my game reported linker errors properly so far, so for now I assume it’s the driver that’s not telling me why it failed.
Maybe I’m missing some knowledge here. I will check it with GLSLValidate a bit later.

For now, maybe someone can help.

Vertex shader:


#ifndef __GLSL_CG_DATA_TYPES
#define hfloat float
#define hvec2 vec2
#define hvec3 vec3
#define hvec4 vec4
#else
#define hfloat half
#define hvec2 half2
#define hvec3 half3
#define hvec4 half4
#endif

varying hvec4 eyeVec;
varying hvec4 zenithVec;
varying hvec4 lightVec;
varying hfloat fog;

void main( void )
{
  hvec3 normal;
  hvec3 tangent;
  hvec3 binormal;

  gl_Position = ftransform();
#ifdef __GLSL_CG_DATA_TYPES
  gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
#endif
  vec2 tc = (gl_Vertex.xz + gl_MultiTexCoord0.zw) * hvec2(0.01, 0.01);
  gl_TexCoord[0].xy = tc * 0.024414;
  gl_TexCoord[0].zw = tc * 5;
  gl_TexCoord[1].xy = tc * 0.2;

  normal.xyz    = (gl_ModelViewMatrix * hvec4(gl_Normal.x, gl_Normal.y, gl_Normal.z, 0.0)).xyz;
  normal = normalize(normal);
  tangent.xyz   = (gl_ModelViewMatrix * hvec4(1.0, 0.0, 0.0, 0.0)).xyz;
  binormal.xyz = (gl_ModelViewMatrix * hvec4(0.0, 0.0, 1.0, 0.0)).xyz;
  tangent = tangent - normal * dot(tangent, normal);
  binormal = binormal - normal * dot(binormal, normal);

  eyeVec.xyz = (gl_ModelViewMatrix * gl_Vertex).xyz;
  eyeVec.xyz = hvec3(dot(eyeVec.xyz,tangent), dot(eyeVec.xyz,binormal), dot(eyeVec.xyz,normal));
  /* alt */
  eyeVec.w = gl_Vertex.y;

  lightVec.xyz = normalize(gl_LightSource[0].position.xyz);
  lightVec.xyz = hvec3(dot(lightVec.xyz,tangent), dot(lightVec.xyz,binormal), dot(lightVec.xyz,normal));
  /* eye alt */
  lightVec.w = dot ( (gl_ModelViewMatrix * hvec4(0.0, 1.0, 0.0, 0.0)).xyz,
                     (gl_ModelViewMatrix * hvec4(0.0, 0.0, 0.0, 1.0)).xyz );

  zenithVec.xyz = (gl_ModelViewMatrix * hvec4(0.0, 1.0, 0.0, 0.0)).xyz;
  zenithVec.xyz = hvec3(dot(zenithVec.xyz,tangent), dot(zenithVec.xyz,binormal), dot(zenithVec.xyz,normal));
  zenithVec.w = gl_Vertex.y;

  hfloat depth = max(-eyeVec.w, 1.0);
  hfloat f_dist = length(eyeVec.xyz);
  fog = f_dist * ((depth) / (depth - lightVec.w));
  fog = clamp(pow(fog * 0.03, 0.5), 0.0, 1.0);
}

Fragment shader:


#ifndef __GLSL_CG_DATA_TYPES
#define hfloat float
#define hvec2 vec2
#define hvec3 vec3
#define hvec4 vec4
#else
#define hfloat half
#define hvec2 half2
#define hvec3 half3
#define hvec4 half4
#endif

uniform sampler2D texNormal;
uniform sampler2D texMap;
uniform sampler2D texReef;
uniform float brightness;

varying hvec4 eyeVec;
varying hvec4 zenithVec;
varying hvec4 lightVec;
varying hfloat fog;

void main( void )
{
  if (eyeVec.w > 0.8) discard;

  hvec3 eyeVec2 = normalize(eyeVec.xyz);
  hvec3 lightVec2 = normalize(lightVec.xyz);

  hvec3 v_normal = texture2D(texMap, gl_TexCoord[0].xy).rgb - hvec3(0.5, 0.5, 0.5);
  hfloat shadow = length(v_normal) * 2.0;
  v_normal =   texture2D(texNormal, gl_TexCoord[0].zw).rgb - hvec3(0.5, 0.5, 0.5)
             + v_normal;
  v_normal = normalize(v_normal);

  hvec4 color = texture2D(texReef, gl_TexCoord[0].zw).rgba;
  hfloat reef = smoothstep(3.0, 3.2, texture2D(texNormal, gl_TexCoord[1].xy).r * 4.0 - eyeVec.w * 0.5);
  reef *= color.a;

  color.rgb = mix(hvec3(1.0, 0.9, 0.6), color.rgb, reef);

  color.rgb = color.rgb * clamp(dot(v_normal, lightVec2) + 0.2, 0.2, 1.0) * shadow;

  gl_FragColor.rgb = mix(color.rgb, hvec3(0.0, 0.3, 0.1), fog) * brightness;
}

This is terrain shader for underwater refraction rendering. All terrain shaders in my game fail to link on that machine. All other shaders seem fine.

Some additional clues:
GL_VENDOR: NVIDIA Corporation
GL_RENDERER: GeForce 8800 GTS/PCI/SSE2
GL_VERSION: 2.1.2

I mix general attributes with fixed function attributes but I do not bind general attributes to fixed location before linking - I’m always retrieving attribute location after linking.

I use half types to pass varying variables but I do that in other shaders and they compile just fine.

Both shaders “compile” (glCompileShader) just fine, it’s the glLinkProgram that reports a failure.

At first glance it looks like driver bug. I remember pulling my hair out, trying to figure out the cause for ATI drivers not to link one of shaders (same as here - no error message from driver). It turned out I had 8 varying variables + glFragCoord = 9 varying variables (8 supported).

Anyone finds something suspicious about these shaders?

Thanks in advance for any clues.

At first sight, I don’t see anything wrong with the shaders but I wouldn’t be surprised if the strange linking behaviour is caused by the discard statement… don’t know why but it happened to me a few times.

N.

Here’s some advice for determining why a GLSL program might have failed on NVIDIA hardware.

You can download the free Cg Toolkit and use the cgc (cgc.exe for Windows) compiler to compile your GLSL code so you can see the actual generated assembly.

For example, if you save your vertex shader as v.glsl, you can run:

cgc -oglsl -strict -D__GLSL_CG_DATA_TYPES -profile vp40 v.glsl

Here’s what the options mean:

  • -oglsl means use the OpenGL GLSL language front-end (instead of the default being Cg)

  • -strict means warn about GLSL extensions

  • -D__GLSL_CG_DATA_TYPES mimics the OpenGL driver’s default to define to indicate half-precision and fixed-point numeric types are available (only provides these data types in fragment profiles)

  • -profile vp40 means choose the GeForce 6/7 vertex profile. Use fp40 for the matching fragment profile. You can use gp4vp and gp4fp (and gp4gp for geometry) for GeForce 8. You can also use vp30, fp30, arbfp1, and arbvp1. The profile decides what target GPU (and OpenGL extension) you want to generate code for.

The output assembly spews to stdout and you can inspect it for problems.

I’m not sure this will help in this particular case. I ran your GLSL source text through the Cg 2.0 compiler and didn’t see any problems but I didn’t inspect the assembly to carefully.

Using the Cg compiler this way is even more useful for observing the performance of your GLSL shaders. You can compare one version of the shader to another this way.

You can get Cg Toolkit 2.0 from:

http://developer.nvidia.com/object/cg_toolkit.html

I hope this helps.

  • Mark

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.