1 // 2 // Copyright (C) 2016 LunarG, Inc. 3 // 4 // All rights reserved. 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions 8 // are met: 9 // 10 // Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // 13 // Redistributions in binary form must reproduce the above 14 // copyright notice, this list of conditions and the following 15 // disclaimer in the documentation and/or other materials provided 16 // with the distribution. 17 // 18 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its 19 // contributors may be used to endorse or promote products derived 20 // from this software without specific prior written permission. 21 // 22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 // POSSIBILITY OF SUCH DAMAGE. 34 // 35 36 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) 37 38 #ifndef _IOMAPPER_INCLUDED 39 #define _IOMAPPER_INCLUDED 40 41 #include <cstdint> 42 #include "LiveTraverser.h" 43 #include <unordered_map> 44 #include <unordered_set> 45 // 46 // A reflection database and its interface, consistent with the OpenGL API reflection queries. 47 // 48 49 class TInfoSink; 50 51 namespace glslang { 52 53 class TIntermediate; 54 struct TVarEntryInfo { 55 int id; 56 TIntermSymbol* symbol; 57 bool live; 58 int newBinding; 59 int newSet; 60 int newLocation; 61 int newComponent; 62 int newIndex; 63 EShLanguage stage; 64 struct TOrderById { operatorTVarEntryInfo::TOrderById65 inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) { return l.id < r.id; } 66 }; 67 68 struct TOrderByPriority { 69 // ordering: 70 // 1) has both binding and set 71 // 2) has binding but no set 72 // 3) has no binding but set 73 // 4) has no binding and no set operatorTVarEntryInfo::TOrderByPriority74 inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) { 75 const TQualifier& lq = l.symbol->getQualifier(); 76 const TQualifier& rq = r.symbol->getQualifier(); 77 78 // simple rules: 79 // has binding gives 2 points 80 // has set gives 1 point 81 // who has the most points is more important. 82 int lPoints = (lq.hasBinding() ? 2 : 0) + (lq.hasSet() ? 1 : 0); 83 int rPoints = (rq.hasBinding() ? 2 : 0) + (rq.hasSet() ? 1 : 0); 84 85 if (lPoints == rPoints) 86 return l.id < r.id; 87 return lPoints > rPoints; 88 } 89 }; 90 }; 91 92 // Base class for shared TIoMapResolver services, used by several derivations. 93 struct TDefaultIoResolverBase : public glslang::TIoMapResolver { 94 public: 95 TDefaultIoResolverBase(const TIntermediate& intermediate); 96 typedef std::vector<int> TSlotSet; 97 typedef std::unordered_map<int, TSlotSet> TSlotSetMap; 98 99 // grow the reflection stage by stage notifyBindingTDefaultIoResolverBase100 void notifyBinding(EShLanguage, TVarEntryInfo& /*ent*/) override {} notifyInOutTDefaultIoResolverBase101 void notifyInOut(EShLanguage, TVarEntryInfo& /*ent*/) override {} beginNotificationsTDefaultIoResolverBase102 void beginNotifications(EShLanguage) override {} endNotificationsTDefaultIoResolverBase103 void endNotifications(EShLanguage) override {} beginResolveTDefaultIoResolverBase104 void beginResolve(EShLanguage) override {} endResolveTDefaultIoResolverBase105 void endResolve(EShLanguage) override {} beginCollectTDefaultIoResolverBase106 void beginCollect(EShLanguage) override {} endCollectTDefaultIoResolverBase107 void endCollect(EShLanguage) override {} reserverResourceSlotTDefaultIoResolverBase108 void reserverResourceSlot(TVarEntryInfo& /*ent*/, TInfoSink& /*infoSink*/) override {} reserverStorageSlotTDefaultIoResolverBase109 void reserverStorageSlot(TVarEntryInfo& /*ent*/, TInfoSink& /*infoSink*/) override {} 110 int getBaseBinding(TResourceType res, unsigned int set) const; 111 const std::vector<std::string>& getResourceSetBinding() const; 112 virtual TResourceType getResourceType(const glslang::TType& type) = 0; 113 bool doAutoBindingMapping() const; 114 bool doAutoLocationMapping() const; 115 TSlotSet::iterator findSlot(int set, int slot); 116 bool checkEmpty(int set, int slot); validateInOutTDefaultIoResolverBase117 bool validateInOut(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; } 118 int reserveSlot(int set, int slot, int size = 1); 119 int getFreeSlot(int set, int base, int size = 1); 120 int resolveSet(EShLanguage /*stage*/, TVarEntryInfo& ent) override; 121 int resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) override; 122 int resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) override; 123 int resolveInOutComponent(EShLanguage /*stage*/, TVarEntryInfo& ent) override; 124 int resolveInOutIndex(EShLanguage /*stage*/, TVarEntryInfo& ent) override; addStageTDefaultIoResolverBase125 void addStage(EShLanguage stage) override { 126 if (stage < EShLangCount) 127 stageMask[stage] = true; 128 } 129 uint32_t computeTypeLocationSize(const TType& type, EShLanguage stage); 130 131 TSlotSetMap slots; 132 bool hasError = false; 133 134 protected: 135 TDefaultIoResolverBase(TDefaultIoResolverBase&); 136 TDefaultIoResolverBase& operator=(TDefaultIoResolverBase&); 137 const TIntermediate& intermediate; 138 int nextUniformLocation; 139 int nextInputLocation; 140 int nextOutputLocation; 141 bool stageMask[EShLangCount + 1]; 142 // Return descriptor set specific base if there is one, and the generic base otherwise. selectBaseBindingTDefaultIoResolverBase143 int selectBaseBinding(int base, int descriptorSetBase) const { 144 return descriptorSetBase != -1 ? descriptorSetBase : base; 145 } 146 getLayoutSetTDefaultIoResolverBase147 static int getLayoutSet(const glslang::TType& type) { 148 if (type.getQualifier().hasSet()) 149 return type.getQualifier().layoutSet; 150 else 151 return 0; 152 } 153 isSamplerTypeTDefaultIoResolverBase154 static bool isSamplerType(const glslang::TType& type) { 155 return type.getBasicType() == glslang::EbtSampler && type.getSampler().isPureSampler(); 156 } 157 isTextureTypeTDefaultIoResolverBase158 static bool isTextureType(const glslang::TType& type) { 159 return (type.getBasicType() == glslang::EbtSampler && 160 (type.getSampler().isTexture() || type.getSampler().isSubpass())); 161 } 162 isUboTypeTDefaultIoResolverBase163 static bool isUboType(const glslang::TType& type) { 164 return type.getQualifier().storage == EvqUniform; 165 } 166 isImageTypeTDefaultIoResolverBase167 static bool isImageType(const glslang::TType& type) { 168 return type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage(); 169 } 170 isSsboTypeTDefaultIoResolverBase171 static bool isSsboType(const glslang::TType& type) { 172 return type.getQualifier().storage == EvqBuffer; 173 } 174 175 // Return true if this is a SRV (shader resource view) type: isSrvTypeTDefaultIoResolverBase176 static bool isSrvType(const glslang::TType& type) { 177 return isTextureType(type) || type.getQualifier().storage == EvqBuffer; 178 } 179 180 // Return true if this is a UAV (unordered access view) type: isUavTypeTDefaultIoResolverBase181 static bool isUavType(const glslang::TType& type) { 182 if (type.getQualifier().isReadOnly()) 183 return false; 184 return (type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage()) || 185 (type.getQualifier().storage == EvqBuffer); 186 } 187 }; 188 189 // Default I/O resolver for OpenGL 190 struct TDefaultGlslIoResolver : public TDefaultIoResolverBase { 191 public: 192 typedef std::map<TString, int> TVarSlotMap; // <resourceName, location/binding> 193 typedef std::map<int, TVarSlotMap> TSlotMap; // <resourceKey, TVarSlotMap> 194 TDefaultGlslIoResolver(const TIntermediate& intermediate); validateBindingTDefaultGlslIoResolver195 bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; } 196 TResourceType getResourceType(const glslang::TType& type) override; 197 int resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) override; 198 int resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) override; 199 int resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) override; 200 void beginResolve(EShLanguage /*stage*/) override; 201 void endResolve(EShLanguage stage) override; 202 void beginCollect(EShLanguage) override; 203 void endCollect(EShLanguage) override; 204 void reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override; 205 void reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override; 206 const TString& getAccessName(const TIntermSymbol*); 207 // in/out symbol and uniform symbol are stored in the same resourceSlotMap, the storage key is used to identify each type of symbol. 208 // We use stage and storage qualifier to construct a storage key. it can help us identify the same storage resource used in different stage. 209 // 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. 210 // Note: both stage and type must less then 0xffff. buildStorageKeyTDefaultGlslIoResolver211 int buildStorageKey(EShLanguage stage, TStorageQualifier type) { 212 assert(static_cast<uint32_t>(stage) <= 0x0000ffff && static_cast<uint32_t>(type) <= 0x0000ffff); 213 return (stage << 16) | type; 214 } 215 216 protected: 217 // Use for mark pre stage, to get more interface symbol information. 218 EShLanguage preStage; 219 // Use for mark current shader stage for resolver 220 EShLanguage currentStage; 221 // Slot map for storage resource(location of uniform and interface symbol) It's a program share slot 222 TSlotMap resourceSlotMap; 223 // Slot map for other resource(image, ubo, ssbo), It's a program share slot. 224 TSlotMap storageSlotMap; 225 }; 226 227 typedef std::map<TString, TVarEntryInfo> TVarLiveMap; 228 229 // override function "operator=", if a vector<const _Kty, _Ty> being sort, 230 // when use vc++, the sort function will call : 231 // pair& operator=(const pair<_Other1, _Other2>& _Right) 232 // { 233 // first = _Right.first; 234 // second = _Right.second; 235 // return (*this); 236 // } 237 // that will make a const type handing on left. 238 // override this function can avoid a compiler error. 239 // In the future, if the vc++ compiler can handle such a situation, 240 // this part of the code will be removed. 241 struct TVarLivePair : std::pair<const TString, TVarEntryInfo> { TVarLivePairTVarLivePair242 TVarLivePair(const std::pair<const TString, TVarEntryInfo>& _Right) : pair(_Right.first, _Right.second) {} 243 TVarLivePair& operator=(const TVarLivePair& _Right) { 244 const_cast<TString&>(first) = _Right.first; 245 second = _Right.second; 246 return (*this); 247 } TVarLivePairTVarLivePair248 TVarLivePair(const TVarLivePair& src) : pair(src) { } 249 }; 250 typedef std::vector<TVarLivePair> TVarLiveVector; 251 252 // I/O mapper 253 class TIoMapper { 254 public: TIoMapper()255 TIoMapper() {} ~TIoMapper()256 virtual ~TIoMapper() {} 257 // grow the reflection stage by stage 258 bool virtual addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*); doMap(TIoMapResolver *,TInfoSink &)259 bool virtual doMap(TIoMapResolver*, TInfoSink&) { return true; } 260 }; 261 262 // I/O mapper for OpenGL 263 class TGlslIoMapper : public TIoMapper { 264 public: TGlslIoMapper()265 TGlslIoMapper() { 266 memset(inVarMaps, 0, sizeof(TVarLiveMap*) * EShLangCount); 267 memset(outVarMaps, 0, sizeof(TVarLiveMap*) * EShLangCount); 268 memset(uniformVarMap, 0, sizeof(TVarLiveMap*) * EShLangCount); 269 memset(intermediates, 0, sizeof(TIntermediate*) * EShLangCount); 270 } ~TGlslIoMapper()271 virtual ~TGlslIoMapper() { 272 for (size_t stage = 0; stage < EShLangCount; stage++) { 273 if (inVarMaps[stage] != nullptr) { 274 delete inVarMaps[stage]; 275 inVarMaps[stage] = nullptr; 276 } 277 if (outVarMaps[stage] != nullptr) { 278 delete outVarMaps[stage]; 279 outVarMaps[stage] = nullptr; 280 } 281 if (uniformVarMap[stage] != nullptr) { 282 delete uniformVarMap[stage]; 283 uniformVarMap[stage] = nullptr; 284 } 285 if (intermediates[stage] != nullptr) 286 intermediates[stage] = nullptr; 287 } 288 } 289 // grow the reflection stage by stage 290 bool addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*) override; 291 bool doMap(TIoMapResolver*, TInfoSink&) override; 292 TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount], 293 *uniformVarMap[EShLangCount]; 294 TIntermediate* intermediates[EShLangCount]; 295 bool hadError = false; 296 }; 297 298 } // end namespace glslang 299 300 #endif // _IOMAPPER_INCLUDED 301 302 #endif // !GLSLANG_WEB && !GLSLANG_ANGLE 303