GLSL loop problem on Radeon HD cards?

I have a problem in my shaders on an ATI Radeon HD 5450 card (but I have reports from customers on other Radeon HD cards too, as well as one nVidia GeForce GT 330M).

It works fine on an ATI FirePro v3750 (and other cards) though.

It seems due to the loops I do in my code, because I tried to unroll them and it works fine.

I there some kind of limitation on loops with these cards?

My shader computes phong illumination for 4 lights, doing a loop on them.

Here’s an extract of the meaningful parts involving the loops:


uniform bvec4 LightsEnabled; // holds the booleans telling which lights are enabled

void main(void)
{
    vec4 finalColor;

    vec4 DiffuseColor[4];
    vec4 SpecularColor[4];
   
   for (int i = 0; i < 4; i++)
   {
        DiffuseColor[i] = vec4(0);
        SpecularColor[i] = vec4(0);

        if (LightsEnabled[i])
        {
            DirectionalLight(i, normal, amb, DiffuseColor[i], SpecularColor[i]);
       
            DiffuseColor[i]  *=  materialDiffuse;

            finalColor += DiffuseColor[i];

        }

   }
 
   gl_FragColor = finalColor;

Your problem is likely here:

if (LightsEnabled[i])

The spec says that this is possible, but it’s one of those outside cases that I would look dimly at. Just use a bool[4] array instead of a bvec4.

Also, this is a poorly written shader. It can be rewritten as this:


   for (int i = 0; i < 4; i++)
   {
     vec4 diffuseLightIntensity;
     vec4 specularLightIntensity

     if (LightsEnabled[i])
     {
        DirectionalLight(i, normal, amb, diffuseLightIntensity, specularLightIntensity);
       
        finalColor += diffuseLightIntensity * materialDiffuse;
     }
   }

No need for arrays of those values; just overwrite the old ones. Nor is there a need to initialize them with 0; DirectionalLight should be outputting to those variables, so it should initialize them.

Thank you Alfonse,

but why is the use of bool[4] different from using a bvec4?

The difference is that most people do not access a vector using [] with non-compile-time values. This means that, while GLSL says that this should be possible, drivers don’t see this case often. So there can be bugs in it, much like the one you ran into.

The majority of uses of arrays do use them with non-compile time values, in looping structures and such. Your use case is common for arrays, so drivers will have seen that case fairly often. And therefore, they’re less likely to be broken.

Hi Alfonse,

I have another problematic piece of code that works on some cards but not on others:


    const int NumberOfSplits = 4;
    varying vec4  ShadowCoord[NumberOfSplits]; 
    uniform float SplitDepths[NumberOfSplits];

...

    vec4 coord;

    for (int i = 0; i < NumberOfSplits; i++)
    {                
        if (vertexDepth > SplitDepths[i])
        {
            coord = ShadowCoord[i];
            break;
        }
    }

if I unroll it like this it works in all cards (or at least in those that I tested):


    vec4 coord;

    for (int i = 0; i < NumberOfSplits; i++)
    {                
        if (vertexDepth > SplitDepths[i])
        {
            if (i==0)         
                coord = ShadowCoord[0];
            else if (i==1)
                coord = ShadowCoord[1];
            else if (i==2)
                coord = ShadowCoord[2];
            else
                coord = ShadowCoord[3];

            break;
        }

    }

Am I doing something wrong in the first case, with


            coord = ShadowCoord[i];

?

Thanks

What do you expect me or anyone else to do about it? Or anyone else? It’s a driver bug.

You have two alternatives:

1: Live with these bugs and continue to create workarounds for them until they get fixed.

2: Stop using varying arrays and other things.

These are your options. If you want your code to work everywhere without workarounds, then you’re going to have to stop doing these unusual things like this. Yeah, it’s not fair, it should work, but that’s life.

I didn’t know using a varying array was an unusual thing.

Where can I find a list of all these unusual things, so I can start writing better shaders code?

Thanks for your time.