Revert "Merge pull request #1792 from Roy-AMD/automapping-opengl-location"
authorJohn Kessenich <cepheus@frii.com>
Tue, 23 Jul 2019 10:10:36 +0000 (04:10 -0600)
committerJohn Kessenich <cepheus@frii.com>
Tue, 23 Jul 2019 10:10:36 +0000 (04:10 -0600)
This reverts commit 50ada66c2717fb579979d54ac723475de2b1a5c4, reversing
changes made to 3464b6f519be1500faa60698918f13f4dd796dd0.

glslang/MachineIndependent/ShaderLang.cpp
glslang/MachineIndependent/iomapper.cpp
glslang/MachineIndependent/iomapper.h
glslang/Public/ShaderLang.h

index b595b86..fa21db9 100755 (executable)
@@ -1852,7 +1852,7 @@ const char* TShader::getInfoDebugLog()
     return infoSink->debug.c_str();
 }
 
-TProgram::TProgram() : reflection(0), linked(false)
+TProgram::TProgram() : reflection(0), ioMapper(nullptr), linked(false)
 {
     pool = new TPoolAllocator;
     infoSink = new TInfoSink;
@@ -1864,6 +1864,7 @@ TProgram::TProgram() : reflection(0), linked(false)
 
 TProgram::~TProgram()
 {
+    delete ioMapper;
     delete infoSink;
     delete reflection;
 
@@ -2034,24 +2035,21 @@ void TProgram::dumpReflection() { if (reflection != nullptr) reflection->dump();
 //
 // I/O mapping implementation.
 //
-bool TProgram::mapIO(TIoMapResolver* pResolver, TIoMapper* pIoMapper)
+bool TProgram::mapIO(TIoMapResolver* resolver)
 {
-    if (! linked)
+    if (! linked || ioMapper)
         return false;
-    TIoMapper* ioMapper = nullptr;
-    TIoMapper defaultIOMapper;
-    if (pIoMapper == nullptr)
-        ioMapper = &defaultIOMapper;
-    else
-        ioMapper = pIoMapper;
+
+    ioMapper = new TIoMapper;
+
     for (int s = 0; s < EShLangCount; ++s) {
         if (intermediate[s]) {
-            if (! ioMapper->addStage((EShLanguage)s, *intermediate[s], *infoSink, pResolver))
+            if (! ioMapper->addStage((EShLanguage)s, *intermediate[s], *infoSink, resolver))
                 return false;
         }
     }
 
-    return ioMapper->doMap(pResolver, *infoSink);
+    return true;
 }
 
 } // end namespace glslang
index 1817a01..46c7558 100644 (file)
 
 #include "../Include/Common.h"
 #include "../Include/InfoSink.h"
+#include "iomapper.h"
+#include "LiveTraverser.h"
+#include "localintermediate.h"
 
 #include "gl_types.h"
-#include "iomapper.h"
+
+#include <unordered_set>
+#include <unordered_map>
 
 //
 // Map IO bindings.
 //    c. implicit dead bindings are left un-bound.
 //
 
+
 namespace glslang {
 
-class TVarGatherTraverser : public TLiveTraverser {
+struct TVarEntryInfo
+{
+    int               id;
+    TIntermSymbol*    symbol;
+    bool              live;
+    int               newBinding;
+    int               newSet;
+    int               newLocation;
+    int               newComponent;
+    int               newIndex;
+
+    struct TOrderById
+    {
+      inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r)
+      {
+        return l.id < r.id;
+      }
+    };
+
+    struct TOrderByPriority
+    {
+        // ordering:
+        // 1) has both binding and set
+        // 2) has binding but no set
+        // 3) has no binding but set
+        // 4) has no binding and no set
+        inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r)
+        {
+            const TQualifier& lq = l.symbol->getQualifier();
+            const TQualifier& rq = r.symbol->getQualifier();
+
+            // simple rules:
+            // has binding gives 2 points
+            // has set gives 1 point
+            // who has the most points is more important.
+            int lPoints = (lq.hasBinding() ? 2 : 0) + (lq.hasSet() ? 1 : 0);
+            int rPoints = (rq.hasBinding() ? 2 : 0) + (rq.hasSet() ? 1 : 0);
+
+            if (lPoints == rPoints)
+              return l.id < r.id;
+            return lPoints > rPoints;
+        }
+    };
+};
+
+
+
+typedef std::vector<TVarEntryInfo> TVarLiveMap;
+
+class TVarGatherTraverser : public TLiveTraverser
+{
 public:
     TVarGatherTraverser(const TIntermediate& i, bool traverseDeadCode, TVarLiveMap& inList, TVarLiveMap& outList, TVarLiveMap& uniformList)
       : TLiveTraverser(i, traverseDeadCode, true, true, false)
@@ -68,6 +124,7 @@ public:
     {
     }
 
+
     virtual void visitSymbol(TIntermSymbol* base)
     {
         TVarLiveMap* target = nullptr;
@@ -77,15 +134,14 @@ public:
             target = &outputList;
         else if (base->getQualifier().isUniformOrBuffer() && !base->getQualifier().layoutPushConstant)
             target = &uniformList;
+
         if (target) {
-            TVarEntryInfo ent = {base->getId(), base, ! traverseAll};
-            ent.stage = intermediate.getStage();
-            TVarLiveMap::iterator at = target->find(
-                ent.symbol->getName()); // std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById());
-            if (at != target->end() && at->second.id == ent.id)
-                at->second.live = at->second.live || ! traverseAll; // update live state
+            TVarEntryInfo ent = { base->getId(), base, !traverseAll };
+            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
-                (*target)[ent.symbol->getName()] = ent;
+              target->insert(at, ent);
         }
     }
 
@@ -106,7 +162,9 @@ public:
     {
     }
 
-    virtual void visitSymbol(TIntermSymbol* base) {
+
+    virtual void visitSymbol(TIntermSymbol* base)
+    {
         const TVarLiveMap* source;
         if (base->getQualifier().storage == EvqVaryingIn)
             source = &inputList;
@@ -118,23 +176,23 @@ public:
             return;
 
         TVarEntryInfo ent = { base->getId() };
-        TVarLiveMap::const_iterator at = source->find(base->getName());
+        TVarLiveMap::const_iterator at = std::lower_bound(source->begin(), source->end(), ent, TVarEntryInfo::TOrderById());
         if (at == source->end())
             return;
 
-        if (at->second.id != ent.id)
+        if (at->id != ent.id)
             return;
 
-        if (at->second.newBinding != -1)
-            base->getWritableType().getQualifier().layoutBinding = at->second.newBinding;
-        if (at->second.newSet != -1)
-            base->getWritableType().getQualifier().layoutSet = at->second.newSet;
-        if (at->second.newLocation != -1)
-            base->getWritableType().getQualifier().layoutLocation = at->second.newLocation;
-        if (at->second.newComponent != -1)
-            base->getWritableType().getQualifier().layoutComponent = at->second.newComponent;
-        if (at->second.newIndex != -1)
-            base->getWritableType().getQualifier().layoutIndex = at->second.newIndex;
+        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:
@@ -152,12 +210,10 @@ struct TNotifyUniformAdaptor
       , resolver(r)
     {
     }
-
-    inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
+    inline void operator()(TVarEntryInfo& ent)
     {
-        resolver.notifyBinding(stage, entKey.second);
+        resolver.notifyBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
     }
-
 private:
     TNotifyUniformAdaptor& operator=(TNotifyUniformAdaptor&);
 };
@@ -166,46 +222,49 @@ struct TNotifyInOutAdaptor
 {
     EShLanguage stage;
     TIoMapResolver& resolver;
-    inline TNotifyInOutAdaptor(EShLanguage s, TIoMapResolver& r) 
+    inline TNotifyInOutAdaptor(EShLanguage s, TIoMapResolver& r)
       : stage(s)
       , resolver(r)
     {
     }
-
-    inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
+    inline void operator()(TVarEntryInfo& ent)
     {
-        resolver.notifyInOut(stage, entKey.second);
+        resolver.notifyInOut(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
     }
-
 private:
     TNotifyInOutAdaptor& operator=(TNotifyInOutAdaptor&);
 };
 
-struct TResolverUniformAdaptor {
-    TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e)
+struct TResolverUniformAdaptor
+{
+    TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e, TIntermediate& interm)
       : stage(s)
       , resolver(r)
       , infoSink(i)
       , error(e)
+      , intermediate(interm)
     {
     }
 
-    inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
-        TVarEntryInfo& ent = entKey.second;
+    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);
+        const bool isValid = resolver.validateBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(),
+                                                             ent.live);
         if (isValid) {
-            resolver.resolveBinding(stage, ent);
-            resolver.resolveSet(stage, ent);
-            resolver.resolveUniformLocation(stage, ent);
+            ent.newBinding = resolver.resolveBinding(stage, ent.symbol->getName().c_str(), ent.symbol->getType(),
+                                                            ent.live);
+            ent.newSet = resolver.resolveSet(stage, ent.symbol->getName().c_str(), ent.symbol->getType(), ent.live);
+            ent.newLocation = resolver.resolveUniformLocation(stage, ent.symbol->getName().c_str(),
+                                                                     ent.symbol->getType(), ent.live);
 
             if (ent.newBinding != -1) {
                 if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) {
-                    TString err = "mapped binding out of range: " + entKey.first;
+                    TString err = "mapped binding out of range: " + ent.symbol->getName();
 
                     infoSink.info.message(EPrefixInternalError, err.c_str());
                     error = true;
@@ -213,52 +272,64 @@ struct TResolverUniformAdaptor {
             }
             if (ent.newSet != -1) {
                 if (ent.newSet >= int(TQualifier::layoutSetEnd)) {
-                    TString err = "mapped set out of range: " + entKey.first;
+                    TString err = "mapped set out of range: " + ent.symbol->getName();
 
                     infoSink.info.message(EPrefixInternalError, err.c_str());
                     error = true;
                 }
             }
         } else {
-            TString errorMsg = "Invalid binding: " + entKey.first;
+            TString errorMsg = "Invalid binding: " + ent.symbol->getName();
             infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
             error = true;
         }
     }
 
-    inline void setStage(EShLanguage s) { stage = s; }
-
     EShLanguage     stage;
     TIoMapResolver& resolver;
     TInfoSink&      infoSink;
     bool&           error;
+    TIntermediate&  intermediate;
 
 private:
     TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&);
 };
 
-struct TResolverInOutAdaptor {
-    TResolverInOutAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e)
+struct TResolverInOutAdaptor
+{
+    TResolverInOutAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e, TIntermediate& interm)
       : stage(s)
       , resolver(r)
       , infoSink(i)
       , error(e)
+      , intermediate(interm)
     {
     }
 
-    inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
+    inline void operator()(TVarEntryInfo& ent)
     {
-        TVarEntryInfo& ent = entKey.second;
         ent.newLocation = -1;
         ent.newComponent = -1;
         ent.newBinding = -1;
         ent.newSet = -1;
         ent.newIndex = -1;
-        const bool isValid = resolver.validateInOut(stage, ent);
+        const bool isValid = resolver.validateInOut(stage,
+                                                    ent.symbol->getName().c_str(),
+                                                    ent.symbol->getType(),
+                                                    ent.live);
         if (isValid) {
-            resolver.resolveInOutLocation(stage, ent);
-            resolver.resolveInOutComponent(stage, ent);
-            resolver.resolveInOutIndex(stage, ent);
+            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;
             if (ent.symbol->getType().getQualifier().semanticName != nullptr) {
@@ -273,621 +344,218 @@ struct TResolverInOutAdaptor {
         }
     }
 
-    inline void setStage(EShLanguage s) { stage = s; }
-
     EShLanguage     stage;
     TIoMapResolver& resolver;
     TInfoSink&      infoSink;
     bool&           error;
+    TIntermediate&  intermediate;
 
 private:
     TResolverInOutAdaptor& operator=(TResolverInOutAdaptor&);
 };
 
-// The class is used for reserving explicit uniform locations and ubo/ssbo/opaque bindings
-
-struct TSymbolValidater
+// Base class for shared TIoMapResolver services, used by several derivations.
+struct TDefaultIoResolverBase : public glslang::TIoMapResolver
 {
-    TSymbolValidater(TIoMapResolver& r, TInfoSink& i, TVarLiveMap* in[EShLangCount], TVarLiveMap* out[EShLangCount],
-                     TVarLiveMap* uniform[EShLangCount], bool& hadError)
-        : resolver(r)
-        , infoSink(i)
-        , currentStage(EShLangCount)
-        , preStage(EShLangCount)
-        , nextStage(EShLangCount)
-        , hadError(hadError)
-    {
-        memcpy(inVarMaps, in, EShLangCount * (sizeof(TVarLiveMap*)));
-        memcpy(outVarMaps, out, EShLangCount * (sizeof(TVarLiveMap*)));
-        memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*)));
-    }
-
-    inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
-        TVarEntryInfo& ent1 = entKey.second;
-        TIntermSymbol* base = ent1.symbol;
-        const TType& type = ent1.symbol->getType();
-        const TString& name = entKey.first;
-        TString mangleName1, mangleName2;
-        type.appendMangledName(mangleName1);
-        EShLanguage stage = ent1.stage;
-        if (currentStage != stage) {
-            preStage = currentStage;
-            currentStage = stage;
-            nextStage = EShLangCount;
-            for (int i = currentStage + 1; i < EShLangCount; i++) {
-                if (inVarMaps[i] != nullptr)
-                    nextStage = static_cast<EShLanguage>(i);
-            }
-        }
-        if (base->getQualifier().storage == EvqVaryingIn) {
-            // validate stage in;
-            if (preStage == EShLangCount)
-                return;
-            if (outVarMaps[preStage] != nullptr) {
-                auto ent2 = outVarMaps[preStage]->find(name);
-                if (ent2 != outVarMaps[preStage]->end()) {
-                    ent2->second.symbol->getType().appendMangledName(mangleName2);
-                    if (mangleName1 == mangleName2)
-                        return;
-                    else {
-                        TString err = "Invalid In/Out variable type : " + entKey.first;
-                        infoSink.info.message(EPrefixInternalError, err.c_str());
-                        hadError = true;
-                    }
-                }
-                return;
-            }
-        } else if (base->getQualifier().storage == EvqVaryingOut) {
-            // validate stage out;
-            if (nextStage == EShLangCount)
-                return;
-            if (outVarMaps[nextStage] != nullptr) {
-                auto ent2 = inVarMaps[nextStage]->find(name);
-                if (ent2 != inVarMaps[nextStage]->end()) {
-                    ent2->second.symbol->getType().appendMangledName(mangleName2);
-                    if (mangleName1 == mangleName2)
-                        return;
-                    else {
-                        TString err = "Invalid In/Out variable type : " + entKey.first;
-                        infoSink.info.message(EPrefixInternalError, err.c_str());
-                        hadError = true;
-                    }
-                }
-                return;
-            }
-        } else if (base->getQualifier().isUniformOrBuffer() && ! base->getQualifier().layoutPushConstant) {
-            // validate uniform type;
-            for (int i = 0; i < EShLangCount; i++) {
-                if (i != currentStage && outVarMaps[i] != nullptr) {
-                    auto ent2 = uniformVarMap[i]->find(name);
-                    if (ent2 != uniformVarMap[i]->end()) {
-                        ent2->second.symbol->getType().appendMangledName(mangleName2);
-                        if (mangleName1 != mangleName2) {
-                            TString err = "Invalid Uniform variable type : " + entKey.first;
-                            infoSink.info.message(EPrefixInternalError, err.c_str());
-                            hadError = true;
-                        }
-                        mangleName2.clear();
-                    }
-                }
-            }
-        }
-    }
-    TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount], *uniformVarMap[EShLangCount];
-    // Use for mark pre stage, to get more interface symbol information.
-    EShLanguage preStage, currentStage, nextStage;
-    // Use for mark current shader stage for resolver
-    TIoMapResolver& resolver;
-    TInfoSink& infoSink;
-    bool& hadError;
-
-private:
-    TSymbolValidater& operator=(TSymbolValidater&);
-};
+    TDefaultIoResolverBase(const TIntermediate &intermediate) :
+        intermediate(intermediate),
+        nextUniformLocation(intermediate.getUniformLocationBase()),
+        nextInputLocation(0),
+        nextOutputLocation(0)
+    { }
 
-struct TSlotCollector {
-    TSlotCollector(TIoMapResolver& r, TInfoSink& i) : resolver(r), infoSink(i) { }
-
-    inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
-        resolver.reserverStorageSlot(entKey.second, infoSink);
-        resolver.reserverResourceSlot(entKey.second, infoSink);
+    int getBaseBinding(TResourceType res, unsigned int set) const {
+        return selectBaseBinding(intermediate.getShiftBinding(res), 
+                                 intermediate.getShiftBindingForSet(res, set));
     }
-    TIoMapResolver& resolver;
-    TInfoSink& infoSink;
 
-private:
-    TSlotCollector& operator=(TSlotCollector&);
-};
+    const std::vector<std::string>& getResourceSetBinding() const { return intermediate.getResourceSetBinding(); }
 
-TDefaultIoResolverBase::TDefaultIoResolverBase(const TIntermediate& intermediate)
-    : intermediate(intermediate)
-    , nextUniformLocation(intermediate.getUniformLocationBase())
-    , nextInputLocation(0)
-    , nextOutputLocation(0)
-{
-    memset(stageMask, false, sizeof(bool) * (EShLangCount + 1));
-}
-
-int TDefaultIoResolverBase::getBaseBinding(TResourceType res, unsigned int set) const {
-    return selectBaseBinding(intermediate.getShiftBinding(res), intermediate.getShiftBindingForSet(res, set));
-}
-
-const std::vector<std::string>& TDefaultIoResolverBase::getResourceSetBinding() const {
-    return intermediate.getResourceSetBinding();
-}
-
-bool TDefaultIoResolverBase::doAutoBindingMapping() const { return intermediate.getAutoMapBindings(); }
-
-bool TDefaultIoResolverBase::doAutoLocationMapping() const { return intermediate.getAutoMapLocations(); }
+    bool doAutoBindingMapping() const { return intermediate.getAutoMapBindings(); }
+    bool doAutoLocationMapping() const { return intermediate.getAutoMapLocations(); }
 
-TDefaultIoResolverBase::TSlotSet::iterator TDefaultIoResolverBase::findSlot(int set, int slot) {
-    return std::lower_bound(slots[set].begin(), slots[set].end(), slot);
-}
-
-bool TDefaultIoResolverBase::checkEmpty(int set, int slot) {
-    TSlotSet::iterator at = findSlot(set, slot);
-    return ! (at != slots[set].end() && *at == slot);
-}
+    typedef std::vector<int> TSlotSet;
+    typedef std::unordered_map<int, TSlotSet> TSlotSetMap;
+    TSlotSetMap slots;
 
-int TDefaultIoResolverBase::reserveSlot(int set, int slot, int size) {
-    TSlotSet::iterator at = findSlot(set, slot);
-    // tolerate aliasing, by not double-recording aliases
-    // (policy about appropriateness of the alias is higher up)
-    for (int i = 0; i < size; i++) {
-        if (at == slots[set].end() || *at != slot + i)
-            at = slots[set].insert(at, slot + i);
-        ++at;
+    TSlotSet::iterator findSlot(int set, int slot)
+    {
+        return std::lower_bound(slots[set].begin(), slots[set].end(), slot);
     }
-    return slot;
-}
 
-int TDefaultIoResolverBase::getFreeSlot(int set, int base, int size) {
-    TSlotSet::iterator at = findSlot(set, base);
-    if (at == slots[set].end())
-        return reserveSlot(set, base, size);
-    // look for a big enough gap
-    for (; at != slots[set].end(); ++at) {
-        if (*at - base >= size)
-            break;
-        base = *at + 1;
+    bool checkEmpty(int set, int slot)
+    {
+        TSlotSet::iterator at = findSlot(set, slot);
+        return !(at != slots[set].end() && *at == slot);
     }
-    return reserveSlot(set, base, size);
-}
 
-int TDefaultIoResolverBase::resolveSet(EShLanguage /*stage*/, TVarEntryInfo& ent) {
-    const TType& type = ent.symbol->getType();
-    if (type.getQualifier().hasSet()) {
-        return ent.newSet = type.getQualifier().layoutSet;
-    }
-    // If a command line or API option requested a single descriptor set, use that (if not overrided by spaceN)
-    if (getResourceSetBinding().size() == 1) {
-        return ent.newSet = atoi(getResourceSetBinding()[0].c_str());
-    }
-    return ent.newSet = 0;
-}
+    int reserveSlot(int set, int slot, int size = 1)
+    {
+        TSlotSet::iterator at = findSlot(set, slot);
 
-int TDefaultIoResolverBase::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
-    const TType& type = ent.symbol->getType();
-    const char* name = ent.symbol->getName().c_str();
-    // kick out of not doing this
-    if (! doAutoLocationMapping()) {
-        return ent.newLocation = -1;
-    }
-    // no locations added if already present, a built-in variable, a block, or an opaque
-    if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getBasicType() == EbtBlock ||
-        type.getBasicType() == EbtAtomicUint || (type.containsOpaque() && intermediate.getSpv().openGl == 0)) {
-        return ent.newLocation = -1;
-    }
-    // no locations on blocks of built-in variables
-    if (type.isStruct()) {
-        if (type.getStruct()->size() < 1) {
-            return ent.newLocation = -1;
-        }
-        if ((*type.getStruct())[0].type->isBuiltIn()) {
-            return ent.newLocation = -1;
+        // tolerate aliasing, by not double-recording aliases
+        // (policy about appropriateness of the alias is higher up)
+        for (int i = 0; i < size; i++) {
+                if (at == slots[set].end() || *at != slot + i)
+                        at = slots[set].insert(at, slot + i);
+                ++at;
         }
-    }
-    int location = intermediate.getUniformLocationOverride(name);
-    if (location != -1) {
-        return ent.newLocation = location;
-    }
-    location = nextUniformLocation;
-    nextUniformLocation += TIntermediate::computeTypeUniformLocationSize(type);
-    return ent.newLocation = location;
-}
 
-int TDefaultIoResolverBase::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) {
-    const TType& type = ent.symbol->getType();
-    // kick out of not doing this
-    if (! doAutoLocationMapping()) {
-        return ent.newLocation = -1;
+        return slot;
     }
 
-    // no locations added if already present, or a built-in variable
-    if (type.getQualifier().hasLocation() || type.isBuiltIn()) {
-        return ent.newLocation = -1;
-    }
+    int getFreeSlot(int set, int base, int size = 1)
+    {
+        TSlotSet::iterator at = findSlot(set, base);
+        if (at == slots[set].end())
+            return reserveSlot(set, base, size);
 
-    // no locations on blocks of built-in variables
-    if (type.isStruct()) {
-        if (type.getStruct()->size() < 1) {
-            return ent.newLocation = -1;
-        }
-        if ((*type.getStruct())[0].type->isBuiltIn()) {
-            return ent.newLocation = -1;
+        // look for a big enough gap
+        for (; at != slots[set].end(); ++at) {
+            if (*at - base >= size)
+                break;
+            base = *at + 1;
         }
+        return reserveSlot(set, base, size);
     }
-    // point to the right input or output location counter
-    int& nextLocation = type.getQualifier().isPipeInput() ? nextInputLocation : nextOutputLocation;
-    // Placeholder. This does not do proper cross-stage lining up, nor
-    // work with mixed location/no-location declarations.
-    int location = nextLocation;
-    int typeLocationSize;
-    // Don’t take into account the outer-most array if the stage’s
-    // interface is automatically an array.
-    typeLocationSize = computeTypeLocationSize(type, stage);
-    nextLocation += typeLocationSize;
-    return ent.newLocation = location;
-}
 
-int TDefaultIoResolverBase::resolveInOutComponent(EShLanguage /*stage*/, TVarEntryInfo& ent) {
-    return ent.newComponent = -1;
-}
+    virtual bool validateBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool /*is_live*/) override = 0;
 
-int TDefaultIoResolverBase::resolveInOutIndex(EShLanguage /*stage*/, TVarEntryInfo& ent) { return ent.newIndex = -1; }
-
-uint32_t TDefaultIoResolverBase::computeTypeLocationSize(const TType& type, EShLanguage stage) {
-    int typeLocationSize;
-    // Don’t take into account the outer-most array if the stage’s
-    // interface is automatically an array.
-    if (type.getQualifier().isArrayedIo(stage)) {
-        TType elementType(type, 0);
-        typeLocationSize = TIntermediate::computeTypeLocationSize(elementType, stage);
-    } else {
-        typeLocationSize = TIntermediate::computeTypeLocationSize(type, stage);
-    }
-    return typeLocationSize;
-}
+    virtual int resolveBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool is_live) override = 0;
 
-//TDefaultGlslIoResolver
-TResourceType TDefaultGlslIoResolver::getResourceType(const glslang::TType& type) {
-    if (isImageType(type)) {
-        return EResImage;
-    }
-    if (isTextureType(type)) {
-        return EResTexture;
-    }
-    if (isSsboType(type)) {
-        return EResSsbo;
-    }
-    if (isSamplerType(type)) {
-        return EResSampler;
-    }
-    if (isUboType(type)) {
-        return EResUbo;
-    }
-    return EResCount;
-}
+    int resolveSet(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool /*is_live*/) override
+    {
+        if (type.getQualifier().hasSet())
+            return type.getQualifier().layoutSet;
 
-TDefaultGlslIoResolver::TDefaultGlslIoResolver(const TIntermediate& intermediate)
-    : TDefaultIoResolverBase(intermediate)
-    , preStage(EShLangCount)
-    , currentStage(EShLangCount)
-{ }
-
-int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) {
-    const TType& type = ent.symbol->getType();
-    const TString& name = ent.symbol->getName();
-    if (currentStage != stage) {
-        preStage = currentStage;
-        currentStage = stage;
-    }
-    // kick out of not doing this
-    if (! doAutoLocationMapping()) {
-        return ent.newLocation = -1;
-    }
-    // expand the location to each element if the symbol is a struct or array
-    if (type.getQualifier().hasLocation()) {
-        return ent.newLocation = type.getQualifier().layoutLocation;
-    }
-    // no locations added if already present, or a built-in variable
-    if (type.isBuiltIn()) {
-        return ent.newLocation = -1;
-    }
-    // no locations on blocks of built-in variables
-    if (type.isStruct()) {
-        if (type.getStruct()->size() < 1) {
-            return ent.newLocation = -1;
-        }
-        if ((*type.getStruct())[0].type->isBuiltIn()) {
-            return ent.newLocation = -1;
-        }
-    }
-    int typeLocationSize = computeTypeLocationSize(type, stage);
-    int location = type.getQualifier().layoutLocation;
-    bool hasLocation = false;
-    EShLanguage keyStage(EShLangCount);
-    TStorageQualifier storage;
-    storage = EvqInOut;
-    if (type.getQualifier().isPipeInput()) {
-        // If this symbol is a input, search pre stage's out
-        keyStage = preStage;
-    }
-    if (type.getQualifier().isPipeOutput()) {
-        // If this symbol is a output, search next stage's in
-        keyStage = currentStage;
-    }
-    // The in/out in current stage is not declared with location, but it is possible declared
-    // with explicit location in other stages, find the storageSlotMap firstly to check whether
-    // the in/out has location
-    int resourceKey = buildStorageKey(keyStage, storage);
-    if (! storageSlotMap[resourceKey].empty()) {
-        TVarSlotMap::iterator iter = storageSlotMap[resourceKey].find(name);
-        if (iter != storageSlotMap[resourceKey].end()) {
-            // If interface resource be found, set it has location and this symbol's new location
-            // equal the symbol's explicit location declarated in pre or next stage.
-            //
-            // vs:    out vec4 a;
-            // fs:    layout(..., location = 3,...) in vec4 a;
-            hasLocation = true;
-            location = iter->second;
-            // if we want deal like that:
-            // vs:    layout(location=4) out vec4 a;
-            //        out vec4 b;
-            //
-            // fs:    in vec4 a;
-            //        layout(location = 4) in vec4 b;
-            // we need retraverse the map.
-        }
-        if (! hasLocation) {
-            // If interface resource note found, It's mean the location in two stage are both implicit declarat.
-            // So we should find a new slot for this interface.
-            //
-            // vs: out vec4 a;
-            // fs: in vec4 a;
-            location = getFreeSlot(resourceKey, 0, typeLocationSize);
-            storageSlotMap[resourceKey][name] = location;
-        }
-    } else {
-        // the first interface declarated in a program.
-        TVarSlotMap varSlotMap;
-        location = getFreeSlot(resourceKey, 0, typeLocationSize);
-        varSlotMap[name] = location;
-        storageSlotMap[resourceKey] = varSlotMap;
-    }
-    //Update location
-    return ent.newLocation = location;
-}
+        // If a command line or API option requested a single descriptor set, use that (if not overrided by spaceN)
+        if (getResourceSetBinding().size() == 1)
+            return atoi(getResourceSetBinding()[0].c_str());
 
-int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
-    const TType& type = ent.symbol->getType();
-    const TString& name = ent.symbol->getName();
-    // kick out of not doing this
-    if (! doAutoLocationMapping()) {
-        return ent.newLocation = -1;
+        return 0;
     }
-    // expand the location to each element if the symbol is a struct or array
-    if (type.getQualifier().hasLocation() && (type.isStruct() || type.isArray())) {
-        return ent.newLocation = type.getQualifier().layoutLocation;
-    } else {
+    int resolveUniformLocation(EShLanguage /*stage*/, const char* name, const glslang::TType& type, bool /*is_live*/) override
+    {
+        // kick out of not doing this
+        if (!doAutoLocationMapping())
+            return -1;
+
         // no locations added if already present, a built-in variable, a block, or an opaque
-        if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getBasicType() == EbtBlock ||
-            type.getBasicType() == EbtAtomicUint || (type.containsOpaque() && intermediate.getSpv().openGl == 0)) {
-            return ent.newLocation = -1;
-        }
+        if (type.getQualifier().hasLocation() || type.isBuiltIn() ||
+            type.getBasicType() == EbtBlock ||
+            type.getBasicType() == EbtAtomicUint ||
+            (type.containsOpaque() && intermediate.getSpv().openGl == 0))
+            return -1;
+
         // no locations on blocks of built-in variables
         if (type.isStruct()) {
-            if (type.getStruct()->size() < 1) {
-                return ent.newLocation = -1;
-            }
-            if ((*type.getStruct())[0].type->isBuiltIn()) {
-                return ent.newLocation = -1;
-            }
+            if (type.getStruct()->size() < 1)
+                return -1;
+            if ((*type.getStruct())[0].type->isBuiltIn())
+                return -1;
         }
+
+        int location = intermediate.getUniformLocationOverride(name);
+        if (location != -1)
+            return location;
+
+        location = nextUniformLocation;
+
+        nextUniformLocation += TIntermediate::computeTypeUniformLocationSize(type);
+
+        return location;
     }
-    int location = intermediate.getUniformLocationOverride(name.c_str());
-    if (location != -1) {
-        return ent.newLocation = location;
+    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
+    {
+        // kick out of not doing this
+        if (!doAutoLocationMapping())
+            return -1;
 
-    int size = TIntermediate::computeTypeUniformLocationSize(type);
-
-    // The uniform in current stage is not declared with location, but it is possible declared
-    // with explicit location in other stages, find the storageSlotMap firstly to check whether
-    // the uniform has location
-    bool hasLocation = false;
-    int resourceKey = buildStorageKey(EShLangCount, EvqUniform);
-    TVarSlotMap& slotMap = storageSlotMap[resourceKey];
-    // Check dose shader program has uniform resource
-    if (! slotMap.empty()) {
-        // If uniform resource not empty, try find a same name uniform
-        TVarSlotMap::iterator iter = slotMap.find(name);
-        if (iter != slotMap.end()) {
-            // If uniform resource be found, set it has location and this symbol's new location
-            // equal the uniform's explicit location declarated in other stage.
-            //
-            // vs:    uniform vec4 a;
-            // fs:    layout(..., location = 3,...) uniform vec4 a;
-            hasLocation = true;
-            location = iter->second;
-        }
-        if (! hasLocation) {
-            // No explicit location declaraten in other stage.
-            // So we should find a new slot for this uniform.
-            //
-            // vs:    uniform vec4 a;
-            // fs:    uniform vec4 a;
-            location = getFreeSlot(resourceKey, 0, computeTypeLocationSize(type, currentStage));
-            storageSlotMap[resourceKey][name] = location;
+        // no locations added if already present, or a built-in variable
+        if (type.getQualifier().hasLocation() || type.isBuiltIn())
+            return -1;
+
+        // no locations on blocks of built-in variables
+        if (type.isStruct()) {
+            if (type.getStruct()->size() < 1)
+                return -1;
+            if ((*type.getStruct())[0].type->isBuiltIn())
+                return -1;
+        }
+
+        // point to the right input or output location counter
+        int& nextLocation = type.getQualifier().isPipeInput() ? nextInputLocation : nextOutputLocation;
+
+        // Placeholder. This does not do proper cross-stage lining up, nor
+        // work with mixed location/no-location declarations.
+        int location = nextLocation;
+        int typeLocationSize;
+        // Don’t take into account the outer-most array if the stage’s
+        // interface is automatically an array.
+        if (type.getQualifier().isArrayedIo(stage)) {
+                TType elementType(type, 0);
+                typeLocationSize = TIntermediate::computeTypeLocationSize(elementType, stage);
+        } else {
+                typeLocationSize = TIntermediate::computeTypeLocationSize(type, stage);
         }
-    } else {
-        // the first uniform declarated in a program.
-        TVarSlotMap varSlotMap;
-        location = getFreeSlot(resourceKey, 0, size);
-        varSlotMap[name] = location;
-        storageSlotMap[resourceKey] = varSlotMap;
-    }
-    return ent.newLocation = location;
-}
+        nextLocation += typeLocationSize;
 
-int TDefaultGlslIoResolver::resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) {
-    const TType& type = ent.symbol->getType();
-    const TString& name = ent.symbol->getName();
-    // On OpenGL arrays of opaque types take a seperate binding for each element
-    int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1;
-    TResourceType resource = getResourceType(type);
-    // don't need to handle uniform symbol, it will be handled in resolveUniformLocation
-    if (resource == EResUbo && type.getBasicType() != EbtBlock) {
-        return ent.newBinding = -1;
+        return location;
     }
-    // There is no 'set' qualifier in OpenGL shading language, each resource has its own
-    // binding name space, so remap the 'set' to resource type which make each resource
-    // binding is valid from 0 to MAX_XXRESOURCE_BINDINGS
-    int set = resource;
-    if (resource < EResCount) {
-        if (type.getQualifier().hasBinding()) {
-            ent.newBinding = reserveSlot(set, getBaseBinding(resource, set) + type.getQualifier().layoutBinding, numBindings);
-            return ent.newBinding;
-        } else if (ent.live && doAutoBindingMapping()) {
-            // The resource in current stage is not declared with binding, but it is possible declared
-            // with explicit binding in other stages, find the resourceSlotMap firstly to check whether
-            // the resource has binding, don't need to allocate if it already has a binding
-            bool hasBinding = false;
-            if (! resourceSlotMap[resource].empty()) {
-                TVarSlotMap::iterator iter = resourceSlotMap[resource].find(name);
-                if (iter != resourceSlotMap[resource].end()) {
-                    hasBinding = true;
-                    ent.newBinding = iter->second;
-                }
-            }
-            if (! hasBinding) {
-                TVarSlotMap varSlotMap;
-                // find free slot, the caller did make sure it passes all vars with binding
-                // first and now all are passed that do not have a binding and needs one
-                int binding = getFreeSlot(resource, getBaseBinding(resource, set), numBindings);
-                varSlotMap[name] = binding;
-                resourceSlotMap[resource] = varSlotMap;
-                ent.newBinding = binding;
-            }
-            return ent.newBinding;
-        }
+    int resolveInOutComponent(EShLanguage /*stage*/, const char* /*name*/, const TType& /*type*/, bool /*is_live*/) override
+    {
+        return -1;
     }
-    return ent.newBinding = -1;
-}
-
-void TDefaultGlslIoResolver::beginResolve(EShLanguage stage) {
-    // reset stage state
-    if (stage == EShLangCount)
-        preStage = currentStage = stage;
-    // update stage state
-    else if (currentStage != stage) {
-        preStage = currentStage;
-        currentStage = stage;
+    int resolveInOutIndex(EShLanguage /*stage*/, const char* /*name*/, const TType& /*type*/, bool /*is_live*/) override
+    {
+        return -1;
     }
-}
 
-void TDefaultGlslIoResolver::endResolve(EShLanguage /*stage*/) {
-    // TODO nothing
-}
+    void notifyBinding(EShLanguage, const char* /*name*/, const TType&, bool /*is_live*/) override {}
+    void notifyInOut(EShLanguage, const char* /*name*/, const TType&, bool /*is_live*/) override {}
+    void endNotifications(EShLanguage) override {}
+    void beginNotifications(EShLanguage) override {}
+    void beginResolve(EShLanguage) override {}
+    void endResolve(EShLanguage) override {}
+
+protected:
+    TDefaultIoResolverBase(TDefaultIoResolverBase&);
+    TDefaultIoResolverBase& operator=(TDefaultIoResolverBase&);
 
-void TDefaultGlslIoResolver::beginCollect(EShLanguage stage) {
-    // reset stage state
-    if (stage == EShLangCount)
-        preStage = currentStage = stage;
-    // update stage state
-    else if (currentStage != stage) {
-        preStage = currentStage;
-        currentStage = stage;
+    const TIntermediate &intermediate;
+    int nextUniformLocation;
+    int nextInputLocation;
+    int nextOutputLocation;
+
+    // Return descriptor set specific base if there is one, and the generic base otherwise.
+    int selectBaseBinding(int base, int descriptorSetBase) const {
+        return descriptorSetBase != -1 ? descriptorSetBase : base;
     }
-}
 
-void TDefaultGlslIoResolver::endCollect(EShLanguage /*stage*/) {
-    // TODO nothing
-}
+    static int getLayoutSet(const glslang::TType& type) {
+        if (type.getQualifier().hasSet())
+            return type.getQualifier().layoutSet;
+        else
+            return 0;
+    }
 
-void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
-    const TType& type = ent.symbol->getType();
-    const TString& name = ent.symbol->getName();
-    TStorageQualifier storage = type.getQualifier().storage;
-    EShLanguage stage(EShLangCount);
-    switch (storage) {
-    case EvqUniform:
-        if (type.getBasicType() != EbtBlock && type.getQualifier().hasLocation()) {
-            //
-            // Reserve the slots for the uniforms who has explicit location
-            int storageKey = buildStorageKey(EShLangCount, EvqUniform);
-            int location = type.getQualifier().layoutLocation;
-            TVarSlotMap& varSlotMap = storageSlotMap[storageKey];
-            TVarSlotMap::iterator iter = varSlotMap.find(name);
-            if (iter == varSlotMap.end()) {
-                int numLocations = TIntermediate::computeTypeUniformLocationSize(type);
-                reserveSlot(storageKey, location, numLocations);
-                varSlotMap[name] = location;
-            } else {
-                // Allocate location by name for OpenGL driver, so the uniform in different
-                // stages should be declared with the same location
-                if (iter->second != location) {
-                    TString errorMsg = "Invalid location: " + name;
-                    infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
-                }
-            }
-        }
-        break;
-    case EvqVaryingIn:
-    case EvqVaryingOut:
-        //
-        // Reserve the slots for the inout who has explicit location
-        if (type.getQualifier().hasLocation()) {
-            stage = storage == EvqVaryingIn ? preStage : stage;
-            stage = storage == EvqVaryingOut ? currentStage : stage;
-            int storageKey = buildStorageKey(stage, EvqInOut);
-            int location = type.getQualifier().layoutLocation;
-            TVarSlotMap& varSlotMap = storageSlotMap[storageKey];
-            TVarSlotMap::iterator iter = varSlotMap.find(name);
-            if (iter == varSlotMap.end()) {
-                int numLocations = TIntermediate::computeTypeUniformLocationSize(type);
-                reserveSlot(storageKey, location, numLocations);
-                varSlotMap[name] = location;
-            } else {
-                // Allocate location by name for OpenGL driver, so the uniform in different
-                // stages should be declared with the same location
-                if (iter->second != location) {
-                    TString errorMsg = "Invalid location: " + name;
-                    infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
-                }
-            }
-        }
-        break;
-    default:
-        break;
+    static bool isSamplerType(const glslang::TType& type) {
+        return type.getBasicType() == glslang::EbtSampler && type.getSampler().isPureSampler();
     }
-}
 
-void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
-    const TType& type = ent.symbol->getType();
-    const TString& name = ent.symbol->getName();
-    int resource = getResourceType(type);
-    if (type.getQualifier().hasBinding()) {
-        TVarSlotMap& varSlotMap = resourceSlotMap[resource];
-        TVarSlotMap::iterator iter = varSlotMap.find(name);
-        int binding = type.getQualifier().layoutBinding;
-        if (iter == varSlotMap.end()) {
-            // Reserve the slots for the ubo, ssbo and opaques who has explicit binding
-            int numBindings = type.isSizedArray() ? type.getCumulativeArraySize() : 1;
-            varSlotMap[name] = binding;
-            reserveSlot(resource, binding, numBindings);
-        } else {
-            // Allocate binding by name for OpenGL driver, so the resource in different
-            // stages should be declared with the same binding
-            if (iter->second != binding) {
-                TString errorMsg = "Invalid binding: " + name;
-                infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
-            }
-        }
+    static bool isTextureType(const glslang::TType& type) {
+        return (type.getBasicType() == glslang::EbtSampler && 
+                (type.getSampler().isTexture() || type.getSampler().isSubpass()));
     }
-}
 
-//TDefaultGlslIoResolver end
+    static bool isUboType(const glslang::TType& type) {
+        return type.getQualifier().storage == EvqUniform;
+    }
+};
 
 /*
  * Basic implementation of glslang::TIoMapResolver that replaces the
@@ -899,47 +567,66 @@ void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink&
 /*
  * Default resolver
  */
-struct TDefaultIoResolver : public TDefaultIoResolverBase {
-    TDefaultIoResolver(const TIntermediate& intermediate) : TDefaultIoResolverBase(intermediate) { }
-
-    bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; }
+struct TDefaultIoResolver : public TDefaultIoResolverBase
+{
+    TDefaultIoResolver(const TIntermediate &intermediate) : TDefaultIoResolverBase(intermediate) { }
 
-    TResourceType getResourceType(const glslang::TType& type) override {
-        if (isImageType(type)) {
-            return EResImage;
-        }
-        if (isTextureType(type)) {
-            return EResTexture;
-        }
-        if (isSsboType(type)) {
-            return EResSsbo;
-        }
-        if (isSamplerType(type)) {
-            return EResSampler;
-        }
-        if (isUboType(type)) {
-            return EResUbo;
-        }
-        return EResCount;
+    bool validateBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& /*type*/, bool /*is_live*/) override
+    {
+        return true;
     }
 
-    int resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) override {
-        const TType& type = ent.symbol->getType();
+    int resolveBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool is_live) override
+    {
         const int set = getLayoutSet(type);
         // On OpenGL arrays of opaque types take a seperate binding for each element
         int numBindings = intermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1;
-        TResourceType resource = getResourceType(type);
-        if (resource < EResCount) {
-            if (type.getQualifier().hasBinding()) {
-                return ent.newBinding = reserveSlot(
-                           set, getBaseBinding(resource, set) + type.getQualifier().layoutBinding, numBindings);
-            } else if (ent.live && doAutoBindingMapping()) {
-                // find free slot, the caller did make sure it passes all vars with binding
-                // first and now all are passed that do not have a binding and needs one
-                return ent.newBinding = getFreeSlot(set, getBaseBinding(resource, set), numBindings);
-            }
+
+        if (type.getQualifier().hasBinding()) {
+            if (isImageType(type))
+                return reserveSlot(set, getBaseBinding(EResImage, set) + type.getQualifier().layoutBinding, numBindings);
+
+            if (isTextureType(type))
+                return reserveSlot(set, getBaseBinding(EResTexture, set) + type.getQualifier().layoutBinding, numBindings);
+
+            if (isSsboType(type))
+                return reserveSlot(set, getBaseBinding(EResSsbo, set) + type.getQualifier().layoutBinding, numBindings);
+
+            if (isSamplerType(type))
+                return reserveSlot(set, getBaseBinding(EResSampler, set) + type.getQualifier().layoutBinding, numBindings);
+
+            if (isUboType(type))
+                return reserveSlot(set, getBaseBinding(EResUbo, set) + type.getQualifier().layoutBinding, numBindings);
+        } else if (is_live && doAutoBindingMapping()) {
+            // find free slot, the caller did make sure it passes all vars with binding
+            // first and now all are passed that do not have a binding and needs one
+
+            if (isImageType(type))
+                return getFreeSlot(set, getBaseBinding(EResImage, set), numBindings);
+
+            if (isTextureType(type))
+                return getFreeSlot(set, getBaseBinding(EResTexture, set), numBindings);
+
+            if (isSsboType(type))
+                return getFreeSlot(set, getBaseBinding(EResSsbo, set), numBindings);
+
+            if (isSamplerType(type))
+                return getFreeSlot(set, getBaseBinding(EResSampler, set), numBindings);
+
+            if (isUboType(type))
+                return getFreeSlot(set, getBaseBinding(EResUbo, set), numBindings);
         }
-        return ent.newBinding = -1;
+
+        return -1;
+    }
+
+protected:
+    static bool isImageType(const glslang::TType& type) {
+        return type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage();
+    }
+
+    static bool isSsboType(const glslang::TType& type) {
+        return type.getQualifier().storage == EvqBuffer;
     }
 };
 
@@ -960,7 +647,7 @@ t - for shader resource views (SRV)
    BYTEADDRESSBUFFER
    BUFFER
    TBUFFER
-
+    
 s - for samplers
    SAMPLER
    SAMPLER1D
@@ -986,65 +673,98 @@ b - for constant buffer views (CBV)
    CBUFFER
    CONSTANTBUFFER
  ********************************************************************************/
-struct TDefaultHlslIoResolver : public TDefaultIoResolverBase {
-    TDefaultHlslIoResolver(const TIntermediate& intermediate) : TDefaultIoResolverBase(intermediate) { }
-
-    bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; }
+struct TDefaultHlslIoResolver : public TDefaultIoResolverBase
+{
+    TDefaultHlslIoResolver(const TIntermediate &intermediate) : TDefaultIoResolverBase(intermediate) { }
 
-    TResourceType getResourceType(const glslang::TType& type) override {
-        if (isUavType(type)) {
-            return EResUav;
-        }
-        if (isSrvType(type)) {
-            return EResTexture;
-        }
-        if (isSamplerType(type)) {
-            return EResSampler;
-        }
-        if (isUboType(type)) {
-            return EResUbo;
-        }
-        return EResCount;
+    bool validateBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& /*type*/, bool /*is_live*/) override
+    {
+        return true;
     }
 
-    int resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) override {
-        const TType& type = ent.symbol->getType();
+    int resolveBinding(EShLanguage /*stage*/, const char* /*name*/, const glslang::TType& type, bool is_live) override
+    {
         const int set = getLayoutSet(type);
-        TResourceType resource = getResourceType(type);
-        if (resource < EResCount) {
-            if (type.getQualifier().hasBinding()) {
-                return ent.newBinding = reserveSlot(set, getBaseBinding(resource, set) + type.getQualifier().layoutBinding);
-            } else if (ent.live && doAutoBindingMapping()) {
-                // find free slot, the caller did make sure it passes all vars with binding
-                // first and now all are passed that do not have a binding and needs one
-                return ent.newBinding = getFreeSlot(set, getBaseBinding(resource, set));
-            }
+
+        if (type.getQualifier().hasBinding()) {
+            if (isUavType(type))
+                return reserveSlot(set, getBaseBinding(EResUav, set) + type.getQualifier().layoutBinding);
+
+            if (isSrvType(type))
+                return reserveSlot(set, getBaseBinding(EResTexture, set) + type.getQualifier().layoutBinding);
+
+            if (isSamplerType(type))
+                return reserveSlot(set, getBaseBinding(EResSampler, set) + type.getQualifier().layoutBinding);
+
+            if (isUboType(type))
+                return reserveSlot(set, getBaseBinding(EResUbo, set) + type.getQualifier().layoutBinding);
+        } else if (is_live && doAutoBindingMapping()) {
+            // find free slot, the caller did make sure it passes all vars with binding
+            // first and now all are passed that do not have a binding and needs one
+
+            if (isUavType(type))
+                return getFreeSlot(set, getBaseBinding(EResUav, set));
+
+            if (isSrvType(type))
+                return getFreeSlot(set, getBaseBinding(EResTexture, set));
+
+            if (isSamplerType(type))
+                return getFreeSlot(set, getBaseBinding(EResSampler, set));
+
+            if (isUboType(type))
+                return getFreeSlot(set, getBaseBinding(EResUbo, set));
         }
-        return ent.newBinding = -1;
+
+        return -1;
+    }
+
+protected:
+    // Return true if this is a SRV (shader resource view) type:
+    static bool isSrvType(const glslang::TType& type) {
+        return isTextureType(type) || type.getQualifier().storage == EvqBuffer;
+    }
+
+    // Return true if this is a UAV (unordered access view) type:
+    static bool isUavType(const glslang::TType& type) {
+        if (type.getQualifier().readonly)
+            return false;
+
+        return (type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage()) ||
+            (type.getQualifier().storage == EvqBuffer);
     }
 };
 
+
 // Map I/O variables to provided offsets, and make bindings for
 // unbound but live variables.
 //
 // Returns false if the input is too malformed to do this.
-bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) {
-    bool somethingToDo = ! intermediate.getResourceSetBinding().empty() || intermediate.getAutoMapBindings() ||
-                         intermediate.getAutoMapLocations();
+bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSink &infoSink, TIoMapResolver *resolver)
+{
+    bool somethingToDo = !intermediate.getResourceSetBinding().empty() ||
+        intermediate.getAutoMapBindings() ||
+        intermediate.getAutoMapLocations();
+
     for (int res = 0; res < EResCount; ++res) {
-        somethingToDo = somethingToDo || (intermediate.getShiftBinding(TResourceType(res)) != 0) ||
-                        intermediate.hasShiftBindingForSet(TResourceType(res));
+        somethingToDo = somethingToDo ||
+            (intermediate.getShiftBinding(TResourceType(res)) != 0) ||
+            intermediate.hasShiftBindingForSet(TResourceType(res));
     }
-    if (! somethingToDo && resolver == nullptr)
+
+    if (!somethingToDo && resolver == nullptr)
         return true;
+
     if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive())
         return false;
+
     TIntermNode* root = intermediate.getTreeRoot();
     if (root == nullptr)
         return false;
+
     // if no resolver is provided, use the default resolver with the given shifts and auto map settings
     TDefaultIoResolver defaultResolver(intermediate);
     TDefaultHlslIoResolver defaultHlslResolver(intermediate);
+
     if (resolver == nullptr) {
         // TODO: use a passed in IO mapper for this
         if (intermediate.usingHlslIoMapping())
@@ -1052,163 +772,47 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSi
         else
             resolver = &defaultResolver;
     }
-    resolver->addStage(stage);
+
     TVarLiveMap inVarMap, outVarMap, uniformVarMap;
-    TVarLiveVector uniformVector;
     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());
-    while (! iter_binding_live.functions.empty()) {
+
+    while (!iter_binding_live.functions.empty()) {
         TIntermNode* function = iter_binding_live.functions.back();
         iter_binding_live.functions.pop_back();
         function->traverse(&iter_binding_live);
     }
+
     // sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
-    std::for_each(uniformVarMap.begin(), uniformVarMap.end(),
-                  [&uniformVector](TVarLivePair p) { uniformVector.push_back(p); });
-    std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
-        return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
-    });
+    std::sort(uniformVarMap.begin(), uniformVarMap.end(), TVarEntryInfo::TOrderByPriority());
+
     bool hadError = false;
     TNotifyInOutAdaptor inOutNotify(stage, *resolver);
     TNotifyUniformAdaptor uniformNotify(stage, *resolver);
-    TResolverUniformAdaptor uniformResolve(stage, *resolver, infoSink, hadError);
-    TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError);
+    TResolverUniformAdaptor uniformResolve(stage, *resolver, infoSink, hadError, intermediate);
+    TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError, intermediate);
     resolver->beginNotifications(stage);
     std::for_each(inVarMap.begin(), inVarMap.end(), inOutNotify);
     std::for_each(outVarMap.begin(), outVarMap.end(), inOutNotify);
-    std::for_each(uniformVector.begin(), uniformVector.end(), uniformNotify);
+    std::for_each(uniformVarMap.begin(), uniformVarMap.end(), uniformNotify);
     resolver->endNotifications(stage);
     resolver->beginResolve(stage);
     std::for_each(inVarMap.begin(), inVarMap.end(), inOutResolve);
     std::for_each(outVarMap.begin(), outVarMap.end(), inOutResolve);
-    std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve);
-    std::for_each(uniformVector.begin(), uniformVector.end(), [&uniformVarMap](TVarLivePair p) {
-        auto at = uniformVarMap.find(p.second.symbol->getName());
-        if (at != uniformVarMap.end())
-            at->second = p.second;
-    });
+    std::for_each(uniformVarMap.begin(), uniformVarMap.end(), uniformResolve);
     resolver->endResolve(stage);
+
     if (!hadError) {
+        // sort by id again, so we can use lower bound to find entries
+        std::sort(uniformVarMap.begin(), uniformVarMap.end(), TVarEntryInfo::TOrderById());
         TVarSetTraverser iter_iomap(intermediate, inVarMap, outVarMap, uniformVarMap);
         root->traverse(&iter_iomap);
     }
-    return !hadError;
-}
-
-// Map I/O variables to provided offsets, and make bindings for
-// unbound but live variables.
-//
-// Returns false if the input is too malformed to do this.
-bool TGlslIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) {
 
-    bool somethingToDo = ! intermediate.getResourceSetBinding().empty() || intermediate.getAutoMapBindings() ||
-                         intermediate.getAutoMapLocations();
-    for (int res = 0; res < EResCount; ++res) {
-        somethingToDo = somethingToDo || (intermediate.getShiftBinding(TResourceType(res)) != 0) ||
-                        intermediate.hasShiftBindingForSet(TResourceType(res));
-    }
-    if (! somethingToDo && resolver == nullptr) {
-        return true;
-    }
-    if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive()) {
-        return false;
-    }
-    TIntermNode* root = intermediate.getTreeRoot();
-    if (root == nullptr) {
-        return false;
-    }
-    // if no resolver is provided, use the default resolver with the given shifts and auto map settings
-    TDefaultGlslIoResolver defaultResolver(intermediate);
-    if (resolver == nullptr) {
-        resolver = &defaultResolver;
-    }
-    resolver->addStage(stage);
-    inVarMaps[stage] = new TVarLiveMap, outVarMaps[stage] = new TVarLiveMap(), uniformVarMap[stage] = new TVarLiveMap();
-    TVarGatherTraverser iter_binding_all(intermediate, true, *inVarMaps[stage], *outVarMaps[stage],
-                                         *uniformVarMap[stage]);
-    TVarGatherTraverser iter_binding_live(intermediate, false, *inVarMaps[stage], *outVarMaps[stage],
-                                          *uniformVarMap[stage]);
-    root->traverse(&iter_binding_all);
-    iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str());
-    while (! iter_binding_live.functions.empty()) {
-        TIntermNode* function = iter_binding_live.functions.back();
-        iter_binding_live.functions.pop_back();
-        function->traverse(&iter_binding_live);
-    }
-    TNotifyInOutAdaptor inOutNotify(stage, *resolver);
-    TNotifyUniformAdaptor uniformNotify(stage, *resolver);
-    // Resolve current stage input symbol location with previous stage output here,
-    // uniform symbol, ubo, ssbo and opaque symbols are per-program resource,
-    // will resolve uniform symbol location and ubo/ssbo/opaque binding in doMap()
-    resolver->beginNotifications(stage);
-    std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), inOutNotify);
-    std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), inOutNotify);
-    std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(), uniformNotify);
-    resolver->endNotifications(stage);
-    TSlotCollector slotCollector(*resolver, infoSink);
-    resolver->beginCollect(stage);
-    std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), slotCollector);
-    std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), slotCollector);
-    std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(), slotCollector);
-    resolver->endCollect(stage);
-    intermediates[stage] = &intermediate;
     return !hadError;
 }
 
-bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) {
-    resolver->endResolve(EShLangCount);
-    if (!hadError) {
-        //Resolve uniform location, ubo/ssbo/opaque bindings across stages
-        TResolverUniformAdaptor uniformResolve(EShLangCount, *resolver, infoSink, hadError);
-        TResolverInOutAdaptor inOutResolve(EShLangCount, *resolver, infoSink, hadError);
-        TSymbolValidater symbolValidater(*resolver, infoSink, inVarMaps, outVarMaps, uniformVarMap, hadError);
-        TVarLiveVector uniformVector;
-        resolver->beginResolve(EShLangCount);
-        for (int stage = EShLangVertex; stage < EShLangCount; stage++) {
-            if (inVarMaps[stage] != nullptr) {
-                inOutResolve.setStage(EShLanguage(stage));
-                std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), symbolValidater);
-                std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), inOutResolve);
-                std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), symbolValidater);
-                std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), inOutResolve);
-            }
-            if (uniformVarMap[stage] != nullptr) {
-                uniformResolve.setStage(EShLanguage(stage));
-                // sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
-                std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(),
-                              [&uniformVector](TVarLivePair p) { uniformVector.push_back(p); });
-            }
-        }
-        std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
-            return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
-        });
-        std::for_each(uniformVector.begin(), uniformVector.end(), symbolValidater);
-        std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve);
-        std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
-            return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
-        });
-        resolver->endResolve(EShLangCount);
-        for (size_t stage = 0; stage < EShLangCount; stage++) {
-            if (intermediates[stage] != nullptr) {
-                // traverse each stage, set new location to each input/output and unifom symbol, set new binding to
-                // ubo, ssbo and opaque symbols
-                TVarLiveMap** pUniformVarMap = uniformVarMap;
-                std::for_each(uniformVector.begin(), uniformVector.end(), [pUniformVarMap, stage](TVarLivePair p) {
-                    auto at = pUniformVarMap[stage]->find(p.second.symbol->getName());
-                    if (at != pUniformVarMap[stage]->end())
-                        at->second = p.second;
-                });
-                TVarSetTraverser iter_iomap(*intermediates[stage], *inVarMaps[stage], *outVarMaps[stage],
-                                            *uniformVarMap[stage]);
-                intermediates[stage]->getTreeRoot()->traverse(&iter_iomap);
-            }
-        }
-        return !hadError;
-    } else {
-        return false;
-    }
-}
-
 } // end namespace glslang
index 9fef6e3..5e0d439 100644 (file)
@@ -36,9 +36,8 @@
 #ifndef _IOMAPPER_INCLUDED
 #define _IOMAPPER_INCLUDED
 
-#include "LiveTraverser.h"
-#include <unordered_map>
-#include <unordered_set>
+#include "../Public/ShaderLang.h"
+
 //
 // A reflection database and its interface, consistent with the OpenGL API reflection queries.
 //
@@ -48,245 +47,15 @@ class TInfoSink;
 namespace glslang {
 
 class TIntermediate;
-struct TVarEntryInfo {
-    int id;
-    TIntermSymbol* symbol;
-    bool live;
-    int newBinding;
-    int newSet;
-    int newLocation;
-    int newComponent;
-    int newIndex;
-    EShLanguage stage;
-    struct TOrderById {
-        inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) { return l.id < r.id; }
-    };
-
-    struct TOrderByPriority {
-        // ordering:
-        // 1) has both binding and set
-        // 2) has binding but no set
-        // 3) has no binding but set
-        // 4) has no binding and no set
-        inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) {
-            const TQualifier& lq = l.symbol->getQualifier();
-            const TQualifier& rq = r.symbol->getQualifier();
-
-            // simple rules:
-            // has binding gives 2 points
-            // has set gives 1 point
-            // who has the most points is more important.
-            int lPoints = (lq.hasBinding() ? 2 : 0) + (lq.hasSet() ? 1 : 0);
-            int rPoints = (rq.hasBinding() ? 2 : 0) + (rq.hasSet() ? 1 : 0);
-
-            if (lPoints == rPoints)
-                return l.id < r.id;
-            return lPoints > rPoints;
-        }
-    };
-};
-
-// Base class for shared TIoMapResolver services, used by several derivations.
-struct TDefaultIoResolverBase : public glslang::TIoMapResolver {
-public:
-    TDefaultIoResolverBase(const TIntermediate& intermediate);
-    typedef std::vector<int> TSlotSet;
-    typedef std::unordered_map<int, TSlotSet> TSlotSetMap;
-
-    // grow the reflection stage by stage
-    void notifyBinding(EShLanguage, TVarEntryInfo& /*ent*/) override {}
-    void notifyInOut(EShLanguage, TVarEntryInfo& /*ent*/) override {}
-    void beginNotifications(EShLanguage) override {}
-    void endNotifications(EShLanguage) override {}
-    void beginResolve(EShLanguage) override {}
-    void endResolve(EShLanguage) override {}
-    void beginCollect(EShLanguage) override {}
-    void endCollect(EShLanguage) override {}
-    void reserverResourceSlot(TVarEntryInfo& /*ent*/, TInfoSink& /*infoSink*/) override {}
-    void reserverStorageSlot(TVarEntryInfo& /*ent*/, TInfoSink& /*infoSink*/) override {}
-    int getBaseBinding(TResourceType res, unsigned int set) const;
-    const std::vector<std::string>& getResourceSetBinding() const;
-    virtual TResourceType getResourceType(const glslang::TType& type) = 0;
-    bool doAutoBindingMapping() const;
-    bool doAutoLocationMapping() const;
-    TSlotSet::iterator findSlot(int set, int slot);
-    bool checkEmpty(int set, int slot);
-    bool validateInOut(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; };
-    int reserveSlot(int set, int slot, int size = 1);
-    int getFreeSlot(int set, int base, int size = 1);
-    int resolveSet(EShLanguage /*stage*/, TVarEntryInfo& ent) override;
-    int resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) override;
-    int resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) override;
-    int resolveInOutComponent(EShLanguage /*stage*/, TVarEntryInfo& ent) override;
-    int resolveInOutIndex(EShLanguage /*stage*/, TVarEntryInfo& ent) override;
-    void addStage(EShLanguage stage) override {
-        if (stage < EShLangCount)
-            stageMask[stage] = true;
-    };
-    uint32_t computeTypeLocationSize(const TType& type, EShLanguage stage);
-
-    TSlotSetMap slots;
-
-protected:
-    TDefaultIoResolverBase(TDefaultIoResolverBase&);
-    TDefaultIoResolverBase& operator=(TDefaultIoResolverBase&);
-    const TIntermediate& intermediate;
-    int nextUniformLocation;
-    int nextInputLocation;
-    int nextOutputLocation;
-    bool stageMask[EShLangCount + 1];
-    // Return descriptor set specific base if there is one, and the generic base otherwise.
-    int selectBaseBinding(int base, int descriptorSetBase) const {
-        return descriptorSetBase != -1 ? descriptorSetBase : base;
-    }
-
-    static int getLayoutSet(const glslang::TType& type) {
-        if (type.getQualifier().hasSet())
-            return type.getQualifier().layoutSet;
-        else
-            return 0;
-    }
-
-    static bool isSamplerType(const glslang::TType& type) {
-        return type.getBasicType() == glslang::EbtSampler && type.getSampler().isPureSampler();
-    }
-
-    static bool isTextureType(const glslang::TType& type) {
-        return (type.getBasicType() == glslang::EbtSampler &&
-                (type.getSampler().isTexture() || type.getSampler().isSubpass()));
-    }
-
-    static bool isUboType(const glslang::TType& type) {
-        return type.getQualifier().storage == EvqUniform;
-    }
-
-    static bool isImageType(const glslang::TType& type) {
-        return type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage();
-    }
-
-    static bool isSsboType(const glslang::TType& type) {
-        return type.getQualifier().storage == EvqBuffer;
-    }
-
-    // Return true if this is a SRV (shader resource view) type:
-    static bool isSrvType(const glslang::TType& type) {
-        return isTextureType(type) || type.getQualifier().storage == EvqBuffer;
-    }
-
-    // Return true if this is a UAV (unordered access view) type:
-    static bool isUavType(const glslang::TType& type) {
-        if (type.getQualifier().readonly)
-            return false;
-        return (type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage()) ||
-                (type.getQualifier().storage == EvqBuffer);
-    }
-};
-
-// Defaulf I/O resolver for OpenGL
-struct TDefaultGlslIoResolver : public TDefaultIoResolverBase {
-public:
-    typedef std::map<TString, int> TVarSlotMap;  // <resourceName, location/binding>
-    typedef std::map<int, TVarSlotMap> TSlotMap; // <resourceKey, TVarSlotMap>
-    TDefaultGlslIoResolver(const TIntermediate& intermediate);
-    bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) { return true; };
-    TResourceType getResourceType(const glslang::TType& type) override;
-    int resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) override;
-    int resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) override;
-    int resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent);
-    void beginResolve(EShLanguage /*stage*/);
-    void endResolve(EShLanguage stage);
-    void beginCollect(EShLanguage) override;
-    void endCollect(EShLanguage) override;
-    void reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink);
-    void reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink);
-    // in/out symbol and uniform symbol are stored in the same resourceSlotMap, the storage key is used to identify each type of symbol.
-    // We use stage and storage qualifier to construct a storage key. it can help us identify the same storage resource used in different stage.
-    // if a resource is a program resource and we don't need know it usage stage, we can use same stage to build storage key.
-    // Note: both stage and type must less then 0xffff.
-    int buildStorageKey(EShLanguage stage, TStorageQualifier type) {
-        assert(stage <= 0xffff && type <= 0xffff);
-        return (stage << 16) | type;
-    };
-
-protected:
-    // Use for mark pre stage, to get more interface symbol information.
-    EShLanguage preStage;
-    // Use for mark current shader stage for resolver
-    EShLanguage currentStage;
-    // Slot map for storage resource(location of uniform and interface symbol) It's a program share slot
-    TSlotMap resourceSlotMap;
-    // Slot map for other resource(image, ubo, ssbo), It's a program share slot.
-    TSlotMap storageSlotMap;
-};
-
-typedef std::map<TString, TVarEntryInfo> TVarLiveMap;
-
-// override function "operator=", if a vector<const _Kty, _Ty> being sort,
-// when use vc++, the sort function will call :
-// pair& operator=(const pair<_Other1, _Other2>& _Right)
-// {
-//     first = _Right.first;
-//     second = _Right.second;
-//     return (*this);
-// }
-// that will make a const type handing on left.
-// override this function can avoid a compiler error.
-// In the future, if the vc++ compiler can handle such a situation,
-// this part of the code will be removed.
-struct TVarLivePair : std::pair<const TString, TVarEntryInfo> {
-    TVarLivePair(std::pair<const TString, TVarEntryInfo>& _Right) : pair(_Right.first, _Right.second) {}
-    TVarLivePair& operator=(const TVarLivePair& _Right) {
-        const_cast<TString&>(first) = _Right.first;
-        second = _Right.second;
-        return (*this);
-    };
-};
-typedef std::vector<TVarLivePair> TVarLiveVector;
 
 // I/O mapper
 class TIoMapper {
 public:
     TIoMapper() {}
     virtual ~TIoMapper() {}
-    // grow the reflection stage by stage
-    bool virtual addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*);
-    bool virtual doMap(TIoMapResolver*, TInfoSink&) { return true; };
-};
 
-// I/O mapper for OpenGL
-class TGlslIoMapper : public TIoMapper {
-public:
-    TGlslIoMapper() {
-        memset(inVarMaps,     0, sizeof(TVarLiveMap*)   * (EShLangCount + 1));
-        memset(outVarMaps,    0, sizeof(TVarLiveMap*)   * (EShLangCount + 1));
-        memset(uniformVarMap, 0, sizeof(TVarLiveMap*)   * (EShLangCount + 1));
-        memset(intermediates, 0, sizeof(TIntermediate*) * (EShLangCount + 1));
-    }
-    virtual ~TGlslIoMapper() {
-        for (size_t stage = 0; stage < EShLangCount; stage++) {
-            if (inVarMaps[stage] != nullptr) {
-                delete inVarMaps[stage];
-                inVarMaps[stage] = nullptr;
-            }
-            if (outVarMaps[stage] != nullptr) {
-                delete outVarMaps[stage];
-                outVarMaps[stage] = nullptr;
-            }
-            if (uniformVarMap[stage] != nullptr) {
-                delete uniformVarMap[stage];
-                uniformVarMap[stage] = nullptr;
-            }
-            if (intermediates[stage] != nullptr)
-                intermediates[stage] = nullptr;
-        }
-    }
     // grow the reflection stage by stage
-    bool addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*) override;
-    bool doMap(TIoMapResolver*, TInfoSink&) override;
-    TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount],
-                *uniformVarMap[EShLangCount];
-    TIntermediate* intermediates[EShLangCount];
-    bool hadError = false;
+    bool addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*);
 };
 
 } // end namespace glslang
index 8811ca1..954ce8e 100755 (executable)
@@ -646,9 +646,8 @@ protected:
     const TType* type;
 };
 
-class  TReflection;
-class  TIoMapper;
-struct TVarEntryInfo;
+class TReflection;
+class TIoMapper;
 
 // Allows to customize the binding layout after linking.
 // All used uniform variables will invoke at least validateBinding.
@@ -669,61 +668,51 @@ struct TVarEntryInfo;
 // notifiy callbacks, this phase ends with a call to endNotifications.
 // Phase two starts directly after the call to endNotifications
 // and calls all other callbacks to validate and to get the
-// bindings, sets, locations, component and color indices.
+// bindings, sets, locations, component and color indices. 
 //
 // NOTE: that still limit checks are applied to bindings and sets
 // and may result in an error.
 class TIoMapResolver
 {
 public:
-    virtual ~TIoMapResolver() {}
-
-    // Should return true if the resulting/current binding would be okay.
-    // Basic idea is to do aliasing binding checks with this.
-    virtual bool validateBinding(EShLanguage stage, TVarEntryInfo& ent) = 0;
-    // Should return a value >= 0 if the current binding should be overridden.
-    // Return -1 if the current binding (including no binding) should be kept.
-    virtual int resolveBinding(EShLanguage stage, TVarEntryInfo& ent) = 0;
-    // Should return a value >= 0 if the current set should be overridden.
-    // Return -1 if the current set (including no set) should be kept.
-    virtual int resolveSet(EShLanguage stage, TVarEntryInfo& ent) = 0;
-    // Should return a value >= 0 if the current location should be overridden.
-    // Return -1 if the current location (including no location) should be kept.
-    virtual int resolveUniformLocation(EShLanguage stage, TVarEntryInfo& ent) = 0;
-    // Should return true if the resulting/current setup would be okay.
-    // Basic idea is to do aliasing checks and reject invalid semantic names.
-    virtual bool validateInOut(EShLanguage stage, TVarEntryInfo& ent) = 0;
-    // Should return a value >= 0 if the current location should be overridden.
-    // Return -1 if the current location (including no location) should be kept.
-    virtual int resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) = 0;
-    // Should return a value >= 0 if the current component index should be overridden.
-    // Return -1 if the current component index (including no index) should be kept.
-    virtual int resolveInOutComponent(EShLanguage stage, TVarEntryInfo& ent) = 0;
-    // Should return a value >= 0 if the current color index should be overridden.
-    // Return -1 if the current color index (including no index) should be kept.
-    virtual int resolveInOutIndex(EShLanguage stage, TVarEntryInfo& ent) = 0;
-    // Notification of a uniform variable
-    virtual void notifyBinding(EShLanguage stage, TVarEntryInfo& ent) = 0;
-    // Notification of a in or out variable
-    virtual void notifyInOut(EShLanguage stage, TVarEntryInfo& ent) = 0;
-    // Called by mapIO when it starts its notify pass for the given stage
-    virtual void beginNotifications(EShLanguage stage) = 0;
-    // Called by mapIO when it has finished the notify pass
-    virtual void endNotifications(EShLanguage stage) = 0;
-    // Called by mipIO when it starts its resolve pass for the given stage
-    virtual void beginResolve(EShLanguage stage) = 0;
-    // Called by mapIO when it has finished the resolve pass
-    virtual void endResolve(EShLanguage stage) = 0;
-    // Called by mapIO when it starts its symbol collect for teh given stage
-    virtual void beginCollect(EShLanguage stage) = 0;
-    // Called by mapIO when it has finished the symbol collect
-    virtual void endCollect(EShLanguage stage) = 0;
-    // Called by TSlotCollector to resolve storage locations or bindings
-    virtual void reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) = 0;
-    // Called by TSlotCollector to resolve resource locations or bindings
-    virtual void reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) = 0;
-    // Called by mapIO.addStage to set shader stage mask to mark a stage be added to this pipeline
-    virtual void addStage(EShLanguage stage) = 0;
+  virtual ~TIoMapResolver() {}
+
+  // Should return true if the resulting/current binding would be okay.
+  // Basic idea is to do aliasing binding checks with this.
+  virtual bool validateBinding(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
+  // Should return a value >= 0 if the current binding should be overridden.
+  // Return -1 if the current binding (including no binding) should be kept.
+  virtual int resolveBinding(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
+  // Should return a value >= 0 if the current set should be overridden.
+  // 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 a value >= 0 if the current location should be overridden.
+  // Return -1 if the current location (including no location) should be kept.
+  virtual int resolveUniformLocation(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
+  // Should return true if the resulting/current setup would be okay.
+  // 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 overridden.
+  // 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 overridden.
+  // 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 overridden.
+  // 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;
+  // Notification of a uniform variable
+  virtual void notifyBinding(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
+  // Notification of a in or out variable
+  virtual void notifyInOut(EShLanguage stage, const char* name, const TType& type, bool is_live) = 0;
+  // Called by mapIO when it has finished the notify pass
+  virtual void endNotifications(EShLanguage stage) = 0;
+  // Called by mapIO when it starts its notify pass for the given stage
+  virtual void beginNotifications(EShLanguage stage) = 0;
+  // Called by mipIO when it starts its resolve pass for the given stage
+  virtual void beginResolve(EShLanguage stage) = 0;
+  // Called by mapIO when it has finished the resolve pass
+  virtual void endResolve(EShLanguage stage) = 0;
 };
 
 // Make one TProgram per set of shaders that will get linked together.  Add all
@@ -835,7 +824,7 @@ public:
     // I/O mapping: apply base offsets and map live unbound variables
     // If resolver is not provided it uses the previous approach
     // and respects auto assignment and offsets.
-    bool mapIO(TIoMapResolver* pResolver = nullptr, TIoMapper* pIoMapper = nullptr);
+    bool mapIO(TIoMapResolver* resolver = NULL);
 
 protected:
     bool linkStage(EShLanguage, EShMessages);
@@ -846,6 +835,7 @@ protected:
     bool newedIntermediate[EShLangCount];      // track which intermediate were "new" versus reusing a singleton unit in a stage
     TInfoSink* infoSink;
     TReflection* reflection;
+    TIoMapper* ioMapper;
     bool linked;
 
 private: