Introspecting uniform blocks with instance names

Hello,
I have a question regarding introspection of the uniforms of a shader.

Given the following code :

#version 450
layout(std140, binding=0) uniform theInterface { 
  int x; 
};
void main() { gl_FragColor = vec4(x); }

introspecting the shader through glGetProgramInterfaceiv gives me “x” which is fine.

I can modify it this way :

#version 450
layout(std140, binding=0) uniform theInterface { 
  int x; 
} theInstance;
void main() { gl_FragColor = vec4(theInstance.x); }

but then, introspecting it gives me

theInterface.x 

which seems counter-intuitive, as theInterface.x is not a valid syntax in the shader ? What is the rationale for that ?

1 Like

Instance names are intended for usability within the shader that defines them. This is their only purpose.

Consider a Vertex Shader. The output gl_Position is part of the output block gl_PerVertex. Because it has no instance name, you can refer to gl_Position directly in the GLSL shader.

Now consider a Geometry Shader. It has an input block gl_PerVertex and an output block called gl_PerVertex. This is fine because the input and output interfaces are separate.

What isn’t fine is referring to the contents of these blocks. Both blocks have a gl_Position variable. But you need to be able to identify which one you’re talking about.

That’s where the instance name comes in. gl_in is the instance name of the input block of the GS, and the output block has no instance name. So gl_Position is always talking about the GS output block member, while gl_in[X].gl_Position is talking about the input variable.

Also, this allows blocks to be arrayed, which is important for the GS, since it takes multiple vertices.

You couldn’t use the block name, because the block name from the VS output needs to match the corresponding block name from the GS input. Well, you could use the block name for disambiguation, but then you’d break every shader made before GLSL 1.50, since none of them write to gl_PerVertex.gl_Position. And forcing that on every VS, even one that doesn’t get linked to a GS, is silly.

OK, yes, you could have some syntactic way of saying that this particular block’s members must be prefixed by the block name, while another block’s members need not be so prefixed. But what would that syntax look like? uniform layout(prefix) BlockName? uniform BlockName[1], which forces you to use BlockName[0] when referring to the members?

No, the developers decided to create instance names instead. Indeed, you’ll note that the syntax looks like this:

struct TypeName
{
  ...
} variableName;

variableName is an instance of TypeName; this is why the analogous syntax in GLSL blocks is called an “instance name”. This also makes for convenient array declaration syntax.

In a shader, instance names only exists as a disambiguation tool. Matching interface blocks are only required to have matching block names, not instance names.

Though buffer-backed interface blocks (BBIB) have a caveat to this. See, interfaces between two linked shader stages don’t appear in the program introspection API. So it’s OK to have an output block with an instance name in one stage, and its matching input block can have no instance name. If you link these shaders together, you can’t ask what the name of either set of members is, because program introspection only allows you to ask about the input/outputs to the entire program. And if they’re in separable programs, then the name of each is unambiguous: the output block+instance name will be BlockName.member, while the input block without an instance name will just be member.

For BBIBs in different stages that are intended to match, there is a problem. If you could have a VS use a BBIB with an instance name, and the GS use the same BBIB with no instance name, these are supposed to be matching blocks. There should only be one block… so how do you name its members?

The answer is that, in order for BBIBs to match, they must be consistent about instance name usage. They don’t have to use the same instance name, but they must all be using an instance name or none may use it.

But that’s a digression.

To answer your question, the block name is used in the interface because the instance name is considered a disambiguator in the shader. The instance name was chosen to disambiguate things, so it is not considered part of the shader interface. This allows matching blocks to use whatever instance name is appropriate to that local shader.