Constants Exceeded

When I run a shader program I wrote on my ati card, I am informed that it will be funnitn in software since I exceeded the maximum number of constants.

What does this mean? Do constants mean my code is too long, or that I use to many variable? I only have 1 varying vec4 and 1 vec3 uniform.

Moreso, are any of these compiler/linker messages documented anywhere?

On ATI it could be many things but if you only use one variable, I can’t think what it could be. (using a lot of contants in code, too may uniforms?)

Post your shader here if you want a definite answer.

The warnings/errors are not standardized in the spec so they vary from vendor to vendor.

Its the lighting equation examples given from the “Traditional Shaders” chapter of the Orange book, but with the functions eliminated.

I realize that some of the stuff happening in the fragement shader could be moved to the vertex shader, and I plan on getting to that. I really more interested in what caused the “constants exceeded.”

Vertex Shader

varying vec4 normal;

void main(void) 
{
	normal = vec4(gl_NormalMatrix * gl_Normal,0.0);
	gl_Position    = ftransform();
}

Fragment Shader

uniform vec3 EyePos;

varying vec4 normal;

void main (void)
{
   float nDotVP;
   float nDotHV;
   float pf;
   float spotDot;
   float spotAttenuation;
   float attenuation;
   float d;
   vec4 VP;
   vec4 halfVector;
   vec4 amb;
   vec4 dif;
   vec4 spec;

   //Loop through lights
   for(int i = 0; i < gl_MaxLights; i++)
   {
   // Compute vect from surface to light position
   VP = gl_LightSource[i].position - vec4(0.0);

   // Compute distance between surfact and light position
   d = length(VP);

   // Normalize the vector from surface to light position
   VP = normalize(VP);

   // Compute attenuation
   attenuation = 1.0 / (gl_LightSource[i].constantAttenuation + gl_LightSource[i].linearAttenuation * d + gl_LightSource[i].quadraticAttenuation * d * d);

      if (gl_LightSource[i].position.w == 0.0)
   {
      //DirectionalLight(i,amb,dif,spec);
      nDotHV = max(0.0, dot(normal, gl_LightSource[i].halfVector));
      attenuation = 1.0;
   }
      else 
   {
      //PointLight(i,EyePos,amb,dif,spec);
      halfVector = normalize(VP + vec4(EyePos,1.0));

      nDotVP = max(0.0, dot(normal, VP));
      nDotHV = max(0.0, dot(normal, halfVector));

      if(gl_LightSource[i].spotCutoff < 180.0)
      {
         //SpotLight(i,EyePos,amb,dif,spec);
         // See if point on surface is inside cone of illumination
         spotDot = dot(-VP, vec4(gl_LightSource[i].spotDirection,0.0));

         if (spotDot < gl_LightSource[i].spotCosCutoff)
            spotAttenuation = 0.0;
         else
            spotAttenuation = pow(spotDot, gl_LightSource[i].spotExponent);
         attenuation *= spotAttenuation;
      }
   }

   if(nDotVP == 0.0)
      pf = 0.0;
   else
      pf = pow(nDotHV, gl_FrontMaterial.shininess);

   amb += gl_LightSource[i].ambient;
   dif += gl_LightSource[i].diffuse * nDotVP * attenuation;
   spec += gl_LightSource[i].specular * pf * attenuation;
   }

   gl_FragColor = gl_FrontMaterial.emission + gl_LightModel.ambient * gl_FrontMaterial.ambient + amb * gl_FrontMaterial.ambient + dif * gl_FrontMaterial.diffuse;
	gl_FragColor += spec * gl_FrontMaterial.specular * gl_FrontMaterial.shininess;
}

I suspect that I have to many variables. But I could be wrong.

You may only have specified one uniform, but don’t forget that all those built-in uniform states like gl_LightSource[] are constants as well. And the constant register set is much more limited on the fragment side than on the vertex side. You have 32 fragment shader constants on R300 and 64 on R420, compared to 192 and 256 IIRC on the vertex side. Since you’re looping over gl_MaxLights = 8 light sources that’s going to be quite a few constants. After a quick look into the code I can count to at least 7 constants per instance even when packing scalars optimally, so that adds up to 7 * 8 = 56, and that’s just for gl_LightSource alone.

Hi,
Even when you resolve your problem of exceeding constants limit in your shader program , you w’ld have to change your code so as not to use “for loop” as currently ATI cards do not support looping.

The loop is static so it should be fine.

Any idea on how to cut down on the constants?

I tried looking for something to move to the vertex shader, but I can’t think of anything.

Since ATI’s compiler unrolls static loops, would cutting down on the number of lights cut down on the number of constants used?

Yes. There are also parts of the shader that are static that you can move outside the shader. Like for instance this:

amb += gl_LightSource[i].ambient;

This variable is just summing up constants. You can sum it up yourself and pass as a regular uniform. That would save you 7 constants and probably 7 instructions or more as well.

Also, static if-statements like this,
if (gl_LightSource[i].position.w == 0.0)
can be replaced by #ifdef and then you can compile several different versions of the shader for the possible combinations. This should reduce the instruction count a lot and will cut down a bit on the constants as well. It requires a bit more handling from the application side but it’s fairly straightforward.

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