glGetProgramiv() Bug?

Hi Folks:

Should glGetProgramiv(…, GL_LINK_STATUS, &success) set success to 1 for the following vertex and fragment shader pair?

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out vec2 TexCoord; 

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);
	TexCoord = texCoord;	
}
#version 330 core

in vec2 TexCoords;

out vec4 color;

uniform sampler2D texture1;

void main()
{  
	vec4 texColor = texture(texture1, TexCoords);

	if(texColor.a < 0.1)
		discard;

	color = texColor;
}

See it?

It took me hours to notice the vertex shader had “out vec2 TexCoord;” and the fragment shader had “in vec2 TexCoords;”.

Of course I was searching other parts of the program to figure out why a texture wasn’t rendering.

Is this something that should have been caught by glGetProgramiv()?

  Thanks
  Larry

you mean the “s” in “TexCoords”: no, glGetProgramiv() doesnt throw an linking error, as a result the vertexshader passes the coords to the fragmentshader, but the fragmentshader doesnt care about it, it want (and receives) “TexCoords” which isnt provided by the vertexshader, so its undefined (or 0)

to avoid such errors, you can make use of “interface blocks”:

vertexshader:

out SomeNameHere {
   vec2 TexCoord;
} vs_out;

void main() {
   ...
   vs_out.TexCoord = in_TexCoord;
}

fragmentshader:

in SomeNameHere {
   vec2 TexCoords;
} fs_in;

void main() {
   vec4 texel = texture(tex1, fs_in.TexCoords);
   ...
}

this will give you a linking error, saying that the “interface blocks dont match”
changing TexCoords to TexCoord in the fragmentshader will eliminate the error, that means only the variables withing the { block } brackets have to match as well as the block name “SomeNameHere”, the “instance names” (here: vs_out and fs_in) dont have to match. that way you can be sure that the fragmentshader actually receives what the vertexshader passes through

Thanks Again John:

That mismatch in the names of the output and input causes the render to fail.

It seems like an easy catch. I’m surprised it’s not flagged in the link phase of the check.

Interface blocks is a topic in the “Advanced GLSL” tutorial. I haven’t gotten there yet.

As always, I appreciate your assistance.

  Larry

There is a topic in the wiki about interface matching.
Mainly:

mismatching interfaces between stages are linker errors. However, the interface between separable programs in a pipeline can only be checked at runtime, when the pipeline is used.
[…]
For loose variables, an output matches with an input if:

The two variables represent the same interface. This is determined by checking the following, in order (the first overrides the second):
    If both of the variables are given a layout(location) setting that is equivalent.
    If both variables have the same name (and neither variable has a layout(location) qualifier).
The two variables have types which match (separate program allow for some slight mismatching). If they are arrays, the element counts must match.
Have type qualifiers which match, as described below.

Since you (apparently) don’t use separable programs, errors should be reported during link-time, but only for mismatching interfaces.
Since you don’t use blocks, you end up with loose variables.
Since the two variables don’t have the same name, they don’t represent the same interface. Thus you don’t end-up with any interface mismatch.

Thanks Silence:

I’ve taken John Connor’s advice and now use interface blocks for my shaders.

It will be a couple of days before I get to the tutorial that introduces more advanced GLSL topics. I’ve learned so much about OpenGL, and I have so far to go.

I am curious about what you and the wiki are referring to as “separable programs”.

However, I’m consumed right now by getting my first framebuffer code working. An understanding of the details of shader compilation is valuable, and probably necessary to become competent in the use of OpenGL, but I need to focus on one task.

Thanks again for your advice.

  Larry

In OpenGL with GLSL you take a vertex shader, a fragment shader, and optionally other shaders, compile them, then link them together into a single program object. From that point onwards you operate using the program object.

The thing is, the linking step is purely a software construct of OpenGL with GLSL; other APIs don’t have it and even OpenGL with older assembly language vertex and fragment programs didn’t have it. In these APIs there is no program object, and you are free to change vertex shaders without also changing fragment shaders, for example. Shader stages are separate and independent of each other, and behaviour is well-defined for cases where a stage expects an input that the previous stage doesn’t provide (or provides an output that the next stage doesn’t consume). You can freely mix-and-match shaders and avoid some of the inevitable shader combination explosion.

Oddly enough, other APIs manage to do all of this without incurring any performance penalty, thereby indicating that the program object enforced by GLSL is not actually an optimization.

OpenGL provides similar functionality through the GL_ARB_separate_shader_objects extension. Oddly enough, despite every other API being able to handle this without incurring a performance penalty, it appears as though OpenGL can’t.

See the wiki and the specs.