Fix variable scoping of do-while
[platform/upstream/glslang.git] / glslang / MachineIndependent / iomapper.h
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     long long 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 {
65         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
74         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     struct TOrderByPriorityAndLive {
92         // ordering:
93         // 1) do live variables first
94         // 2) has both binding and set
95         // 3) has binding but no set
96         // 4) has no binding but set
97         // 5) has no binding and no set
98         inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) {
99
100             const TQualifier& lq = l.symbol->getQualifier();
101             const TQualifier& rq = r.symbol->getQualifier();
102
103             // simple rules:
104             // has binding gives 2 points
105             // has set gives 1 point
106             // who has the most points is more important.
107             int lPoints = (lq.hasBinding() ? 2 : 0) + (lq.hasSet() ? 1 : 0);
108             int rPoints = (rq.hasBinding() ? 2 : 0) + (rq.hasSet() ? 1 : 0);
109
110             if (l.live != r.live)
111                 return l.live > r.live;
112
113             if (lPoints != rPoints)
114                 return lPoints > rPoints;
115
116             return l.id < r.id;
117         }
118     };
119 };
120
121 // Base class for shared TIoMapResolver services, used by several derivations.
122 struct TDefaultIoResolverBase : public glslang::TIoMapResolver {
123 public:
124     TDefaultIoResolverBase(const TIntermediate& intermediate);
125     typedef std::vector<int> TSlotSet;
126     typedef std::unordered_map<int, TSlotSet> TSlotSetMap;
127
128     // grow the reflection stage by stage
129     void notifyBinding(EShLanguage, TVarEntryInfo& /*ent*/) override {}
130     void notifyInOut(EShLanguage, TVarEntryInfo& /*ent*/) override {}
131     void beginNotifications(EShLanguage) override {}
132     void endNotifications(EShLanguage) override {}
133     void beginResolve(EShLanguage) override {}
134     void endResolve(EShLanguage) override {}
135     void beginCollect(EShLanguage) override {}
136     void endCollect(EShLanguage) override {}
137     void reserverResourceSlot(TVarEntryInfo& /*ent*/, TInfoSink& /*infoSink*/) override {}
138     void reserverStorageSlot(TVarEntryInfo& /*ent*/, TInfoSink& /*infoSink*/) override {}
139     int getBaseBinding(EShLanguage stage, TResourceType res, unsigned int set) const;
140     const std::vector<std::string>& getResourceSetBinding(EShLanguage stage) const;
141     virtual TResourceType getResourceType(const glslang::TType& type) = 0;
142     bool doAutoBindingMapping() const;
143     bool doAutoLocationMapping() const;
144     TSlotSet::iterator findSlot(int set, int slot);
145     bool checkEmpty(int set, int slot);
146     bool validateInOut(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; }
147     int reserveSlot(int set, int slot, int size = 1);
148     int getFreeSlot(int set, int base, int size = 1);
149     int resolveSet(EShLanguage /*stage*/, TVarEntryInfo& ent) override;
150     int resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) override;
151     int resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) override;
152     int resolveInOutComponent(EShLanguage /*stage*/, TVarEntryInfo& ent) override;
153     int resolveInOutIndex(EShLanguage /*stage*/, TVarEntryInfo& ent) override;
154     void addStage(EShLanguage stage, TIntermediate& stageIntermediate) override {
155         if (stage < EShLangCount) {
156             stageMask[stage] = true;
157             stageIntermediates[stage] = &stageIntermediate;
158         }
159     }
160     uint32_t computeTypeLocationSize(const TType& type, EShLanguage stage);
161
162     TSlotSetMap slots;
163     bool hasError = false;
164
165 protected:
166     TDefaultIoResolverBase(TDefaultIoResolverBase&);
167     TDefaultIoResolverBase& operator=(TDefaultIoResolverBase&);
168     const TIntermediate& intermediate;
169     int nextUniformLocation;
170     int nextInputLocation;
171     int nextOutputLocation;
172     bool stageMask[EShLangCount + 1];
173     const TIntermediate* stageIntermediates[EShLangCount];
174
175     // Return descriptor set specific base if there is one, and the generic base otherwise.
176     int selectBaseBinding(int base, int descriptorSetBase) const {
177         return descriptorSetBase != -1 ? descriptorSetBase : base;
178     }
179
180     static int getLayoutSet(const glslang::TType& type) {
181         if (type.getQualifier().hasSet())
182             return type.getQualifier().layoutSet;
183         else
184             return 0;
185     }
186
187     static bool isSamplerType(const glslang::TType& type) {
188         return type.getBasicType() == glslang::EbtSampler && type.getSampler().isPureSampler();
189     }
190
191     static bool isTextureType(const glslang::TType& type) {
192         return (type.getBasicType() == glslang::EbtSampler &&
193                 (type.getSampler().isTexture() || type.getSampler().isSubpass()));
194     }
195
196     static bool isUboType(const glslang::TType& type) {
197         return type.getQualifier().storage == EvqUniform;
198     }
199
200     static bool isImageType(const glslang::TType& type) {
201         return type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage();
202     }
203
204     static bool isSsboType(const glslang::TType& type) {
205         return type.getQualifier().storage == EvqBuffer;
206     }
207
208     // Return true if this is a SRV (shader resource view) type:
209     static bool isSrvType(const glslang::TType& type) {
210         return isTextureType(type) || type.getQualifier().storage == EvqBuffer;
211     }
212
213     // Return true if this is a UAV (unordered access view) type:
214     static bool isUavType(const glslang::TType& type) {
215         if (type.getQualifier().isReadOnly())
216             return false;
217         return (type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage()) ||
218                 (type.getQualifier().storage == EvqBuffer);
219     }
220 };
221
222 // Default I/O resolver for OpenGL
223 struct TDefaultGlslIoResolver : public TDefaultIoResolverBase {
224 public:
225     typedef std::map<TString, int> TVarSlotMap;  // <resourceName, location/binding>
226     typedef std::map<int, TVarSlotMap> TSlotMap; // <resourceKey, TVarSlotMap>
227     TDefaultGlslIoResolver(const TIntermediate& intermediate);
228     bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; }
229     TResourceType getResourceType(const glslang::TType& type) override;
230     int resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) override;
231     int resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) override;
232     int resolveBinding(EShLanguage /*stage*/, TVarEntryInfo& ent) override;
233     void beginResolve(EShLanguage /*stage*/) override;
234     void endResolve(EShLanguage stage) override;
235     void beginCollect(EShLanguage) override;
236     void endCollect(EShLanguage) override;
237     void reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override;
238     void reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) override;
239     // in/out symbol and uniform symbol are stored in the same resourceSlotMap, the storage key is used to identify each type of symbol.
240     // We use stage and storage qualifier to construct a storage key. it can help us identify the same storage resource used in different stage.
241     // 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.
242     // Note: both stage and type must less then 0xffff.
243     int buildStorageKey(EShLanguage stage, TStorageQualifier type) {
244         assert(static_cast<uint32_t>(stage) <= 0x0000ffff && static_cast<uint32_t>(type) <= 0x0000ffff);
245         return (stage << 16) | type;
246     }
247
248 protected:
249     // Use for mark pre stage, to get more interface symbol information.
250     EShLanguage preStage;
251     // Use for mark current shader stage for resolver
252     EShLanguage currentStage;
253     // Slot map for storage resource(location of uniform and interface symbol) It's a program share slot
254     TSlotMap resourceSlotMap;
255     // Slot map for other resource(image, ubo, ssbo), It's a program share slot.
256     TSlotMap storageSlotMap;
257 };
258
259 typedef std::map<TString, TVarEntryInfo> TVarLiveMap;
260
261 // override function "operator=", if a vector<const _Kty, _Ty> being sort,
262 // when use vc++, the sort function will call :
263 // pair& operator=(const pair<_Other1, _Other2>& _Right)
264 // {
265 //     first = _Right.first;
266 //     second = _Right.second;
267 //     return (*this);
268 // }
269 // that will make a const type handing on left.
270 // override this function can avoid a compiler error.
271 // In the future, if the vc++ compiler can handle such a situation,
272 // this part of the code will be removed.
273 struct TVarLivePair : std::pair<const TString, TVarEntryInfo> {
274     TVarLivePair(const std::pair<const TString, TVarEntryInfo>& _Right) : pair(_Right.first, _Right.second) {}
275     TVarLivePair& operator=(const TVarLivePair& _Right) {
276         const_cast<TString&>(first) = _Right.first;
277         second = _Right.second;
278         return (*this);
279     }
280     TVarLivePair(const TVarLivePair& src) : pair(src) { }
281 };
282 typedef std::vector<TVarLivePair> TVarLiveVector;
283
284 // I/O mapper
285 class TIoMapper {
286 public:
287     TIoMapper() {}
288     virtual ~TIoMapper() {}
289     // grow the reflection stage by stage
290     bool virtual addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*);
291     bool virtual doMap(TIoMapResolver*, TInfoSink&) { return true; }
292 };
293
294 // I/O mapper for GLSL
295 class TGlslIoMapper : public TIoMapper {
296 public:
297     TGlslIoMapper() {
298         memset(inVarMaps,     0, sizeof(TVarLiveMap*)   * (EShLangCount + 1));
299         memset(outVarMaps,    0, sizeof(TVarLiveMap*)   * (EShLangCount + 1));
300         memset(uniformVarMap, 0, sizeof(TVarLiveMap*)   * (EShLangCount + 1));
301         memset(intermediates, 0, sizeof(TIntermediate*) * (EShLangCount + 1));
302         profile = ENoProfile;
303         version = 0;
304         autoPushConstantMaxSize = 128;
305         autoPushConstantBlockPacking = ElpStd430;
306     }
307     virtual ~TGlslIoMapper() {
308         for (size_t stage = 0; stage < EShLangCount; stage++) {
309             if (inVarMaps[stage] != nullptr) {
310                 delete inVarMaps[stage];
311                 inVarMaps[stage] = nullptr;
312             }
313             if (outVarMaps[stage] != nullptr) {
314                 delete outVarMaps[stage];
315                 outVarMaps[stage] = nullptr;
316             }
317             if (uniformVarMap[stage] != nullptr) {
318                 delete uniformVarMap[stage];
319                 uniformVarMap[stage] = nullptr;
320             }
321             if (intermediates[stage] != nullptr)
322                 intermediates[stage] = nullptr;
323         }
324     }
325         // If set, the uniform block with the given name will be changed to be backed by
326         // push_constant if it's size is <= maxSize
327     void setAutoPushConstantBlock(const char* name, unsigned int maxSize, TLayoutPacking packing) {
328         autoPushConstantBlockName = name;
329         autoPushConstantMaxSize = maxSize;
330         autoPushConstantBlockPacking = packing;
331     }
332     // grow the reflection stage by stage
333     bool addStage(EShLanguage, TIntermediate&, TInfoSink&, TIoMapResolver*) override;
334     bool doMap(TIoMapResolver*, TInfoSink&) override;
335     TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount],
336                 *uniformVarMap[EShLangCount];
337     TIntermediate* intermediates[EShLangCount];
338     bool hadError = false;
339     EProfile profile;
340     int version;
341
342 private:
343     TString autoPushConstantBlockName;
344     unsigned int autoPushConstantMaxSize;
345     TLayoutPacking autoPushConstantBlockPacking;
346 };
347
348 } // end namespace glslang
349
350 #endif // _IOMAPPER_INCLUDED
351
352 #endif // !GLSLANG_WEB && !GLSLANG_ANGLE