Issue about accessing array element of uniform block (AMD glsl compiler)

I have encountered an issue about accessing array element of uniform block, the follow code can demonstrate this issue:


struct SLightSource {
    vec3 color1;
    vec3 color2;
};

layout(std140) uniform LightSourcesBlock {
    SLightSource lightSources[32];
};

vec3 CalcLightColor(const in SLightSource lightSource)
{
    return lightSource.color1 + lightSource.color2;
}

uniform int lightCount;
out vec4 fragColor;

void main()
{
    vec3 lightColor = vec3(0, 0, 0);
    for (int i = 0; i < lightCount; i++)
        lightColor += CalcLightColor(lightSources[i]);

    fragColor = vec4(lightColor, 1);
}

The Above code is very simple but it is enough to demonstrate this issue. Suppose the array in uniform block has been initialized with uniform buffer object: lightSources[0].color1 = (0.25, 0.25, 0.25), lightSources[0].color2 = (0.25, 0.25, 0.25),lightSources[1].color1 = (0.25, 0.25, 0.25),lightSources[1].color2 = (0.25, 0.25, 0.25), and the uniform lightCount is set to 2;
Run the program and the expected output color should be (1, 1, 1). In nVidia video card the output color is OK, but if I run this code in AMD video card the result will be (0.5, 0.5, 0.5), (I have an AMD Radeon HD 7770 card with Catalyst 13.1 driver)
I seems that the uniform value of the second array element in the uniform block is zero when the program evalulate their value. I have checked that both lightSources[1].color1 and lightSources[1].color2 are active uniform after the program is linked.
But if I change the light calcaultion code as follow the output color will be correct:

void main()
{
    vec3 lightColor = vec3(0, 0, 0);
    lightColor += CalcLightColor(lightSources[0]);
    lightColor += CalcLightColor(lightSources[1]);
    fragColor = vec4(lightColor, 1);
}

It looks like that when I access array element by a constant number as its index every thing is fine, but if I use a variable as the array index some strange thing will happen. So is this a feature of GLSL language I have not fully understand or  a bug in AMD GLSL compiler?

How are you loading the structure? std140 says that that vec3 will be padded to a vec4. (http://www.opengl-redbook.com/appendices/AppL.pdf)

I can assure that my uniform buffer layout is correct, since I have query the uniform offset by glGetActiveUniformsiv(), and the result coincides with the layout of my uniform buffer layout. And of course vec3 has a base alignment of 16 bytes, this is described in openGL specification, I obey the spec strictly :-)

I do not know if this is really the issue, but take a look here:
http://www.opengl.org/discussion_boards/showthread.php/166933-ATI-problem-with-GLSL-arrays

On older (ATI)-Cards using non-constants as array-index resulted in a compile-time error. Maybe you have to use a
#version xxx
statement before you can use non-const indices (I do not have Access to newer ati-hardware right now so i cannot test this).

in AMD ShaderAnalyzer, this shader doesn’t even compile. for some reason it doesn’t like you declaring uniform block of struct. i don’t actually have experience with uniform blocks, so i couldn’t fix it; but it does compile that way:

layout (std140) uniform LightSourcesBlock {
    vec3 color1[32];
    vec3 color2[32];
};

vec3 CalcLightColor(const in vec3 c1, const in vec3 c2) {
    return c1 + c2;
}
 
uniform int lightCount;
out vec4 fragColor;
 
void main() {
    vec3 lightColor = vec3(0, 0, 0);
    for (int i = 0; i < lightCount; i++) {
        lightColor += CalcLightColor(color1[i], color2[i]);
    }
    fragColor = vec4(lightColor, 1);
}

can you check if it produces correct result on AMD card? this is my obsessive fear with GLSL - AMD Compiler, especially with arrays. so i’m quite invested in making sure it’s not a new AMD “feature”.

[QUOTE=hlewin;1247565]I do not know if this is really the issue, but take a look here:

On older (ATI)-Cards using non-constants as array-index resulted in a compile-time error. Maybe you have to use a
#version xxx
statement before you can use non-const indices (I do not have Access to newer ati-hardware right now so i cannot test this).[/QUOTE]

In fact, I put a "#version 150" line in the shader since I use OpenGL 3.2 core profile (I fogot to mention this in my first post), the shader compile with no error, but the result is what I have described before. Do you know from which version of GLSL language non-constant array index is allowed ? thanks.

According to Data Type (GLSL) - OpenGL Wiki

Arrays can be accessed with arbitrary numeric expressions. They do not have to be compile-time constants (though there are a few exceptions to this rule; for example, the very next section).

They are valid from 4.00 for opaque types.

Do you know from which version of GLSL language non-constant array index is allowed ?

All of them. At least, for arrays of regular values. GLSL 1.10 allowed this.

I’d guess that this is a driver bug. Try using vec4’s instead of vec3’s; it’s best not to confuse AMD drivers…

They are valid from 4.00 for opaque types.

Point of order: as stated in “the very next section”, they aren’t. Only Dynamically Uniform Expressions can be used with opaque types.

But that’s irrelevant, since he isn’t using an opaque type here.

Do you know from which version of GLSL language non-constant array index is allowed ? thanks.

All of them. At least, for arrays of regular values. GLSL 1.10 allowed this. I’d guess that this is a driver bug. Try using vec4’s instead of vec3’s; it’s best not to confuse AMD drivers…

That’s true from reading the spec - yes. I’ve an old Laptop with a Radeon-mobility where I got the compile-time Errors. As I said I do not know for newer Cards. It was just a thought that the Compiler might treat sources different depending on what Version is requested. I’d try to specify the highest Version and test if it works and then decrease the version-number. Otherwise I would not really know how to handle this.
On the old Laptop i used to roll out Loops by Hand to enable accessing the Array.
#define LOOP(x) CallFunction(ArrayValue, AnOtherArray)
LOOP(0); LOOP(1); LOOP(2)…
Of course this is ridiculous so I would have expected that this behaviour is fixed for newer Cards/newer drivers.
If you try out please post the results here as I’m quite interested in the results.

I thought his index is Dynamically Uniform Expressions since lightCount is a Dynamically Uniform Expressions?

[QUOTE=Alfonse Reinheart;1247589]All of them. At least, for arrays of regular values. GLSL 1.10 allowed this.

I’d guess that this is a driver bug. Try using vec4’s instead of vec3’s; it’s best not to confuse AMD drivers…

Point of order: as stated in “the very next section”, they aren’t. Only Dynamically Uniform Expressions can be used with opaque types.

But that’s irrelevant, since he isn’t using an opaque type here.[/QUOTE]

You are right, after changing vec3 to vec4 everything works fine. Thank you for the suggestion!

What you originally quoted was, “Arrays can be accessed with arbitrary numeric expressions. They do not have to be compile-time constants (though there are a few exceptions to this rule; for example, the very next section).” Then you said, “They are valid from 4.00 for opaque types.”

Your original statement said nothing about expressions being dynamically uniform. Your statement was misleading, suggesting that “arbitrary numeric expressions” are “valid from 4.00 for opaque types.” I just wanted to clear that up in case anyone got the wrong idea.

Yes, in his example, his loop is dynamically uniform. But he’s not using an opaque type, so that’s irrelevant: arbitrary numeric expressions should work on non-opaque types, regardless of GL version.

[QUOTE=Alfonse Reinheart;1247638]What you originally quoted was, “Arrays can be accessed with arbitrary numeric expressions. They do not have to be compile-time constants (though there are a few exceptions to this rule; for example, the very next section).” Then you said, “They are valid from 4.00 for opaque types.”

Your original statement said nothing about expressions being dynamically uniform. Your statement was misleading, suggesting that “arbitrary numeric expressions” are “valid from 4.00 for opaque types.” I just wanted to clear that up in case anyone got the wrong idea.

Yes, in his example, his loop is dynamically uniform. But he’s not using an opaque type, so that’s irrelevant: arbitrary numeric expressions should work on non-opaque types, regardless of GL version.[/QUOTE]

OK I understand

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