Shader communication fail

I have no idea what is going on or how to approach to solve it.

Given:


#version 450
#pragma shader_stage(geometry)
#extension GL_ARB_separate_shader_objects : enable

layout(points) in;
layout(triangle_strip, max_vertices=4) out;
in Vert { vec4 tc, color; vec3 mrWhiteS; } sIn[1];
out Frag { noperspective vec2 tc; flat vec4 color; flat vec3 mrWhiteS; } sOut;

void main() {
    vec4 pos = gl_in[0].gl_Position, tc = sIn[0].tc;
    sOut.color = sIn[0].color;
    //sOut.color = vec4(1.0); <-- makes no difference
    sOut.mrWhiteS = sIn[0].mrWhiteS;
    sOut.tc = tc.xy; gl_Position = vec4(pos.xy, 0.0, 1.0); EmitVertex(); // x0 y0
    sOut.tc = tc.zy; gl_Position = vec4(pos.zy, 0.0, 1.0); EmitVertex(); // x1 y0
    sOut.tc = tc.xw; gl_Position = vec4(pos.xw, 0.0, 1.0); EmitVertex(); // x0 y1
    sOut.tc = tc.zw; gl_Position = vec4(pos.zw, 0.0, 1.0); EmitVertex(); // x1 y1
}

and:


#version 450
#pragma shader_stage(fragment)
#extension GL_ARB_separate_shader_objects : enable

layout (set=0, binding=0) uniform sampler2D image;
in Frag { noperspective vec2 tc; flat vec4 color; flat vec3 mrWhiteS; } sIn;
layout(location=0) out vec4 fbColor;

void main() {
    float val = texture(image, sIn.tc).r;
    // fbColor = vec4(val);  <-- gives expected results. "tc" comes over fine.
    fbColor = sIn.color; // <-- always black
}

(vertex shader code omitted for brevity)

Compiled with VulkanSDK shaderc.
Validation layer is happy.
Render is correct as far as vertex positions and texture coordinates / texturing are concerned.

BUT. “color” and “mrWhiteS” are completely 0’ed out when they reach fragment shader whereas “tc” comes over fine.

Renaming “sIn” and “sOut” to match the name in the respective other stage makes no difference (afaicr from spec - it indeed should not make any difference).

Worked fine in OpenGL (without the vulkan extra explicit binding in shader code).

What is wrong? I’m completely lost.

Mystery solved. Location for the interface blocks is mandatory or it will use whatever happens to be there (tc coming over was an accident - ie. managed to get other random crap to pass over instead also).

So:


out Frag { noperspective vec2 tc; flat vec4 color; flat vec3 mrWhiteS; } sOut; // this will not work
layout(location=0) out Frag { noperspective vec2 tc; flat vec4 color; flat vec3 mrWhiteS; } sOut; // this will work - location is strictly mandatory

// same for other interface blocks