Fragment shader displays the correct image despite error message

Trying tutorial43 in ogldev.org it builds and runs fine except for an error message I get when I close the window, this is shown in image 1.Image 1
As can be seen in the image I printed out the texture units used the sampler2d and samplerCube and they are indeed different. The top of the trace output is shown in image3.Image 3
The correct image is as in image 2 produced by the program.


When I assign the 2 samplers to the same texture unit, the program crashes and I get the error message mentioned in image 1.

My question if everything is fine why the error message about invalid shader when closing the window? is this a bug in the driver?

This indicates that at some point, when the program was “validated” against the current GL state (**), then the shader program:

  1. Makes use of 2+ sampler uniforms,
  2. At least 2 of these survive compile+link and are used in the resulting shader program binary, and
  3. The texture image assigned to 2 or more of these are assigned the same texture image unit number.

(**) Shader program validation occurs when glValidateProgram() is called or a draw call is made with that shader program bound to the context.

So check the code for this. Assuming it’s not a driver bug, it’s likely being invoked someplace you’ve not looked at.

The easy way to avoid this is to just specify the texture unit bindings in your shader code, rather than specify them externally via glUniform1i(). For instance:

layout( binding = 0 ) uniform sampler2D   tex1;
layout( binding = 1 ) uniform samplerCube tex2;

Then there’s no way this conflict can arise between these two sampler uniforms in this shader stage.

So on that tutorial, in lighting.fs we have:

uniform sampler2D gColorMap;
uniform samplerCube gShadowMap;

so there’s a potential for conflict here, since the texture unit bindings aren’t specified in the shader code.

Consulting the code, glValidateProgram() is called in:

    Tutorial43::Init()
      LightingTechnique::Init()
        Technique::Finalize()
          glValidateProgram()

However, there’s no proper GL state setup before this call to glValidateProgram() to put the context in a reasonable state to validate or render with this shader program. That’s likely the problem here.

Evidence to support this is the prefix on that error message you quoted above.

Invalid shader program: active samplers with a different type refer to the same texture image unit

That’s the same prefix used to log error validation errors after glValidateProgram() is called:

bool Technique::Finalize()
{
...
    glValidateProgram(m_shaderProg);
    glGetProgramiv(m_shaderProg, GL_VALIDATE_STATUS, &Success);
    if (!Success) {
        glGetProgramInfoLog(m_shaderProg, sizeof(ErrorLog), NULL, ErrorLog);
        fprintf(stderr, "Invalid shader program: '%s'\n", ErrorLog);
     //   return false;
    }

The only other place that looks like it might be emitting similar error messages is the font shader validation, called here:

    Tutorial43::Init()
      FontRenderer::InitFontRenderer()
        FontShader::InitFontShader()
          `glValidateProgram()`

However, the font shader source code doesn’t make use of more than 1 sampler uniform. So it’s vindicated.

So the cause of the validation error seems to be the lack of proper GL state setup prior to calling glValidateProgram() for the tutorial43 LightingTechnique shader program making use of the lighting.fs fragment shader. Specifically, the sampler uniform values for gColorMap and gShaderMap likely need to be setup properly first (glGetUniformLocation() + glUniform1i()) so that their texture image unit indices are distinct.

Put a breakpoint in the code and check!

Just adding layout ( binding = 0 ) and layout ( binding = 1 ) in the fragment shader before the uniforms of sampler2D and samplerCube got rid of the error message. Thanks a lot for your expertise. I know this is the easy way out, will try to trace and set up the state correctly before glValidateProgram get called…

Sometimes the easy way is the best way.

Adding explicit layout qualifiers is generally preferred in modern OpenGL, and enables greater code robustness as a tradeoff vs flexibility you probably don’t need.

Another robustness “trick” I generally use is to always bind different texture types to different texture units. OpenGL has well-defined rules for how all this works if you use the same texture unit, but using different texture units means that one part of my code becomes less dependent on what might be going on in other parts of it.

Once again: it’s easy, it’s lazy, but my code is simpler, each module is more robust against unwanted side-effects, and I get to spend more time writing new code than I spend debugging existing code.

Thanks for your response. Totally agree with you. In this case the hard way is a major overhaul/refactoring of someone else code which is not worth pursuing…

Happy to help! And this isn’t just the easy way out. This is the newer way, and the way that Vulkan requires it in Vulkan GLSL (if you’re thinking about that yet).

It makes your GLSL more portable if you’re largely doing things “the Vulkan way”.