glGetUniformLocation returns -1 for one Uniform

I’m attempting to create a compute shader class in Java. When I try to find the “InverseRanges” uniform using glGetUniformLocation, -1 is returned.

Here is my shader:

#version 450 core

//"#define NUM_SHADOW_MAPS n" inserted by compute shader class

layout(local_size_x = NUM_SHADOW_MAPS, local_size_y = 1, local_size_z = 1) in;

uniform sampler2D ShadowMaps[NUM_SHADOW_MAPS];
uniform mat4 LightMatrices[NUM_SHADOW_MAPS];
uniform vec2 InverseRanges[NUM_SHADOW_MAPS];
uniform int LightIndices[NUM_SHADOW_MAPS];
uniform int LightTypes[NUM_SHADOW_MAPS];

layout(R32F) uniform image3D VoxelLightMap;
uniform vec3 GridMin;
uniform vec3 GridMax;

shared int table = 0;

float linearizeDepth(float depth, vec2 lightRangeInverse) {
    return (1.0/depth - lightRangeInverse.x) * lightRangeInverse.y;
}

bool isExposedToLight(vec3 worldPos, sampler2D shadowMap, mat4 lightViewProjectionMatrix, vec2 lightRangeInverse, bool outOfBoundsExposed) {
    vec4 lightViewPos = lightViewProjectionMatrix * vec4(worldPos, 1.0);
    vec2 lightUv = (lightViewPos.xy / lightViewPos.w + 1.0) * 0.5;
    float depth = lightViewPos.z;
    if (depth >= 0.0 && lightUv.x >= 0.0 && lightUv.x <= 1.0 && lightUv.y >= 0.0 && lightUv.y <= 1.0) {
        float shadow = texture(shadowMap, lightUv).r;
        depth = linearizeDepth(depth, lightRangeInverse);
        return depth <= shadow;
    }
    return outOfBoundsExposed;
}

void main() {
    
    vec3 wPos = (GridMax - GridMin) * (vec3(gl_WorkGroupID) / vec3(gl_NumWorkGroups)) + GridMin;
    int i = int(gl_LocalInvocationIndex);
    mat4 mat = LightMatrices[i];
    vec2 range = InverseRanges[i];
    int type = LightTypes[i];
    int result = 0;
    if (isExposedToLight(wPos, ShadowMaps[i], mat, range, false/*type == 0*/)) {
        result = 1 << LightIndices[i];
    }
    
    atomicOr(table, result);
    
    memoryBarrierShared();
    if (i == 0) {
        imageStore(VoxelLightMap, ivec3(gl_GlobalInvocationID), vec4(table, 0.0, 0.0, 0.0));
    }
    
}

Here is the code I use to compile, attach, and link:

// build source
String source = buildSource(workSize);
checkError();
int shader = glCreateShader(GL_COMPUTE_SHADER);
checkError();
glShaderSource(shader, source);
checkError();
// compile source
glCompileShader(shader);
checkError();
//intBuf declared as BufferUtils.createIntBuffer(1) previously
glGetShaderiv(shader, GL_COMPILE_STATUS, intBuf);
if (intBuf.get(0) == GL_FALSE) {
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, intBuf);
    int length = intBuf.get(0);
    if (length > 3) {
        String info = glGetShaderInfoLog(shader, length);
        LOG.log(Level.SEVERE, "Bad compile of\n{0}", ShaderDebug.formatShaderSource(source));
        throw new RuntimeException("Compile error in " + name + "\n" + info);
    }
}
// attach shader
glAttachShader(id, shader);
glLinkProgram(id);
checkError();
glGetProgramiv(id, GL_LINK_STATUS, intBuf);
if (intBuf.get(0) == GL_FALSE) {
    glGetProgramInfoLog(id, intBuf, null);
    ByteBuffer log = BufferUtils.createByteBuffer(intBuf.get(0));
    glGetProgramInfoLog(id, intBuf, log);
    throw new RuntimeException("Failed to link " + name + ":\n" + MemoryUtil.memASCII(log));
}
glDeleteShader(shader);
private static void checkError() {
    int flag = glGetError();
    if (flag != GL_NO_ERROR) {
        throw new RuntimeException("OpenGL error: " + flag);
    }
}

Finally, here is where I attempt to find a uniform’s location:

int uniform = glGetUniformLocation(id, name);
checkError();
if (uniform < 0) {
    System.out.println("Unable to locate uniform \"" + name + "\" in shader.");
    return;
}
System.out.println("Successfully located uniform " + name);

The shader is compiled without errors, and the program is linked without errors. No errors were picked up by checkError() anywhere in the program.

“InverseRanges” is also definitely used in the shader, so I wouldn’t think that the compiler is optimizing it away. All the other uniforms are successfully being located.

Been trying to fix this for a couple days now, so any help is greatly appreciated!

It seems that InverseRanges was indeed being culled by the compiler. When I changed the shader so that InverseRanges[i].x is written to the green channel of LightVoxelMap, I’m suddenly able to locate the InverseRanges uniform.

imageStore(VoxelLightMap, ivec3(gl_GlobalInvocationID), vec4(table, InverseRanges[i].x, 0.0, 0.0));

So the original problem is solved, but I’m still confused why InverseRanges was being culled in the first place. It is clearly passed to isExposedToLight(), which clearly uses it for depth linearization.

I don’t know whether this is the cause, but using texture outside of a fragment shader (and also within non-uniform control flow) results in undefined behaviour, as it requires implicit derivates which are undefined in that context. Use e.g. textureLod or textureGrad instead.

Also: if you aren’t already doing this, it’s a good idea to print the shader compilation and linking logs even when compilation and linking succeed, as they can include warnings.

1 Like

Ah, I didn’t realize that. I changed texture to textureLod and now InverseRanges can be located without piping it through the image’s green channel.