glGetActiveUniform array query broken

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.

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