#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)
{
}
+
virtual void visitSymbol(TIntermSymbol* base)
{
TVarLiveMap* target = nullptr;
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);
}
}
{
}
- virtual void visitSymbol(TIntermSymbol* base) {
+
+ virtual void visitSymbol(TIntermSymbol* base)
+ {
const TVarLiveMap* source;
if (base->getQualifier().storage == EvqVaryingIn)
source = &inputList;
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:
, 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&);
};
{
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;
}
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) {
}
}
- 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
/*
* 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;
}
};
BYTEADDRESSBUFFER
BUFFER
TBUFFER
-
+
s - for samplers
SAMPLER
SAMPLER1D
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())
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