1

So i have a custom structure in the fragment shader and an uniform variable that is an array of these structures. It is defined like this:

#version 130
#define MAX_LIGHTS 8

struct Light {
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    vec4 position;
    vec3 direction;
    float cutoff;
    float exponent;
};

uniform Light lights[MAX_LIGHTS];

Now, i'm trying to get the uniform locations like this:

glGetUniformLocation(program, "lights[0].ambient");
glGetUniformLocation(program, "lights[0].diffuse");
// etc...

Everything works fine on my GTX460, but the glGetUniformLocation returns -1 on a Mobility Radeon HD 5650 even though the shader compiles/links fine and everything. (It is an OpenGL 3.1 context btw.)

What am i doing wrong?

EDIT: Alright, here is the full shader (i did not write it, i'm trying to fix a friend's program). Additionally, i have also tested this on an Intel HD integrated graphics adapter and it worked without problems as well.

4
  • 2
    Where is the rest of the shader? If you never reference lights[0].ambient, then you should not expect it to have an active uniform location. I would suggest you run through the list of active uniforms... (See: GL_ACTIVE_UNIFORMS and glGetActiveUniform (...)). From years of experience I can tell you that NV and AMD both have different behavior when it comes to naming and qualifying array-based uniform elements as active. Commented Nov 10, 2013 at 22:53
  • Are you sure it's compiling and linking the shader properly? I'm guessing you're calling glGetProgramInfoLog to get any errors that might have occured? Commented Nov 11, 2013 at 2:04
  • To add to what @AndonM.Coleman said: An active uniform variable is a variable that it is actually used inside the shader, not just declared. The compiler is free to throw away variables that are not used in the code. Therefore, even if a uniform is declared in the shader, as long as it is not used, its reported location can be -1. From here: lighthouse3d.com/tutorials/glsl-core-tutorial/… Commented Nov 11, 2013 at 2:06
  • Yes, as i said, it works on my computer, and the lighting is there, so everything is definitely being used. It returns -1 on every single field but only for lights. Commented Nov 11, 2013 at 9:02

1 Answer 1

11

Since people often blindly fumble around trying to figure out what the cause of glGetUniformLocation (...) returning -1 is, I figured I would share some modified code that I use to enumerate all uniforms per-GLSL program. I actually use a map structure to do type enum to string name but that would be more complicated than necessary.

Utility structure to print human-readable types (up to GLSL 430):

struct glsl_type_set {
  GLenum      type;
  const char* name;
}
type_set [] = {
  GL_INVALID_ENUM,                              "invalid",
  GL_FLOAT,                                     "float",
  GL_FLOAT_VEC2,                                "vec2",
  GL_FLOAT_VEC3,                                "vec3",
  GL_FLOAT_VEC4,                                "vec4",
  GL_DOUBLE,                                    "double",
  GL_DOUBLE_VEC2,                               "dvec2",
  GL_DOUBLE_VEC3,                               "dvec3",
  GL_DOUBLE_VEC4,                               "dvec4",
  GL_INT,                                       "int",
  GL_INT_VEC2,                                  "ivec2",
  GL_INT_VEC3,                                  "ivec3",
  GL_INT_VEC4,                                  "ivec4",
  GL_UNSIGNED_INT,                              "unsigned int",
  GL_UNSIGNED_INT_VEC2,                         "uvec2",
  GL_UNSIGNED_INT_VEC3,                         "uvec3",
  GL_UNSIGNED_INT_VEC4,                         "uvec4",
  GL_BOOL,                                      "bool",
  GL_BOOL_VEC2,                                 "bvec2",
  GL_BOOL_VEC3,                                 "bvec3",
  GL_BOOL_VEC4,                                 "bvec4",
  GL_FLOAT_MAT2,                                "mat2",
  GL_FLOAT_MAT3,                                "mat3",
  GL_FLOAT_MAT4,                                "mat4",
  GL_FLOAT_MAT2x3,                              "mat2x3",
  GL_FLOAT_MAT2x4,                              "mat2x4",
  GL_FLOAT_MAT3x2,                              "mat3x2",
  GL_FLOAT_MAT3x4,                              "mat3x4",
  GL_FLOAT_MAT4x2,                              "mat4x2",
  GL_FLOAT_MAT4x3,                              "mat4x3",
  GL_DOUBLE_MAT2,                               "dmat2",
  GL_DOUBLE_MAT3,                               "dmat3",
  GL_DOUBLE_MAT4,                               "dmat4",
  GL_DOUBLE_MAT2x3,                             "dmat2x3",
  GL_DOUBLE_MAT2x4,                             "dmat2x4",
  GL_DOUBLE_MAT3x2,                             "dmat3x2",
  GL_DOUBLE_MAT3x4,                             "dmat3x4",
  GL_DOUBLE_MAT4x2,                             "dmat4x2",
  GL_DOUBLE_MAT4x3,                             "dmat4x3",
  GL_SAMPLER_1D,                                "sampler1D",
  GL_SAMPLER_2D,                                "sampler2D",
  GL_SAMPLER_3D,                                "sampler3D",
  GL_SAMPLER_CUBE,                              "samplerCube",
  GL_SAMPLER_1D_SHADOW,                         "sampler1DShadow",
  GL_SAMPLER_2D_SHADOW,                         "sampler2DShadow",
  GL_SAMPLER_1D_ARRAY,                          "sampler1DArray",
  GL_SAMPLER_2D_ARRAY,                          "sampler2DArray",
  GL_SAMPLER_1D_ARRAY_SHADOW,                   "sampler1DArrayShadow",
  GL_SAMPLER_2D_ARRAY_SHADOW,                   "sampler2DArrayShadow",
  GL_SAMPLER_2D_MULTISAMPLE,                    "sampler2DMS",
  GL_SAMPLER_2D_MULTISAMPLE_ARRAY,              "sampler2DMSArray",
  GL_SAMPLER_CUBE_SHADOW,                       "samplerCubeShadow",
  GL_SAMPLER_BUFFER,                            "samplerBuffer",
  GL_SAMPLER_2D_RECT,                           "sampler2DRect",
  GL_SAMPLER_2D_RECT_SHADOW,                    "sampler2DRectShadow",
  GL_INT_SAMPLER_1D,                            "isampler1D",
  GL_INT_SAMPLER_2D,                            "isampler2D",
  GL_INT_SAMPLER_3D,                            "isampler3D",
  GL_INT_SAMPLER_CUBE,                          "isamplerCube",
  GL_INT_SAMPLER_1D_ARRAY,                      "isampler1DArray",
  GL_INT_SAMPLER_2D_ARRAY,                      "isampler2DArray",
  GL_INT_SAMPLER_2D_MULTISAMPLE,                "isampler2DMS",
  GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY,          "isampler2DMSArray",
  GL_INT_SAMPLER_BUFFER,                        "isamplerBuffer",
  GL_INT_SAMPLER_2D_RECT,                       "isampler2DRect",
  GL_UNSIGNED_INT_SAMPLER_1D,                   "usampler1D",
  GL_UNSIGNED_INT_SAMPLER_2D,                   "usampler2D",
  GL_UNSIGNED_INT_SAMPLER_3D,                   "usampler3D",
  GL_UNSIGNED_INT_SAMPLER_CUBE,                 "usamplerCube",
  GL_UNSIGNED_INT_SAMPLER_1D_ARRAY,             "usampler2DArray",
  GL_UNSIGNED_INT_SAMPLER_2D_ARRAY,             "usampler2DArray",
  GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE,       "usampler2DMS",
  GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, "usampler2DMSArray",
  GL_UNSIGNED_INT_SAMPLER_BUFFER,               "usamplerBuffer",
  GL_UNSIGNED_INT_SAMPLER_2D_RECT,              "usampler2DRect",
  GL_IMAGE_1D,                                  "image1D",
  GL_IMAGE_2D,                                  "image2D",
  GL_IMAGE_3D,                                  "image3D",
  GL_IMAGE_2D_RECT,                             "image2DRect",
  GL_IMAGE_CUBE,                                "imageCube",
  GL_IMAGE_BUFFER,                              "imageBuffer",
  GL_IMAGE_1D_ARRAY,                            "image1DArray",
  GL_IMAGE_2D_ARRAY,                            "image2DArray",
  GL_IMAGE_2D_MULTISAMPLE,                      "image2DMS",
  GL_IMAGE_2D_MULTISAMPLE_ARRAY,                "image2DMSArray",
  GL_INT_IMAGE_1D,                              "iimage1D",
  GL_INT_IMAGE_2D,                              "iimage2D",
  GL_INT_IMAGE_3D,                              "iimage3D",
  GL_INT_IMAGE_2D_RECT,                         "iimage2DRect",
  GL_INT_IMAGE_CUBE,                            "iimageCube",
  GL_INT_IMAGE_BUFFER,                          "iimageBuffer",
  GL_INT_IMAGE_1D_ARRAY,                        "iimage1DArray",
  GL_INT_IMAGE_2D_ARRAY,                        "iimage2DArray",
  GL_INT_IMAGE_2D_MULTISAMPLE,                  "iimage2DMS",
  GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY,            "iimage2DMSArray",
  GL_UNSIGNED_INT_IMAGE_1D,                     "uimage1D",
  GL_UNSIGNED_INT_IMAGE_2D,                     "uimage2D",
  GL_UNSIGNED_INT_IMAGE_3D,                     "uimage3D",
  GL_UNSIGNED_INT_IMAGE_2D_RECT,                "uimage2DRect",
  GL_UNSIGNED_INT_IMAGE_CUBE,                   "uimageCube",
  GL_UNSIGNED_INT_IMAGE_BUFFER,                 "uimageBuffer",
  GL_UNSIGNED_INT_IMAGE_1D_ARRAY,               "uimage1DArray",
  GL_UNSIGNED_INT_IMAGE_2D_ARRAY,               "uimage2DArray",
  GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE,         "uimage2DMS",
  GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY,   "uimage2DMSArray",
  GL_UNSIGNED_INT_ATOMIC_COUNTER,               "atomic_uint"
};

Code to enumerate all ACTIVE uniforms in a program:

void
eTB_GLSL__print_uniforms (GLuint program)
{
  GLint uniform_count;
  glGetProgramiv (program, GL_ACTIVE_UNIFORMS, &uniform_count);

  GLchar name [256];

  for (GLint i = 0; i < uniform_count; i++) {
    memset (name, '\0', 256);
    GLint  size;
    GLenum type;

    glGetActiveUniform (program, i, 255, NULL, &size, &type, name);

    GLint location = glGetUniformLocation (program, name);

    for (int j = 0; j < sizeof (type_set) / sizeof (glsl_type_set); j++) {
      if (type_set [j].type != type)
        continue;

      const char* type_name = type_set [j].name;

      if (size > 1)
        printf ( "Uniform %d (loc=%d):\t%20s %-20s <Size: %d>\n",
                   i, location, type_name, name, size );
      else
        printf ( "Uniform %d (loc=%d):\t%20s %-20s\n",
                   i, location, type_name, name );

      break;
    }

    if (i == (uniform_count - 1))
      printf ("\n");
  }
}

Sample Output (AMD):

Uniform 0 (loc=0):                         float buffer_res_x        
Uniform 1 (loc=1):                         float buffer_res_y        
Uniform 2 (loc=2):                         float buffer_scale        
Uniform 3 (loc=3):                          mat4 camera_matrix       
Uniform 4 (loc=4):                          bool fxaa                
Uniform 5 (loc=5):                          vec3 light_colors         <Size: 128>
Uniform 6 (loc=133):                        vec3 light_pos            <Size: 128>
Uniform 7 (loc=261):                        mat4 modelview_mat       
Uniform 8 (loc=262):                         int num_lights          
Uniform 9 (loc=263):                   sampler2D depth_buffer        
Uniform 10 (loc=264):                  sampler2D diffuse_buffer      
Uniform 11 (loc=265):                  sampler2D normal_buffer       
Uniform 12 (loc=266):                samplerCube shadow_buffer        <Size: 10>

Sample Output (NV):

Uniform 0 (loc=0):                         float buffer_res_x        
Uniform 1 (loc=1):                         float buffer_res_y        
Uniform 2 (loc=2):                         float buffer_scale        
Uniform 3 (loc=3):                          mat4 camera_matrix       
Uniform 4 (loc=4):                          bool fxaa                
Uniform 5 (loc=5):                          vec3 light_colors[0]      <Size: 128>
Uniform 6 (loc=133):                        vec3 light_pos[0]         <Size: 128>
Uniform 7 (loc=261):                        mat4 modelview_mat       
Uniform 8 (loc=262):                         int num_lights          
Uniform 9 (loc=263):                   sampler2D depth_buffer        
Uniform 10 (loc=264):                  sampler2D diffuse_buffer      
Uniform 11 (loc=265):                  sampler2D normal_buffer       
Uniform 12 (loc=266):                samplerCube shadow_buffer[0]     <Size: 10>

I chose this particular shader because it is the first one I could find that demonstrates how NV and AMD differ when reporting uniform names for arrays, there is nothing particularly special about it. NV always uses [0] notation and AMD does not (newer drivers tend to, however). You can still query individual uniform locations provided they are within the range indicated by <Size: X>. That is to say that while the driver will enumerate them as name[0] or name, it is technically valid to query the uniform location for name or name[0] in either implementation.

I would be very interested in seeing three things:

  1. The output of this after linking on your AMD hardware
  2. The output of this after linking on your NV hardware
  3. Your full shader

With these three things, an actual answer should be possible.

UPDATE

I believe the GLSL compiler is having a hard time determining usage because of the way the shader is written, to confirm this, try replacing:

vec3 computeLight(int light_index){
  Light light = lights[light_index];
  if(light.position == vec4(0.0)) { return vec3(0.0);}
  if(light.position.w == 0.0 ) {return directionLight(light);}
  if(light.cutoff == 0) {return pointLight(light);}
  return reflectionLight(light);
}

[...]

vec3 lighting = vec3(0.);
  for(int i = 0; i < lights_no; i++) {
    lighting += computeLight(i);
}

With something much uglier like:

vec3 lighting = vec3(0.0);
  for(int i = 0; i < lights_no; i++) {
    Light light = lights [i];
    if (light.position != vec4 (0.0)) {
      if (light.position.w == 0.0)
        lighting += directionLight(light);
      else if (light.cutoff == 0.0)
        lighting += pointLight(light);
      else
        lighting += reflectionLight (light);
    }
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Alright, i tried this and the light uniforms seem to just disappear for some reason. Here is the output: pastebin.com/gm1ty36M pastebin.com/eqpJ6rFU Also, here is the full shader code, but i'd like to note that i didn't write it, i'm trying to help a friend: pastebin.com/jnSqEKW5
@Detheroc: See my updated answer, I believe this is due to using a non-const expression within a function to index the uniform array. This is invalid in OpenGL ES for sure, it does not violate desktop OpenGL rules however I would not be surprised if the GLSL compiler is not properly analyzing computeLight (...). If this is the case, I would suggest re-writing computeLight (...) to be passed a Light instead of an index to read from the lights [] array.
Thank you for your help, the friend has told me that the problem has been fixed by updating drivers, so unfortunatelly i didn't get to test your solution. The important thing is that it works now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.