diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 4d3c4b90..f2b786eb 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -403,6 +403,7 @@ public: // drop qualifiers that don't belong in a temporary variable void makeTemporary() { + semanticName = nullptr; storage = EvqTemporary; builtIn = EbvNone; clearInterstage(); @@ -451,6 +452,7 @@ public: specConstant = false; } + const char* semanticName; TStorageQualifier storage : 6; TBuiltInVariable builtIn : 8; TPrecisionQualifier precision : 3; diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index ea24000f..162e400b 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -2,5 +2,5 @@ // For the version, it uses the latest git tag followed by the number of commits. // For the date, it uses the current date (when then script is run). -#define GLSLANG_REVISION "Overload400-PrecQual.1911" +#define GLSLANG_REVISION "Overload400-PrecQual.1914" #define GLSLANG_DATE "14-Mar-2017" diff --git a/glslang/MachineIndependent/iomapper.cpp b/glslang/MachineIndependent/iomapper.cpp index 07aa4762..bebf775d 100644 --- a/glslang/MachineIndependent/iomapper.cpp +++ b/glslang/MachineIndependent/iomapper.cpp @@ -66,11 +66,14 @@ namespace glslang { struct TVarEntryInfo { - int id; - TIntermSymbol* symbol; - bool live; - int newBinding; - int newSet; + int id; + TIntermSymbol* symbol; + bool live; + int newBinding; + int newSet; + int newLocation; + int newComponent; + int newIndex; struct TOrderById { @@ -113,70 +116,109 @@ typedef std::vector TVarLiveMap; class TVarGatherTraverser : public TLiveTraverser { public: - TVarGatherTraverser(const TIntermediate& i, TVarLiveMap& vars, bool traverseDeadCode) + TVarGatherTraverser(const TIntermediate& i, bool traverseDeadCode, TVarLiveMap& inList, TVarLiveMap& outList, TVarLiveMap& uniformList) : TLiveTraverser(i, traverseDeadCode, true, true, false) - , varLiveList(vars) + , inputList(inList) + , outputList(outList) + , uniformList(uniformList) { } virtual void visitSymbol(TIntermSymbol* base) { - if (base->getType().getQualifier().isUniformOrBuffer()) { + TVarLiveMap* target = nullptr; + if (base->getQualifier().storage == EvqVaryingIn) + target = &inputList; + else if (base->getQualifier().storage == EvqVaryingOut) + target = &outputList; + else if (base->getQualifier().isUniformOrBuffer()) + target = &uniformList; + + if (target) { TVarEntryInfo ent = { base->getId(), base, !traverseAll }; - TVarLiveMap::iterator at = std::lower_bound(varLiveList.begin(), varLiveList.end(), ent, TVarEntryInfo::TOrderById()); - if (at != varLiveList.end() && at->id == ent.id) + TVarLiveMap::iterator at = std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById()); + if (at != target->end() && at->id == ent.id) at->live = at->live || !traverseAll; // update live state else - varLiveList.insert(at, ent); + target->insert(at, ent); } } private: - TVarLiveMap& varLiveList; + TVarLiveMap& inputList; + TVarLiveMap& outputList; + TVarLiveMap& uniformList; }; class TVarSetTraverser : public TLiveTraverser { public: - TVarSetTraverser(const TIntermediate& i, const TVarLiveMap& vars) + TVarSetTraverser(const TIntermediate& i, const TVarLiveMap& inList, const TVarLiveMap& outList, const TVarLiveMap& uniformList) : TLiveTraverser(i, true, true, true, false) - , varLiveList(vars) + , inputList(inList) + , outputList(outList) + , uniformList(uniformList) { } virtual void visitSymbol(TIntermSymbol* base) { - TVarEntryInfo ent = { base->getId() }; - TVarLiveMap::const_iterator at = std::lower_bound(varLiveList.begin(), varLiveList.end(), ent, TVarEntryInfo::TOrderById()); - if (at == varLiveList.end()) + const TVarLiveMap* source; + if (base->getQualifier().storage == EvqVaryingIn) + source = &inputList; + else if (base->getQualifier().storage == EvqVaryingOut) + source = &outputList; + else if (base->getQualifier().isUniformOrBuffer()) + source = &uniformList; + else return; - if (!(at->id == ent.id)) + + TVarEntryInfo ent = { base->getId() }; + TVarLiveMap::const_iterator at = std::lower_bound(source->begin(), source->end(), ent, TVarEntryInfo::TOrderById()); + if (at == source->end()) + return; + + if (at->id != ent.id) return; if (at->newBinding != -1) base->getWritableType().getQualifier().layoutBinding = at->newBinding; if (at->newSet != -1) base->getWritableType().getQualifier().layoutSet = at->newSet; + if (at->newLocation != -1) + base->getWritableType().getQualifier().layoutLocation = at->newLocation; + if (at->newComponent != -1) + base->getWritableType().getQualifier().layoutComponent = at->newComponent; + if (at->newIndex != -1) + base->getWritableType().getQualifier().layoutIndex = at->newIndex; } private: - const TVarLiveMap& varLiveList; + const TVarLiveMap& inputList; + const TVarLiveMap& outputList; + const TVarLiveMap& uniformList; }; -struct TResolverAdaptor +struct TResolverUniformAdaptor { - TResolverAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e) - : stage(s) - , resolver(r) + TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e, TIntermediate& interm) + : resolver(r) + , stage(s) , infoSink(i) , error(e) + , intermediate(interm) { } inline void operator()(TVarEntryInfo& ent) { + ent.newLocation = -1; + ent.newComponent = -1; + ent.newBinding = -1; + ent.newSet = -1; + ent.newIndex = -1; const bool isValid = resolver.validateBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live); if (isValid) { ent.newBinding = resolver.resolveBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live); @@ -209,15 +251,69 @@ struct TResolverAdaptor TIoMapResolver& resolver; TInfoSink& infoSink; bool& error; + TIntermediate& intermediate; private: - TResolverAdaptor& operator=(TResolverAdaptor&); + TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&); +}; + +struct TResolverInOutAdaptor +{ + TResolverInOutAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e, TIntermediate& interm) + : resolver(r) + , stage(s) + , infoSink(i) + , error(e) + , intermediate(interm) + { + } + + inline void operator()(TVarEntryInfo& ent) + { + ent.newLocation = -1; + ent.newComponent = -1; + ent.newBinding = -1; + ent.newSet = -1; + ent.newIndex = -1; + const bool isValid = resolver.validateInOut(stage, + ent.symbol->getName().c_str(), + ent.symbol->getType(), + ent.live); + if (isValid) { + ent.newLocation = resolver.resolveInOutLocation(stage, + ent.symbol->getName().c_str(), + ent.symbol->getType(), + ent.live); + ent.newComponent = resolver.resolveInOutComponent(stage, + ent.symbol->getName().c_str(), + ent.symbol->getType(), + ent.live); + ent.newIndex = resolver.resolveInOutIndex(stage, + ent.symbol->getName().c_str(), + ent.symbol->getType(), + ent.live); + } else { + TString errorMsg = "Invalid shader In/Out variable semantic: "; + errorMsg += ent.symbol->getType().getQualifier().semanticName; + infoSink.info.message(EPrefixInternalError, errorMsg.c_str()); + error = true; + } + } + + EShLanguage stage; + TIoMapResolver& resolver; + TInfoSink& infoSink; + bool& error; + TIntermediate& intermediate; + +private: + TResolverInOutAdaptor& operator=(TResolverInOutAdaptor&); }; /* * Basic implementation of glslang::TIoMapResolver that replaces the - * previous offset behaviour. - * It does the same, uses the offsets for th corresponding uniform + * previous offset behavior. + * It does the same, uses the offsets for the corresponding uniform * types. Also respects the EOptionAutoMapBindings flag and binds * them if needed. */ @@ -348,6 +444,23 @@ struct TDefaultIoResolver : public glslang::TIoMapResolver return type.getQualifier().layoutSet; return 0; } + + bool validateInOut(EShLanguage stage, const char* name, const TType& type, bool is_live) override + { + return true; + } + int resolveInOutLocation(EShLanguage stage, const char* name, const TType& type, bool is_live) override + { + return -1; + } + int resolveInOutComponent(EShLanguage stage, const char* name, const TType& type, bool is_live) override + { + return -1; + } + int resolveInOutIndex(EShLanguage stage, const char* name, const TType& type, bool is_live) override + { + return -1; + } }; // Map I/O variables to provided offsets, and make bindings for @@ -386,9 +499,9 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSi resolver = &defaultResolver; } - TVarLiveMap varMap; - TVarGatherTraverser iter_binding_all(intermediate, varMap, true); - TVarGatherTraverser iter_binding_live(intermediate, varMap, false); + TVarLiveMap inVarMap, outVarMap, uniformVarMap; + TVarGatherTraverser iter_binding_all(intermediate, true, inVarMap, outVarMap, uniformVarMap); + TVarGatherTraverser iter_binding_live(intermediate, false, inVarMap, outVarMap, uniformVarMap); root->traverse(&iter_binding_all); iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str()); @@ -400,16 +513,19 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSi } // sort entries by priority. see TVarEntryInfo::TOrderByPriority for info. - std::sort(varMap.begin(), varMap.end(), TVarEntryInfo::TOrderByPriority()); + std::sort(uniformVarMap.begin(), uniformVarMap.end(), TVarEntryInfo::TOrderByPriority()); bool hadError = false; - TResolverAdaptor doResolve(stage, *resolver, infoSink, hadError); - std::for_each(varMap.begin(), varMap.end(), doResolve); + TResolverUniformAdaptor uniformResolve(stage, *resolver, infoSink, hadError, intermediate); + TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError, intermediate); + std::for_each(inVarMap.begin(), inVarMap.end(), inOutResolve); + std::for_each(outVarMap.begin(), outVarMap.end(), inOutResolve); + std::for_each(uniformVarMap.begin(), uniformVarMap.end(), uniformResolve); if (!hadError) { // sort by id again, so we can use lower bound to find entries - std::sort(varMap.begin(), varMap.end(), TVarEntryInfo::TOrderById()); - TVarSetTraverser iter_iomap(intermediate, varMap); + std::sort(uniformVarMap.begin(), uniformVarMap.end(), TVarEntryInfo::TOrderById()); + TVarSetTraverser iter_iomap(intermediate, inVarMap, outVarMap, uniformVarMap); root->traverse(&iter_iomap); } diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 34940a69..392a2ab0 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -423,6 +423,11 @@ public: bool getGeoPassthroughEXT() const { return geoPassthroughEXT; } #endif + const char* addSemanticName(const TString& name) + { + return semanticNameSet.insert(name).first->c_str(); + } + protected: TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&); void error(TInfoSink& infoSink, const char*); @@ -501,6 +506,7 @@ protected: std::vector usedAtomics; // sets of bindings used by atomic counters std::vector xfbBuffers; // all the data we need to track per xfb buffer std::unordered_set usedConstantId; // specialization constant ids used + std::set semanticNameSet; private: void operator=(TIntermediate&); // prevent assignments diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h index 8aa9baa3..8d8abd77 100644 --- a/glslang/Public/ShaderLang.h +++ b/glslang/Public/ShaderLang.h @@ -452,10 +452,12 @@ class TIoMapper; // and resolveSet are invoked to resolve the binding and descriptor // set index respectively. // Invocations happen in a particular order: -// 1) var with binding and set already defined -// 2) var with binding but no set defined -// 3) var with set but no binding defined -// 4) var with no binding and no set defined +// 1) all shader inputs +// 2) all shader outputs +// 3) all uniforms with binding and set already defined +// 4) all uniforms with binding but no set defined +// 5) all uniforms with set but no binding defined +// 6) all uniforms with no binding and no set defined // // NOTE: that still limit checks are applied to bindings and sets // and may result in an error. @@ -473,6 +475,18 @@ public: // Should return a value >= 0 if the current set should be overriden. // Return -1 if the current set (including no set) should be kept. virtual int resolveSet(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Should return true if the resuling/current setup would be ok. + // Basic idea is to do aliasing checks and reject invalid semantic names. + virtual bool validateInOut(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Should return a value >= 0 if the current location should be overriden. + // Return -1 if the current location (including no location) should be kept. + virtual int resolveInOutLocation(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Should return a value >= 0 if the current component index should be overriden. + // Return -1 if the current component index (including no index) should be kept. + virtual int resolveInOutComponent(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; + // Should return a value >= 0 if the current color index should be overriden. + // Return -1 if the current color index (including no index) should be kept. + virtual int resolveInOutIndex(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0; }; // Make one TProgram per set of shaders that will get linked together. Add all diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index 166141b3..7a0172c8 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -3528,7 +3528,9 @@ bool HlslGrammar::acceptPostDecls(TQualifier& qualifier) parseContext.handleRegister(registerDesc.loc, qualifier, profile.string, *registerDesc.string, subComponent, spaceDesc.string); } else { // semantic, in idToken.string - parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(*idToken.string)); + TString semanticUpperCase = *idToken.string; + std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper); + parseContext.handleSemantic(idToken.loc, qualifier, mapSemantic(semanticUpperCase.c_str()), semanticUpperCase); } } else if (peekTokenClass(EHTokLeftAngle)) { found = true; diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 3c88d47b..34cf5d37 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -4144,7 +4144,7 @@ TFunction* HlslParseContext::handleConstructorCall(const TSourceLoc& loc, const // Handle seeing a "COLON semantic" at the end of a type declaration, // by updating the type according to the semantic. // -void HlslParseContext::handleSemantic(TSourceLoc loc, TQualifier& qualifier, TBuiltInVariable builtIn) +void HlslParseContext::handleSemantic(TSourceLoc loc, TQualifier& qualifier, TBuiltInVariable builtIn, const TString& upperCase) { // adjust for stage in/out @@ -4161,6 +4161,7 @@ void HlslParseContext::handleSemantic(TSourceLoc loc, TQualifier& qualifier, TBu } qualifier.builtIn = builtIn; + qualifier.semanticName = intermediate.addSemanticName(upperCase); } // diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index 2f6f24c7..602bb86a 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -91,7 +91,7 @@ public: TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermOperator&); void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&); TFunction* handleConstructorCall(const TSourceLoc&, const TType&); - void handleSemantic(TSourceLoc, TQualifier&, TBuiltInVariable); + void handleSemantic(TSourceLoc, TQualifier&, TBuiltInVariable, const TString& upperCase); void handlePackOffset(const TSourceLoc&, TQualifier&, const glslang::TString& location, const glslang::TString* component); void handleRegister(const TSourceLoc&, TQualifier&, const glslang::TString* profile, const glslang::TString& desc, diff --git a/hlsl/hlslScanContext.cpp b/hlsl/hlslScanContext.cpp index ba8088bc..d08a2c36 100755 --- a/hlsl/hlslScanContext.cpp +++ b/hlsl/hlslScanContext.cpp @@ -467,12 +467,9 @@ void HlslScanContext::tokenize(HlslToken& token) token.tokenClass = tokenClass; } -glslang::TBuiltInVariable HlslScanContext::mapSemantic(const TString& semantic) +glslang::TBuiltInVariable HlslScanContext::mapSemantic(const char* upperCase) { - TString semanticUpperCase = semantic; - std::transform(semanticUpperCase.begin(), semanticUpperCase.end(), semanticUpperCase.begin(), ::toupper); - - auto it = SemanticMap->find(semanticUpperCase.c_str()); + auto it = SemanticMap->find(upperCase); if (it != SemanticMap->end()) return it->second; else diff --git a/hlsl/hlslScanContext.h b/hlsl/hlslScanContext.h index bb8b09e8..c6f47ff5 100755 --- a/hlsl/hlslScanContext.h +++ b/hlsl/hlslScanContext.h @@ -82,7 +82,7 @@ public: static void deleteKeywordMap(); void tokenize(HlslToken&); - glslang::TBuiltInVariable mapSemantic(const TString& semantic); + glslang::TBuiltInVariable mapSemantic(const char*); protected: HlslScanContext(HlslScanContext&); diff --git a/hlsl/hlslTokenStream.h b/hlsl/hlslTokenStream.h index 333fef96..cb6c9e72 100755 --- a/hlsl/hlslTokenStream.h +++ b/hlsl/hlslTokenStream.h @@ -52,7 +52,7 @@ namespace glslang { bool acceptTokenClass(EHlslTokenClass); EHlslTokenClass peek() const; bool peekTokenClass(EHlslTokenClass) const; - glslang::TBuiltInVariable mapSemantic(const TString& semantic) { return scanner.mapSemantic(semantic); } + glslang::TBuiltInVariable mapSemantic(const char* upperCase) { return scanner.mapSemantic(upperCase); } void pushTokenStream(const TVector* tokens); void popTokenStream();