Uniform array offset (ATI bug?)

I have encoutered what is most likely a bug in ATI’s driver.

If you have a vertex shader with the line

vec3 someUniformArray[2];

then calling glUniformLocationARB( program, “someUniformArray[0]” ) should point to the first vec3 in the array, and glUniformLocationARB( program, “someUniformArray[1]” ) should point to the second vec3. Then supplying the C/C++ array { 1.0f, 1.0f, 1.0f } to each of these separately by using glUniform3fv() should fill all 6 floats in someUniformArray with 1.0. Is this all correct?

If so, there is a bug in the way it works in the ATI drivers (BTW, I’m running Radeon 9800 Pro, Catalyst 4.9), which always give an offset with a multiple of 4 (in number of floats), as if you are using a uniform array of vec4’s.

For example, using the same uniform array as above - which is really just 6 floats - and requesting “someUniformArray[0]” from glUniformLocationARB() gives the correct location which points to the first of the 6 floats. But, requesting “someUniformArray[1]” points to the 5th float. In other words it is skipping the first 4 floats, which is only correct if the array is of vec4’s, but it happens when using vec3’s and vec2’s as well which means some values never get filled. In this case someUniformArray[1].x will not be set.

Hopefully all that makes sense. Has anyone had this problem? Is it a know issue?

Luckily, it is not too difficult to work around for the moment, the easiest way is to just use 1 big C/C++ array of all the values and updating all at once, but it would be good to have the convience of partial updates in the future.

The return value of glUniformLocationARB is just a location of the uniform you asked for.
You must not use the location to do any calculation on them. The uniform location in an array could even be reverse ordered.
The location “offset” of 4 between two consecutive vec3 can mean that they are actually stored in a vec4 array of program parameters, which BTW is what all vector processors with vec4 base sizes need to do to allow programmable addressing. The locations returned might be totally different among implementations.
If you want to update an array of vec3 values in one sweep, just use the count parameter in glUniform3fv and the start location where to begin. The driver needs to handle the rest.

Okay, I’m not doing direct calculations on the returned values here’s a more concrete example, maybe I’m wrong but I think it should work like this:

Vertex Shader

vec3 someArray[2];

C++ code example 1

GLfloat values[] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
GLint location = glGetUniformLocationARB( programObject, "someArray[0]" );
glUniform3fvARB( location, 2, values );

C++ code example 2

GLfloat values[] = { 1.0f, 1.0f, 1.0f };
GLint location = glGetUniformLocationARB( programObject, "someArray[0]" );
glUniform3fvARB( location, 1, values );

GLint location = glGetUniformLocationARB( programObject, "someArray[1]" );
glUniform3fvARB( location, 1, values );

As far as I understand, both of these examples should give the same result. The result being that all 6 floats in the vec3 someArray[2] uniform are assigned the value 1.0f. Is this correct?

What actually happens is that the first example behaves as I expect and all 6 components of the array are 1.0f. But, using the second code example the following is true inside the vertex shader:

someArray[0].x == 1.0
someArray[0].y == 1.0
someArray[0].z == 1.0

someArray[1].x == 0.0
someArray[1].y == 1.0
someArray[1].z == 1.0

I don’t think this is correct, although possibly I’m misunderstanding the spec.

As a final example to confirm what I was trying to describe in my first post, this code:

C++ code example 3

GLfloat values[] = { 1.0f, 1.0f, 1.0f };

// same as example 2, but don't assign to someArray[0]
// GLint location = glGetUniformLocationARB( programObject, "someArray[0]" );
// glUniform3fvARB( location, 1, values );

GLint location = glGetUniformLocationARB( programObject, "someArray[1]" );
glUniform3fvARB( location, 1, values );

which only assigns to the location someArray[1] gives the following results:

someArray[0].x == 0.0
someArray[0].y == 0.0
someArray[0].z == 0.0

someArray[1].x == 0.0
someArray[1].y == 1.0 // first assigned value is here
someArray[1].z == 1.0

As you can see the 4th ‘location’ is updated which, as far as I understand, is not correct - it’s working as if I had a vec4 array even when I don’t.

Hopefully this clears things up. If I’m wrong, I’m not sure what is supposed to happen.

Thanks.

Right, all of your examples should correctly assign the values the way you intended. Contact ATI for a fix.

Thanks Relic, that’s what I suspected.

I just quickly tested this and can verify that there’s a bug here. Quick question though, did you contact ATI about this already? If not, you don’t have to, I can just file the bug report directly.

Humus: I just sent an email to devrel@ati.com after confirming that it was a bug on this thread. I wasn’t sure if that was the right address but I was waiting to hear back if it was wrong.

So do as you see fit with regards to reporting it if it’s easy for you to do so, or if that address is okay for reporting bugs then, yes I have reported it. :wink:

That address is certainly okay for reporting bugs. It will just pass through more people and may end up on my desk to verify anyway. Many OpenGL bugs do.

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