diff --git a/Test/baseResults/spv.invariantAll.vert.out b/Test/baseResults/spv.invariantAll.vert.out new file mode 100644 index 000000000..ec5ad30ac --- /dev/null +++ b/Test/baseResults/spv.invariantAll.vert.out @@ -0,0 +1,55 @@ +spv.invariantAll.vert +// Module Version 10000 +// Generated by (magic number): 8000a +// Id's are bound by 25 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Vertex 4 "main" 13 17 + Source GLSL 450 + Name 4 "main" + Name 11 "gl_PerVertex" + MemberName 11(gl_PerVertex) 0 "gl_Position" + MemberName 11(gl_PerVertex) 1 "gl_PointSize" + MemberName 11(gl_PerVertex) 2 "gl_ClipDistance" + MemberName 11(gl_PerVertex) 3 "gl_CullDistance" + Name 13 "" + Name 17 "v" + MemberDecorate 11(gl_PerVertex) 0 Invariant + MemberDecorate 11(gl_PerVertex) 0 BuiltIn Position + MemberDecorate 11(gl_PerVertex) 1 Invariant + MemberDecorate 11(gl_PerVertex) 1 BuiltIn PointSize + MemberDecorate 11(gl_PerVertex) 2 Invariant + MemberDecorate 11(gl_PerVertex) 2 BuiltIn ClipDistance + MemberDecorate 11(gl_PerVertex) 3 Invariant + MemberDecorate 11(gl_PerVertex) 3 BuiltIn CullDistance + Decorate 11(gl_PerVertex) Block + Decorate 17(v) Location 0 + Decorate 17(v) Invariant + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypeInt 32 0 + 9: 8(int) Constant 1 + 10: TypeArray 6(float) 9 +11(gl_PerVertex): TypeStruct 7(fvec4) 6(float) 10 10 + 12: TypePointer Output 11(gl_PerVertex) + 13: 12(ptr) Variable Output + 14: TypeInt 32 1 + 15: 14(int) Constant 0 + 16: TypePointer Output 6(float) + 17(v): 16(ptr) Variable Output + 20: 6(float) Constant 0 + 21: 6(float) Constant 1065353216 + 23: TypePointer Output 7(fvec4) + 4(main): 2 Function None 3 + 5: Label + 18: 6(float) Load 17(v) + 19: 6(float) Load 17(v) + 22: 7(fvec4) CompositeConstruct 18 19 20 21 + 24: 23(ptr) AccessChain 13 15 + Store 24 22 + Return + FunctionEnd diff --git a/Test/spv.invariantAll.vert b/Test/spv.invariantAll.vert new file mode 100644 index 000000000..e094aa077 --- /dev/null +++ b/Test/spv.invariantAll.vert @@ -0,0 +1,10 @@ +#version 450 core +#pragma STDGL invariant(all) + +layout(location=0) out highp float v; + +void main() +{ + gl_Position = vec4(v, v, 0, 1); +} + diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index c2b9edcf6..f1c7d8480 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -327,6 +327,16 @@ void TParseContext::setAtomicCounterBlockDefaults(TType& block) const block.getQualifier().layoutMatrix = ElmRowMajor; } +void TParseContext::setInvariant(const TSourceLoc& loc, const char* builtin) { + TSymbol* symbol = symbolTable.find(builtin); + if (symbol && symbol->getType().getQualifier().isPipeOutput()) { + if (intermediate.inIoAccessed(builtin)) + warn(loc, "changing qualification after use", "invariant", builtin); + TSymbol* csymbol = symbolTable.copyUp(symbol); + csymbol->getWritableType().getQualifier().invariant = true; + } +} + void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& tokens) { #ifndef GLSLANG_WEB @@ -404,8 +414,33 @@ void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& intermediate.setUseVariablePointers(); } else if (tokens[0].compare("once") == 0) { warn(loc, "not implemented", "#pragma once", ""); - } else if (tokens[0].compare("glslang_binary_double_output") == 0) + } else if (tokens[0].compare("glslang_binary_double_output") == 0) { intermediate.setBinaryDoubleOutput(); + } else if (spvVersion.spv > 0 && tokens[0].compare("STDGL") == 0 && + tokens[1].compare("invariant") == 0 && tokens[3].compare("all") == 0) { + intermediate.setInvariantAll(); + // Set all builtin out variables invariant if declared + setInvariant(loc, "gl_Position"); + setInvariant(loc, "gl_PointSize"); + setInvariant(loc, "gl_ClipDistance"); + setInvariant(loc, "gl_CullDistance"); + setInvariant(loc, "gl_TessLevelOuter"); + setInvariant(loc, "gl_TessLevelInner"); + setInvariant(loc, "gl_PrimitiveID"); + setInvariant(loc, "gl_Layer"); + setInvariant(loc, "gl_ViewportIndex"); + setInvariant(loc, "gl_FragDepth"); + setInvariant(loc, "gl_SampleMask"); + setInvariant(loc, "gl_ClipVertex"); + setInvariant(loc, "gl_FrontColor"); + setInvariant(loc, "gl_BackColor"); + setInvariant(loc, "gl_FrontSecondaryColor"); + setInvariant(loc, "gl_BackSecondaryColor"); + setInvariant(loc, "gl_TexCoord"); + setInvariant(loc, "gl_FogFragCoord"); + setInvariant(loc, "gl_FragColor"); + setInvariant(loc, "gl_FragData"); + } #endif } @@ -3651,6 +3686,8 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q profileRequires(loc, ENoProfile, 130, nullptr, "out for stage outputs"); profileRequires(loc, EEsProfile, 300, nullptr, "out for stage outputs"); qualifier.storage = EvqVaryingOut; + if (intermediate.isInvariantAll()) + qualifier.invariant = true; break; case EvqInOut: qualifier.storage = EvqVaryingIn; diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index c9e633420..de4488465 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -241,6 +241,7 @@ protected: // override this to set the language-specific name virtual const char* getAtomicCounterBlockName() const { return ""; } virtual void setAtomicCounterBlockDefaults(TType&) const {} + virtual void setInvariant(const TSourceLoc& loc, const char* builtin) {} virtual void finalizeAtomicCounterBlockLayout(TVariable&) {} bool isAtomicCounterBlock(const TSymbol& symbol) { const TVariable* var = symbol.getAsVariable(); @@ -511,6 +512,7 @@ protected: virtual const char* getAtomicCounterBlockName() const override; virtual void finalizeAtomicCounterBlockLayout(TVariable&) override; virtual void setAtomicCounterBlockDefaults(TType& block) const override; + virtual void setInvariant(const TSourceLoc& loc, const char* builtin) override; public: // diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp index 42b416dba..9656e2e7e 100644 --- a/glslang/MachineIndependent/linkValidate.cpp +++ b/glslang/MachineIndependent/linkValidate.cpp @@ -316,6 +316,7 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit) MERGE_TRUE(useUnknownFormat); MERGE_TRUE(hlslOffsets); MERGE_TRUE(useStorageBuffer); + MERGE_TRUE(invariantAll); MERGE_TRUE(hlslIoMapping); // TODO: sourceFile diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 5cc9930ac..9e8af3898 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -291,6 +291,7 @@ public: numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false), invertY(false), useStorageBuffer(false), + invariantAll(false), nanMinMaxClamp(false), depthReplacing(false), uniqueId(0), @@ -560,6 +561,8 @@ public: void setUseStorageBuffer() { useStorageBuffer = true; } bool usingStorageBuffer() const { return useStorageBuffer; } + void setInvariantAll() { invariantAll = true; } + bool isInvariantAll() const { return invariantAll; } void setDepthReplacing() { depthReplacing = true; } bool isDepthReplacing() const { return depthReplacing; } bool setLocalSize(int dim, int size) @@ -1063,6 +1066,7 @@ protected: bool recursive; bool invertY; bool useStorageBuffer; + bool invariantAll; bool nanMinMaxClamp; // true if desiring min/max/clamp to favor non-NaN over NaN bool depthReplacing; int localSize[3]; diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp index 20683a686..3746557fd 100644 --- a/gtests/Spv.FromFile.cpp +++ b/gtests/Spv.FromFile.cpp @@ -363,6 +363,7 @@ INSTANTIATE_TEST_SUITE_P( "spv.intrinsicsSpirvLiteral.vert", "spv.intrinsicsSpirvStorageClass.rchit", "spv.intrinsicsSpirvType.rgen", + "spv.invariantAll.vert", "spv.layer.tese", "spv.layoutNested.vert", "spv.length.frag",