diff --git a/Test/baseResults/iomap.crossStage.vk.2.vert.out b/Test/baseResults/iomap.crossStage.vk.2.vert.out new file mode 100755 index 00000000..2334df5c --- /dev/null +++ b/Test/baseResults/iomap.crossStage.vk.2.vert.out @@ -0,0 +1,313 @@ +iomap.crossStage.vk.2.vert +Shader version: 460 +0:? Sequence +0:8 Function Definition: main( ( global void) +0:8 Function Parameters: +0:10 Sequence +0:10 move second child to first child ( temp highp 4-component vector of float) +0:10 val: direct index for structure ( out highp 4-component vector of float) +0:10 'anon@0' ( out block{ out highp 4-component vector of float val}) +0:10 Constant: +0:10 0 (const uint) +0:10 Constant: +0:10 0.500000 +0:10 0.500000 +0:10 0.500000 +0:10 0.500000 +0:11 move second child to first child ( temp highp 4-component vector of float) +0:11 'color' ( smooth out highp 4-component vector of float) +0:11 Constant: +0:11 1.000000 +0:11 1.000000 +0:11 1.000000 +0:11 1.000000 +0:12 move second child to first child ( temp 4-component vector of float) +0:12 gl_Position: direct index for structure ( gl_Position 4-component vector of float Position) +0:12 'anon@1' ( out block{ gl_Position 4-component vector of float Position gl_Position, gl_PointSize float PointSize gl_PointSize, out unsized 1-element array of float ClipDistance gl_ClipDistance, out unsized 1-element array of float CullDistance gl_CullDistance}) +0:12 Constant: +0:12 0 (const uint) +0:12 Constant: +0:12 1.000000 +0:12 1.000000 +0:12 1.000000 +0:12 1.000000 +0:? Linker Objects +0:? 'anon@0' ( out block{ out highp 4-component vector of float val}) +0:? 'color' ( smooth out highp 4-component vector of float) +0:? 'anon@1' ( out block{ gl_Position 4-component vector of float Position gl_Position, gl_PointSize float PointSize gl_PointSize, out unsized 1-element array of float ClipDistance gl_ClipDistance, out unsized 1-element array of float CullDistance gl_CullDistance}) + +iomap.crossStage.vk.2.geom +Shader version: 460 +invocations = -1 +max_vertices = 3 +input primitive = points +output primitive = triangle_strip +0:? Sequence +0:23 Function Definition: main( ( global void) +0:23 Function Parameters: +0:25 Sequence +0:25 Sequence +0:25 Sequence +0:25 move second child to first child ( temp highp int) +0:25 'i' ( temp highp int) +0:25 Constant: +0:25 0 (const int) +0:25 Loop with condition tested first +0:25 Loop Condition +0:25 Compare Less Than ( temp bool) +0:25 'i' ( temp highp int) +0:25 Constant: +0:25 3 (const int) +0:25 Loop Body +0:26 Sequence +0:26 move second child to first child ( temp highp 4-component vector of float) +0:26 'colorOut' (layout( stream=0) out highp 4-component vector of float) +0:26 component-wise multiply ( temp highp 4-component vector of float) +0:26 indirect index ( temp highp 4-component vector of float) +0:26 'color' ( in 1-element array of highp 4-component vector of float) +0:26 'i' ( temp highp int) +0:26 val: direct index for structure ( in highp 4-component vector of float) +0:26 indirect index ( temp block{ in highp 4-component vector of float val}) +0:26 'vv' ( in 1-element array of block{ in highp 4-component vector of float val}) +0:26 'i' ( temp highp int) +0:26 Constant: +0:26 0 (const int) +0:27 move second child to first child ( temp highp 4-component vector of float) +0:27 vv2Val: direct index for structure (layout( stream=0) out highp 4-component vector of float) +0:27 'anon@0' (layout( stream=0) out block{layout( stream=0) out highp 4-component vector of float vv2Val}) +0:27 Constant: +0:27 0 (const uint) +0:27 Constant: +0:27 1.000000 +0:27 1.000000 +0:27 1.000000 +0:27 1.000000 +0:28 EmitVertex ( global void) +0:25 Loop Terminal Expression +0:25 Post-Increment ( temp highp int) +0:25 'i' ( temp highp int) +0:30 EndPrimitive ( global void) +0:? Linker Objects +0:? 'vgo1' ( in 1-element array of highp 4-component vector of float) +0:? 'color' ( in 1-element array of highp 4-component vector of float) +0:? 'colorOut' (layout( stream=0) out highp 4-component vector of float) +0:? 'vv' ( in 1-element array of block{ in highp 4-component vector of float val}) +0:? 'anon@0' (layout( stream=0) out block{layout( stream=0) out highp 4-component vector of float vv2Val}) + +iomap.crossStage.vk.2.frag +Shader version: 460 +gl_FragCoord origin is upper left +0:? Sequence +0:19 Function Definition: main( ( global void) +0:19 Function Parameters: +0:21 Sequence +0:21 move second child to first child ( temp highp 4-component vector of float) +0:21 'fragColor' ( out highp 4-component vector of float) +0:21 add ( temp highp 4-component vector of float) +0:21 'colorOut' ( smooth in highp 4-component vector of float) +0:21 component-wise multiply ( temp highp 4-component vector of float) +0:21 component-wise multiply ( temp highp 4-component vector of float) +0:21 component-wise multiply ( temp highp 4-component vector of float) +0:21 'unsetColor' ( smooth in highp 4-component vector of float) +0:21 Construct vec4 ( temp highp 4-component vector of float) +0:21 vector swizzle ( temp highp 4-component vector of float) +0:21 val: direct index for structure ( in highp 2-component vector of float) +0:21 'iVert' ( in block{ in highp 2-component vector of float val}) +0:21 Constant: +0:21 0 (const int) +0:21 Sequence +0:21 Constant: +0:21 0 (const int) +0:21 Constant: +0:21 0 (const int) +0:21 Constant: +0:21 1 (const int) +0:21 Constant: +0:21 1 (const int) +0:21 Construct vec4 ( temp highp 4-component vector of float) +0:21 vector swizzle ( temp highp 4-component vector of float) +0:21 val2: direct index for structure ( in highp 2-component vector of float) +0:21 'anon@0' ( in block{ in highp 2-component vector of float val2}) +0:21 Constant: +0:21 0 (const uint) +0:21 Sequence +0:21 Constant: +0:21 0 (const int) +0:21 Constant: +0:21 0 (const int) +0:21 Constant: +0:21 1 (const int) +0:21 Constant: +0:21 1 (const int) +0:22 'vv2Val' ( smooth in highp 4-component vector of float) +0:? Linker Objects +0:? 'unsetColor' ( smooth in highp 4-component vector of float) +0:? 'colorOut' ( smooth in highp 4-component vector of float) +0:? 'fragColor' ( out highp 4-component vector of float) +0:? 'iVert' ( in block{ in highp 2-component vector of float val}) +0:? 'anon@0' ( in block{ in highp 2-component vector of float val2}) +0:? 'vv2Val' ( smooth in highp 4-component vector of float) + + +Linked vertex stage: + + +Linked geometry stage: + + +Linked fragment stage: + +ERROR: Linking vertex and geometry stages: Input 'vgo1' in geometry shader has no corresponding output in vertex shader. +ERROR: Linking geometry and fragment stages: Input 'unsetColor' in fragment shader has no corresponding output in geometry shader. +ERROR: Linking geometry and fragment stages: Input 'Vertex' in fragment shader has no corresponding output in geometry shader. +ERROR: Linking geometry and fragment stages: Input 'Vertex2' in fragment shader has no corresponding output in geometry shader. +ERROR: Linking geometry and fragment stages: Input 'vv2Val' in fragment shader has no corresponding output in geometry shader. + +Shader version: 460 +0:? Sequence +0:8 Function Definition: main( ( global void) +0:8 Function Parameters: +0:10 Sequence +0:10 move second child to first child ( temp highp 4-component vector of float) +0:10 val: direct index for structure ( out highp 4-component vector of float) +0:10 'anon@0' ( out block{ out highp 4-component vector of float val}) +0:10 Constant: +0:10 0 (const uint) +0:10 Constant: +0:10 0.500000 +0:10 0.500000 +0:10 0.500000 +0:10 0.500000 +0:11 move second child to first child ( temp highp 4-component vector of float) +0:11 'color' ( smooth out highp 4-component vector of float) +0:11 Constant: +0:11 1.000000 +0:11 1.000000 +0:11 1.000000 +0:11 1.000000 +0:12 move second child to first child ( temp 4-component vector of float) +0:12 gl_Position: direct index for structure ( gl_Position 4-component vector of float Position) +0:12 'anon@1' ( out block{ gl_Position 4-component vector of float Position gl_Position, gl_PointSize float PointSize gl_PointSize, out 1-element array of float ClipDistance gl_ClipDistance, out 1-element array of float CullDistance gl_CullDistance}) +0:12 Constant: +0:12 0 (const uint) +0:12 Constant: +0:12 1.000000 +0:12 1.000000 +0:12 1.000000 +0:12 1.000000 +0:? Linker Objects +0:? 'anon@0' ( out block{ out highp 4-component vector of float val}) +0:? 'color' ( smooth out highp 4-component vector of float) +0:? 'anon@1' ( out block{ gl_Position 4-component vector of float Position gl_Position, gl_PointSize float PointSize gl_PointSize, out 1-element array of float ClipDistance gl_ClipDistance, out 1-element array of float CullDistance gl_CullDistance}) +Shader version: 460 +invocations = 1 +max_vertices = 3 +input primitive = points +output primitive = triangle_strip +0:? Sequence +0:23 Function Definition: main( ( global void) +0:23 Function Parameters: +0:25 Sequence +0:25 Sequence +0:25 Sequence +0:25 move second child to first child ( temp highp int) +0:25 'i' ( temp highp int) +0:25 Constant: +0:25 0 (const int) +0:25 Loop with condition tested first +0:25 Loop Condition +0:25 Compare Less Than ( temp bool) +0:25 'i' ( temp highp int) +0:25 Constant: +0:25 3 (const int) +0:25 Loop Body +0:26 Sequence +0:26 move second child to first child ( temp highp 4-component vector of float) +0:26 'colorOut' (layout( stream=0) out highp 4-component vector of float) +0:26 component-wise multiply ( temp highp 4-component vector of float) +0:26 indirect index ( temp highp 4-component vector of float) +0:26 'color' ( in 1-element array of highp 4-component vector of float) +0:26 'i' ( temp highp int) +0:26 val: direct index for structure ( in highp 4-component vector of float) +0:26 indirect index ( temp block{ in highp 4-component vector of float val}) +0:26 'vv' ( in 1-element array of block{ in highp 4-component vector of float val}) +0:26 'i' ( temp highp int) +0:26 Constant: +0:26 0 (const int) +0:27 move second child to first child ( temp highp 4-component vector of float) +0:27 vv2Val: direct index for structure (layout( stream=0) out highp 4-component vector of float) +0:27 'anon@0' (layout( stream=0) out block{layout( stream=0) out highp 4-component vector of float vv2Val}) +0:27 Constant: +0:27 0 (const uint) +0:27 Constant: +0:27 1.000000 +0:27 1.000000 +0:27 1.000000 +0:27 1.000000 +0:28 EmitVertex ( global void) +0:25 Loop Terminal Expression +0:25 Post-Increment ( temp highp int) +0:25 'i' ( temp highp int) +0:30 EndPrimitive ( global void) +0:? Linker Objects +0:? 'vgo1' ( in 1-element array of highp 4-component vector of float) +0:? 'color' ( in 1-element array of highp 4-component vector of float) +0:? 'colorOut' (layout( stream=0) out highp 4-component vector of float) +0:? 'vv' ( in 1-element array of block{ in highp 4-component vector of float val}) +0:? 'anon@0' (layout( stream=0) out block{layout( stream=0) out highp 4-component vector of float vv2Val}) +Shader version: 460 +gl_FragCoord origin is upper left +0:? Sequence +0:19 Function Definition: main( ( global void) +0:19 Function Parameters: +0:21 Sequence +0:21 move second child to first child ( temp highp 4-component vector of float) +0:21 'fragColor' ( out highp 4-component vector of float) +0:21 add ( temp highp 4-component vector of float) +0:21 'colorOut' ( smooth in highp 4-component vector of float) +0:21 component-wise multiply ( temp highp 4-component vector of float) +0:21 component-wise multiply ( temp highp 4-component vector of float) +0:21 component-wise multiply ( temp highp 4-component vector of float) +0:21 'unsetColor' ( smooth in highp 4-component vector of float) +0:21 Construct vec4 ( temp highp 4-component vector of float) +0:21 vector swizzle ( temp highp 4-component vector of float) +0:21 val: direct index for structure ( in highp 2-component vector of float) +0:21 'iVert' ( in block{ in highp 2-component vector of float val}) +0:21 Constant: +0:21 0 (const int) +0:21 Sequence +0:21 Constant: +0:21 0 (const int) +0:21 Constant: +0:21 0 (const int) +0:21 Constant: +0:21 1 (const int) +0:21 Constant: +0:21 1 (const int) +0:21 Construct vec4 ( temp highp 4-component vector of float) +0:21 vector swizzle ( temp highp 4-component vector of float) +0:21 val2: direct index for structure ( in highp 2-component vector of float) +0:21 'anon@0' ( in block{ in highp 2-component vector of float val2}) +0:21 Constant: +0:21 0 (const uint) +0:21 Sequence +0:21 Constant: +0:21 0 (const int) +0:21 Constant: +0:21 0 (const int) +0:21 Constant: +0:21 1 (const int) +0:21 Constant: +0:21 1 (const int) +0:22 'vv2Val' ( smooth in highp 4-component vector of float) +0:? Linker Objects +0:? 'unsetColor' ( smooth in highp 4-component vector of float) +0:? 'colorOut' ( smooth in highp 4-component vector of float) +0:? 'fragColor' ( out highp 4-component vector of float) +0:? 'iVert' ( in block{ in highp 2-component vector of float val}) +0:? 'anon@0' ( in block{ in highp 2-component vector of float val2}) +0:? 'vv2Val' ( smooth in highp 4-component vector of float) +Mismatched cross-stage IO + +Validation failed +SPIR-V is not generated for failed compile or link diff --git a/Test/iomap.crossStage.vk.2.frag b/Test/iomap.crossStage.vk.2.frag new file mode 100755 index 00000000..e34a9a9b --- /dev/null +++ b/Test/iomap.crossStage.vk.2.frag @@ -0,0 +1,24 @@ +#version 460 + +in vec4 unsetColor; +in vec4 colorOut; +out vec4 fragColor; + +in Vertex +{ + vec2 val; +} iVert; + +in Vertex2 +{ + vec2 val2; +}; + +in vec4 vv2Val; + +void main() +{ + fragColor = colorOut + unsetColor * vec4(iVert.val.xxyy) * vec4(val2.xxyy) * + vv2Val; +} + diff --git a/Test/iomap.crossStage.vk.2.geom b/Test/iomap.crossStage.vk.2.geom new file mode 100755 index 00000000..11e7b9ab --- /dev/null +++ b/Test/iomap.crossStage.vk.2.geom @@ -0,0 +1,32 @@ +#version 460 + +layout(points) in; +layout(triangle_strip, max_vertices=3) out; + +// Not written by vertex shader +in vec4 vgo1[]; + +in vec4 color[]; + +out vec4 colorOut; + +in VV +{ + vec4 val; +} vv[]; + +out VV2 +{ + vec4 vv2Val; +}; + +void main() +{ + for (int i = 0; i < 3; i++) { + colorOut = color[i] * vv[i].val; + vv2Val = vec4(1.0); + EmitVertex(); + } + EndPrimitive(); +} + diff --git a/Test/iomap.crossStage.vk.2.vert b/Test/iomap.crossStage.vk.2.vert new file mode 100755 index 00000000..8788ec2c --- /dev/null +++ b/Test/iomap.crossStage.vk.2.vert @@ -0,0 +1,14 @@ +#version 460 + +out VV +{ + vec4 val; +}; +out vec4 color; +void main() +{ + val = vec4(0.5); + color = vec4(1.0); + gl_Position = vec4(1.0); +} + diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp index 81857b24..182a6775 100644 --- a/glslang/MachineIndependent/linkValidate.cpp +++ b/glslang/MachineIndependent/linkValidate.cpp @@ -113,6 +113,28 @@ void TIntermediate::mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects, unit.getStage()); } +static inline bool isSameInterface(TIntermSymbol* symbol, EShLanguage stage, TIntermSymbol* unitSymbol, EShLanguage unitStage) { + return // 1) same stage and same shader interface + (stage == unitStage && symbol->getType().getShaderInterface() == unitSymbol->getType().getShaderInterface()) || + // 2) accross stages and both are uniform or buffer + (symbol->getQualifier().storage == EvqUniform && unitSymbol->getQualifier().storage == EvqUniform) || + (symbol->getQualifier().storage == EvqBuffer && unitSymbol->getQualifier().storage == EvqBuffer) || + // 3) in/out matched across stage boundary + (stage < unitStage && symbol->getQualifier().storage == EvqVaryingOut && unitSymbol->getQualifier().storage == EvqVaryingIn) || + (unitStage < stage && symbol->getQualifier().storage == EvqVaryingIn && unitSymbol->getQualifier().storage == EvqVaryingOut); +} + +static bool isSameSymbol(TIntermSymbol* symbol1, EShLanguage stage1, TIntermSymbol* symbol2, EShLanguage stage2) { + // If they are both blocks in the same shader interface, + // match by the block-name, not the identifier name. + if (symbol1->getType().getBasicType() == EbtBlock && symbol2->getType().getBasicType() == EbtBlock) { + if (isSameInterface(symbol1, stage1, symbol2, stage2)) { + return symbol1->getType().getTypeName() == symbol2->getType().getTypeName(); + } + } else if (symbol1->getName() == symbol2->getName()) + return true; + return false; +} // // do error checking on the shader boundary in / out vars // @@ -137,7 +159,32 @@ void TIntermediate::checkStageIO(TInfoSink& infoSink, TIntermediate& unit) { // do matching and error checking mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects, unit.getStage()); - // TODO: final check; make sure that any statically used `in` have matching `out` written to + // Check that all of our inputs have matching outputs from the previous stage. + // Only do this for Vulkan, since GL_ARB_separate_shader_objects allows for + // the in/out to not match + if (spvVersion.vulkan > 0) { + for (auto& nextStageInterm : unitLinkerObjects) { + auto* nextStageSymbol = nextStageInterm->getAsSymbolNode(); + bool found = false; + for (auto& curStageInterm : linkerObjects) { + if (isSameSymbol(curStageInterm->getAsSymbolNode(), getStage(), nextStageSymbol, unit.getStage())) { + found = true; + break; + } + } + if (!found) { + TString errmsg; + errmsg.append("Input '"); + if (nextStageSymbol->getType().getBasicType() == EbtBlock) + errmsg.append(nextStageSymbol->getType().getTypeName()); + else + errmsg.append(nextStageSymbol->getName()); + errmsg.append("' in ").append(StageName(unit.getStage())); + errmsg.append(" shader has no corresponding output in ").append(StageName(getStage())).append(" shader."); + error(infoSink, errmsg.c_str(), unit.getStage()); + } + } + } } void TIntermediate::mergeCallGraphs(TInfoSink& infoSink, TIntermediate& unit) @@ -511,17 +558,6 @@ void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, c globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1); } -static inline bool isSameInterface(TIntermSymbol* symbol, EShLanguage stage, TIntermSymbol* unitSymbol, EShLanguage unitStage) { - return // 1) same stage and same shader interface - (stage == unitStage && symbol->getType().getShaderInterface() == unitSymbol->getType().getShaderInterface()) || - // 2) accross stages and both are uniform or buffer - (symbol->getQualifier().storage == EvqUniform && unitSymbol->getQualifier().storage == EvqUniform) || - (symbol->getQualifier().storage == EvqBuffer && unitSymbol->getQualifier().storage == EvqBuffer) || - // 3) in/out matched across stage boundary - (stage < unitStage && symbol->getQualifier().storage == EvqVaryingOut && unitSymbol->getQualifier().storage == EvqVaryingIn) || - (unitStage < stage && symbol->getQualifier().storage == EvqVaryingIn && unitSymbol->getQualifier().storage == EvqVaryingOut); -} - // // Global Unfiform block stores any default uniforms (i.e. uniforms without a block) // If two linked stages declare the same member, they are meant to be the same uniform @@ -707,24 +743,18 @@ void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& lin // Error check and merge the linker objects (duplicates should not be created) std::size_t initialNumLinkerObjects = linkerObjects.size(); for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) { + TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode(); bool merge = true; + + // Don't merge inputs backwards into previous stages + if (getStage() != unitStage && unitSymbol->getQualifier().storage == EvqVaryingIn) + merge = false; + for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) { TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode(); - TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode(); assert(symbol && unitSymbol); - bool isSameSymbol = false; - // If they are both blocks in the same shader interface, - // match by the block-name, not the identifier name. - if (symbol->getType().getBasicType() == EbtBlock && unitSymbol->getType().getBasicType() == EbtBlock) { - if (isSameInterface(symbol, getStage(), unitSymbol, unitStage)) { - isSameSymbol = symbol->getType().getTypeName() == unitSymbol->getType().getTypeName(); - } - } - else if (symbol->getName() == unitSymbol->getName()) - isSameSymbol = true; - - if (isSameSymbol) { + if (isSameSymbol(symbol, getStage(), unitSymbol, unitStage)) { // filter out copy merge = false; diff --git a/gtests/GlslMapIO.FromFile.cpp b/gtests/GlslMapIO.FromFile.cpp index 1dba5c0c..9c3c8be5 100644 --- a/gtests/GlslMapIO.FromFile.cpp +++ b/gtests/GlslMapIO.FromFile.cpp @@ -345,6 +345,7 @@ INSTANTIATE_TEST_SUITE_P( {{"iomap.variableOutBlockIn.2.vert", "iomap.variableOutBlockIn.geom"}, Semantics::OpenGL}, // vulkan semantics {{"iomap.crossStage.vk.vert", "iomap.crossStage.vk.geom", "iomap.crossStage.vk.frag" }, Semantics::Vulkan}, + {{"iomap.crossStage.vk.2.vert", "iomap.crossStage.vk.2.geom", "iomap.crossStage.vk.2.frag" }, Semantics::Vulkan}, })) ); // clang-format on