Ahoi. Reading this thread triggered my curiosity once again. So I tried my luck with redeclaration of built-in interface blocks and, if I haven’t fallen victim to my own incredible stupidity here, the GLSL compiler seems to violate a multitude of compilation/linkage rules from the spec (all quotes from the GLSL 4.30 Spec):
The gl_PerVertex block can be redeclared in a shader to explicitly indicate what subset of the fixed pipeline interface will be used. This is necessary to establish the interface between multiple programs. […] It must be a subset of the built-in members of gl_PerVertex.
First of all, the wording is awful. The words can and necessary don’t go well together. They can be redeclared when using non-separable programs, they are necessary, however, when using a program pipeline. Maybe a spec bug - maybe a driver. At least the driver seems to be sure that can isn’t the right wording. Anyway, using the following shaders separably works just fine, even though as per the GLSL spec it shouldn’t:
// vertex shader
#version 420
layout(location = 0) in vec4 position;
out gl_PerVertex
{
vec4 gl_Position;
vec2 wtf_AMD;
};
void main()
{
gl_Position = position;
wtf_AMD = position.xy;
}
// geometry shader
#version 420
layout(points) in;
layout(points, max_vertices = 1) out;
in gl_PerVertex
{
vec4 gl_Position;
vec2 wtf_AMD;
} gl_in[];
out gl_PerVertex
{
vec4 gl_Position;
float gl_PointSize;
};
void main()
{
gl_PointSize = 5.f;
gl_Position = gl_in[0].gl_Position + vec4(gl_in[0].wtf_AMD, 0.0, 0.0);
EmitVertex ();
EndPrimitive();
}
No complaints whatsoever - not even when insulting the compiler with a nasty “WTF”. Clearly, the vec2 is not a built-in member of gl_PerVertex and therefore does not belong to aforementioned subset.
If a built-in interface block is redeclared, it must appear in the shader before any use of any member included in the built-in declaration, or a compile-time error will result.
Unless my interpretation is wrong, this simply means, the block needs to appear before any use of any of its members. However, this compiles and works:
#version 420
in vec4 position;
void main()
{
gl_Position = position;
amd_WTF = position.xy;
}
out gl_PerVertex
{
vec4 gl_Position;
vec2 amd_WTF;
};
This seems to violate the spec on two counts… As I understand it, I should not be able to use a member of a redeclared interface prior to its redeclaration and I assumed this goes for gl_Position as well. However, the compiler will only complain about the vec2 not being declared at that point.
Now, what happens if we do all this with an old-school, linked program? The following will compile fine even though it clearly violates the rules of interface matching (which don’t only apply to separable programs):
Matched block names within an interface (as defined above) must match in terms of having the same number of declarations with the same sequence of types and the same sequence of member names, as well as having the same member-wise layout qualification (see next section).[…] Any mismatch will generate a link-time error.
Consider the following clearly mismatching interfaces:
// vertex shader
out gl_PerVertex
{
vec4 gl_Position;
float wtf_AMD_float;
vec2 wtf_AMD;
float wtf_Padding;
};
// geometry shader
in gl_PerVertex
{
vec4 gl_Position;
vec2 wtf_AMD;
float wtf_AMD_float;
} gl_in[];
The only thing that matches is the number of declarations. Neither the type sequence nor the sequence of names match. Two violations. Does the linker complain is it should? No. Actually it compiles, links and runs but generates no primitives - at least not until wtf_AMD_float is actually used:
// write position in the GS
gl_Position = gl_in[0].gl_Position + vec4(gl_in[0].wtf_AMD * gl_in[0].wtf_AMD_float, 0.0, 0.0);
This will link and run just as fine but, oh wonder, generate incorrect output primitives for which actual fragments are rasterized which can addtionally be controlled by adjusting the point size… It shouldn’t even link - and seriously, if for linked programs it also applies that the redeclared members must be a subset of the built-in members of gl_PerVertex, it should even compile IMHO. Too bad the spec doesn’t explicitly state that the latter actually should occur.
Please, someone tell me that I’m making some horrible mistakes above. Otherwise, the whole redeclaration thing seems broken as ****.
EDIT: Just some of it with 13.1 again. The first example simply flickers, i.e. sometimes it generates primtives and sometimes it doesn’t but the compiler/linker still don’t complain. The last example, ironically, generates the correct primitives. Obviously, 13.3 has regressed from incorrect to even more incorrect behavior.