According to The Orange Book and the SDK, glGetActiveUniform on an array uniform should "if one or more elements of the array are active, … the size parameter returns the highest array element index used, plus one, as determined by the compiler and linker.
It appears this API is not returning the highest used +1, but instead the max+1. This is a bug, correct?
With the Cg compiler (cgc -oglsl -profile glslf) I can trivially verify that the NVidia compiler is detecting that only the first array element is used/active.
Further, glGetUniformLocation( “myarray[#]” ) doesn’t return -1 for any of the unused samplers elements from the array, implying they are active. Its man page says “This function returns -1 if name does not correspond to an active uniform variable in program…”
Here’s a short GLUT prog that reproduces the problem. array size returns 8 (max len) instead of the 1 (active len) that the docs say it should. Further it shows that the uniform location for the unused array elements is not -1, implying they are active:
//------------------------------------------------------------------------------
// tst.cxx - Shows that glGetActiveUniformARB returns the "maximum" number
// of array elements, rather than the "used" number of array elements.
//------------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define GL_GLEXT_PROTOTYPES 1
#include <GL/gl.h>
#include <GL/glut.h>
static const char Vertex_src[] =
"void main(void) { gl_Position=ftransform(); }";
static const char Fragment_src[] =
"const int MAX_TEX_UNITS = 8;"
"uniform sampler2D texunit2D[ MAX_TEX_UNITS ];"
""
"void main(void)"
"{"
" gl_FragColor = texture2D( texunit2D[0], vec2( 0., 0. ) );"
"}";
GLhandleARB installShader ( const char *src, GLenum type )
{
const char *type_str = type == GL_VERTEX_SHADER ? "vertex" : "fragment";
GLhandleARB handle = glCreateShaderObjectARB ( type ) ;
glShaderSource ( handle, 1, &src, 0 ) ;
glCompileShader ( handle ) ;
GLint stat ;
glGetObjectParameterivARB ( handle, GL_OBJECT_COMPILE_STATUS_ARB, & stat ) ;
if ( ! stat )
{
fprintf ( stderr, "Failed to compile %s shader.
", type_str );
exit ( 1 ) ;
}
return handle ;
}
GLhandleARB linkShaders ( GLhandleARB vsHandle, GLhandleARB fsHandle )
{
GLint stat ;
GLhandleARB handle = glCreateProgramObjectARB () ;
glAttachObjectARB ( handle, vsHandle ) ;
glAttachObjectARB ( handle, fsHandle ) ;
glLinkProgramARB ( handle ) ;
glGetObjectParameterivARB ( handle, GL_OBJECT_LINK_STATUS_ARB, &stat ) ;
glValidateProgram ( handle ) ;
if ( ! stat )
{
fprintf ( stderr, "Failed to link shader.
" ) ;
exit ( 1 ) ;
}
return handle ;
}
int main ( int argc, char **argv )
{
// Init GL context
glutInit ( &argc, argv ) ;
glutInitDisplayMode ( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE ) ;
glutInitWindowSize ( 500, 500 ) ;
glutCreateWindow ( "Shader Test" ) ;
//glutDisplayFunc ( display ) ;
//glutKeyboardFunc ( keybd ) ;
//glutReshapeFunc ( reshape ) ;
// Load and compile shaders
//const char path[] = "shader_otw.glsl";
//const char path[] = "shader.glsl";
const char path[] = "light_point.glsl";
printf( "Compiling vertex shader...
" );
GLhandleARB vsHandle = installShader ( Vertex_src, GL_VERTEX_SHADER );
printf( "Compiling fragment shader...
" );
GLhandleARB fsHandle = installShader ( Fragment_src, GL_FRAGMENT_SHADER);
// Link shaders
printf( "Linking...
" );
GLhandleARB handle = linkShaders ( vsHandle, fsHandle ) ;
// Activate shader
glUseProgramObjectARB ( handle ) ;
// Now query number of "used" textures
GLint num_uniforms = 0 ;
glGetObjectParameterivARB ( handle, GL_OBJECT_ACTIVE_UNIFORMS_ARB,
& num_uniforms );
for ( int i = 0; i < num_uniforms ; i++ )
{
char name[ 1024 ] ;
GLint size;
GLenum type;
glGetActiveUniformARB( handle, i, 1024, 0, &size, &type, name );
if ( strcmp( name, "texunit2D" ) == 0 && type == GL_SAMPLER_2D )
{
// NOTE: This should return 1 (active len).
// Instead it returns 8 (max len)
printf( "Number of used textures = %d
", size );
// Now also double-check the results with gl
for ( int j = 0; j < size; j++ )
{
char name[ 80 ];
sprintf( name, "texunit2D[%d]", j );
GLint loc = glGetUniformLocationARB( handle, name );
printf( "%s = %d
", name, loc );
}
break;
}
}
// Draw with shader
//glutMainLoop () ;
return 0 ;
}
BTW, this is with NVidia 185.18.14.