GLSL sampler array = different behaviour on RADEON / GEFORCE

Can you find error in this test of sampler array?

It renders correctly on both GEFORCE and RADEON cards, but RADEONs throw GL_INVALID_OPERATION in glEnd.

It is so simplified, that it creates no fragments and sampler lookup is dead code, but GL_INVALID_OPERATION is still present.

Bigger version with array longer than 1 compiles and links without errors, but renders incorrectly on RADEONs.

#include <GL/glew.h>
#include <GL/glut.h>

GLuint shadowmap;
GLint program;

void display()
{
	glUseProgram(program);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D,shadowmap);

	GLint zero=0;
	glUniform1iv(glGetUniformLocation(program,"shadowMap"),1,&zero);

	glBegin(GL_TRIANGLES);
	glVertex3f(0,0,0);
	glVertex3f(0,0,0);
	glVertex3f(0,0,0);
	glEnd(); // throws GL_INVALID_OPERATION with Radeon, Catalyst 6.12
	glutSwapBuffers();
}

int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
	glutInitWindowSize(640,480);
	glutCreateWindow("test");
	glutDisplayFunc(display);
	glewInit();

	glGenTextures(1,&shadowmap);
	glBindTexture(GL_TEXTURE_2D,shadowmap);
	glTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT,64,64,0,GL_DEPTH_COMPONENT,GL_UNSIGNED_BYTE,0);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_COMPARE_MODE,GL_COMPARE_R_TO_TEXTURE);

	program = glCreateProgram();
	GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
	const GLchar* strings[] = {"uniform sampler2DShadow shadowMap[1]; void main() { shadow2DProj(shadowMap[0], gl_FragCoord); gl_FragColor = vec4(1.0,1.0,1.0,1.0); }"};
	glShaderSource(shader,1,strings,0);
	glCompileShader(shader);
	glAttachShader(program,shader);
	glLinkProgram(program);

	glutMainLoop();
	return 0;
}

It’s hard to read like that

uniform sampler2DShadow shadowMap[1];

void main()
{
   shadow2DProj(shadowMap[0], gl_FragCoord);    
   gl_FragColor = vec4(1.0,1.0,1.0,1.0);
}

Your code does nothing and the useless parts can be striped out.

glGetUniformLocation(program,“shadowMap”)
would return -1
and I think you need to actually call
glGetUniformLocation(program,“shadowMap[0]”)

because it is FOR EACH ELEMENT in the array.

V-man, are you sure?

I am pretty sure you can query the location of the array, then supply the entire array values in one call. (otherwise what would be the point of the glUniform*iv calls?)

Perhaps you are confusing it with glGetUniform where you need the index of each element of the array. (as you can’t assume strides etc.)

The location of first element of array can be retrieved by either using the name of the uniform array, or the name of the uniform array appended with “[0]” so both “shadowMap” and “shadowMap[0]” should do the same correct thing.


It renders correctly on both GEFORCE and RADEON cards, but RADEONs throw GL_INVALID_OPERATION in glEnd.

It is possible that there is some problem within the Radeon driver. One possible candidate is combination of fixed function vertex processing with fragment shader that uses the gl_FragCoord built-in varying. Try to provide vertex shader and/or replace the gl_FragCoord with constant value or texture coordinate.

Looks like you can use shadowMap as well.
I guess I was thinking of struct

It’s god to check that glGetUniformLocation(program,“shadowMap”) isn’t -1, else glUniform1iv can generate GL_INVALID_OPERATION

Thanks for hints. Unfortunatelly no progress.

I changed fragment shader to

uniform sampler2DShadow shadowMap[1];
void main() 
{
    gl_FragColor = shadow2DProj(shadowMap[0], vec4(1.0,1.0,1.0,1.0)); 
}

to avoid gl_FragCoord issue and any dead code issues.

Program is still linked successfully.

glGetUniformLocation still returns 0 (on Radeons, they don’t eliminate dead code).

shadowMap[0] in glGetUniformLocation makes no difference.

Attaching vertex shader “void main() { gl_Position = gl_Vertex; }” makes no difference.

I reported it to Catalyst Crew few days ago using http://support.ati.com/ics/survey/survey.asp?deptID=894&surveyID=486&type=web form, but I don’t know if anyone reads it, form required me to pick driver version from list of outdated versions.

Originally posted by V-man:

It’s god to check that glGetUniformLocation(program,“shadowMap”) isn’t -1, else glUniform1iv can generate GL_INVALID_OPERATION

There will be no OGL error. The specification explicitly allows value of -1 to be passed to glUniform* functions.

If the value of location is -1, the Uniform* commands will silently ignore the data passed in, and the current uniform values will not be changed.

Originally posted by Dee.cz:
Thanks for hints. Unfortunatelly no progress.

I assume that if you replace the sampler array with single sampler that the error is not generated.

Originally posted by Komat:
I assume that if you replace the sampler array with single sampler that the error is not generated.
Yes, error is reported only with array.

Originally posted by Dee.cz:
(on Radeons, they don’t eliminate dead code).
Are you sure about this?

Looks like there is a little thing in the shader_objects spec. In the Q&A section, it says it returns INVALID_OPERATION when -1 is given to glUniform, but in the Errors section, it says the opposite.

Dead code is likely eliminated, but if you try to get the location of a uniform, most often you get a valid value (not -1)

Originally posted by V-man:
Looks like there is a little thing in the shader_objects spec. In the Q&A section, it says it returns INVALID_OPERATION when -1 is given to glUniform, but in the Errors section, it says the opposite.

Revision 0.87 and older generated that error for location -1. This was changed in latter revisions (issue 36) which were promoted to OGL2.0 core.

Originally posted by Dee.cz:
[quote]Originally posted by Komat:
I assume that if you replace the sampler array with single sampler that the error is not generated.
Yes, error is reported only with array.
[/QUOTE]In that case it almost certainly is a bug within the driver.

SKoder, V-man could be right and I was wrong. All I know is I can get valid location for dead variable referenced by dead shader code, but not for dead variable never referenced by shader.

Komat, I made mistake, it reports error even with plain sampler2D, without sampler array.

Originally posted by Dee.cz:
Komat, I made mistake, it reports error even with plain sampler2D, without sampler array.
In that case try to use the GL_DEPTH_COMPONENT16 internal format when creating the texture. All ATI cards older than X1600 (this includes the X1800) only supported 16bit depth textures.