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