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     // in/out symbol and uniform symbol are stored in the same resourceSlotMap, the storage key is used to identify each type of symbol.
207     // We use stage and storage qualifier to construct a storage key. it can help us identify the same storage resource used in different stage.
208     // 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.
209     // Note: both stage and type must less then 0xffff.
buildStorageKeyTDefaultGlslIoResolver210     int buildStorageKey(EShLanguage stage, TStorageQualifier type) {
211         assert(static_cast<uint32_t>(stage) <= 0x0000ffff && static_cast<uint32_t>(type) <= 0x0000ffff);
212         return (stage << 16) | type;
213     }
214 
215 protected:
216     // Use for mark pre stage, to get more interface symbol information.
217     EShLanguage preStage;
218     // Use for mark current shader stage for resolver
219     EShLanguage currentStage;
220     // Slot map for storage resource(location of uniform and interface symbol) It's a program share slot
221     TSlotMap resourceSlotMap;
222     // Slot map for other resource(image, ubo, ssbo), It's a program share slot.
223     TSlotMap storageSlotMap;
224 };
225 
226 typedef std::map<TString, TVarEntryInfo> TVarLiveMap;
227 
228 // override function "operator=", if a vector<const _Kty, _Ty> being sort,
229 // when use vc++, the sort function will call :
230 // pair& operator=(const pair<_Other1, _Other2>& _Right)
231 // {
232 //     first = _Right.first;
233 //     second = _Right.second;
234 //     return (*this);
235 // }
236 // that will make a const type handing on left.
237 // override this function can avoid a compiler error.
238 // In the future, if the vc++ compiler can handle such a situation,
239 // this part of the code will be removed.
240 struct TVarLivePair : std::pair<const TString, TVarEntryInfo> {
TVarLivePairTVarLivePair241     TVarLivePair(const std::pair<const TString, TVarEntryInfo>& _Right) : pair(_Right.first, _Right.second) {}
242     TVarLivePair& operator=(const TVarLivePair& _Right) {
243         const_cast<TString&>(first) = _Right.first;
244         second = _Right.second;
245         return (*this);
246     }
TVarLivePairTVarLivePair247     TVarLivePair(const TVarLivePair& src) : pair(src) { }
248 };
249 typedef std::vector<TVarLivePair> TVarLiveVector;
250 
251 // I/O mapper
252 class TIoMapper {
253 public:
TIoMapper()254     TIoMapper() {}
~TIoMapper()255     virtual ~TIoMapper() {}
256     // grow the reflection stage by stage
257     bool virtual addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*);
doMap(TIoMapResolver *,TInfoSink &)258     bool virtual doMap(TIoMapResolver*, TInfoSink&) { return true; }
259 };
260 
261 // I/O mapper for OpenGL
262 class TGlslIoMapper : public TIoMapper {
263 public:
TGlslIoMapper()264     TGlslIoMapper() {
265         memset(inVarMaps,     0, sizeof(TVarLiveMap*)   * (EShLangCount + 1));
266         memset(outVarMaps,    0, sizeof(TVarLiveMap*)   * (EShLangCount + 1));
267         memset(uniformVarMap, 0, sizeof(TVarLiveMap*)   * (EShLangCount + 1));
268         memset(intermediates, 0, sizeof(TIntermediate*) * (EShLangCount + 1));
269         profile = ENoProfile;
270         version = 0;
271     }
~TGlslIoMapper()272     virtual ~TGlslIoMapper() {
273         for (size_t stage = 0; stage < EShLangCount; stage++) {
274             if (inVarMaps[stage] != nullptr) {
275                 delete inVarMaps[stage];
276                 inVarMaps[stage] = nullptr;
277             }
278             if (outVarMaps[stage] != nullptr) {
279                 delete outVarMaps[stage];
280                 outVarMaps[stage] = nullptr;
281             }
282             if (uniformVarMap[stage] != nullptr) {
283                 delete uniformVarMap[stage];
284                 uniformVarMap[stage] = nullptr;
285             }
286             if (intermediates[stage] != nullptr)
287                 intermediates[stage] = nullptr;
288         }
289     }
290     // grow the reflection stage by stage
291     bool addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*) override;
292     bool doMap(TIoMapResolver*, TInfoSink&) override;
293     TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount],
294                 *uniformVarMap[EShLangCount];
295     TIntermediate* intermediates[EShLangCount];
296     bool hadError = false;
297     EProfile profile;
298     int version;
299 };
300 
301 } // end namespace glslang
302 
303 #endif // _IOMAPPER_INCLUDED
304 
305 #endif // !GLSLANG_WEB && !GLSLANG_ANGLE
306