Browse Source

Merge branch 'TiemoJung-semantic_handling'

John Kessenich 9 years ago
parent
commit
2dd643ff03

+ 2 - 0
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;

+ 1 - 1
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"

+ 149 - 33
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<TVarEntryInfo> 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)
     {
+        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;
+
         TVarEntryInfo ent = { base->getId() };
-        TVarLiveMap::const_iterator at = std::lower_bound(varLiveList.begin(), varLiveList.end(), ent, TVarEntryInfo::TOrderById());
-        if (at == varLiveList.end())
+        TVarLiveMap::const_iterator at = std::lower_bound(source->begin(), source->end(), ent, TVarEntryInfo::TOrderById());
+        if (at == source->end())
             return;
-        if (!(at->id == ent.id))
+
+        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:
+    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:
-    TResolverAdaptor& operator=(TResolverAdaptor&);
+    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);
     }
 

+ 6 - 0
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<TOffsetRange> usedAtomics;  // sets of bindings used by atomic counters
     std::vector<TXfbBuffer> xfbBuffers;     // all the data we need to track per xfb buffer
     std::unordered_set<int> usedConstantId; // specialization constant ids used
+    std::set<TString> semanticNameSet;
 
 private:
     void operator=(TIntermediate&); // prevent assignments

+ 18 - 4
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

+ 3 - 1
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;

+ 2 - 1
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);
 }
 
 //

+ 1 - 1
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,

+ 2 - 5
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

+ 1 - 1
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&);

+ 1 - 1
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<HlslToken>* tokens);
         void popTokenStream();