2 // Copyright (C) 2016 LunarG, Inc.
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
10 // Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
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.
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.
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.
36 #if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE)
38 #ifndef _IOMAPPER_INCLUDED
39 #define _IOMAPPER_INCLUDED
42 #include "LiveTraverser.h"
43 #include <unordered_map>
44 #include <unordered_set>
46 // A reflection database and its interface, consistent with the OpenGL API reflection queries.
54 struct TVarEntryInfo {
56 TIntermSymbol* symbol;
65 inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) { return l.id < r.id; }
68 struct TOrderByPriority {
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();
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);
85 if (lPoints == rPoints)
87 return lPoints > rPoints;
91 struct TOrderByPriorityAndLive {
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) {
100 const TQualifier& lq = l.symbol->getQualifier();
101 const TQualifier& rq = r.symbol->getQualifier();
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);
110 if (l.live != r.live)
111 return l.live > r.live;
113 if (lPoints != rPoints)
114 return lPoints > rPoints;
121 // Base class for shared TIoMapResolver services, used by several derivations.
122 struct TDefaultIoResolverBase : public glslang::TIoMapResolver {
124 TDefaultIoResolverBase(const TIntermediate& intermediate);
125 typedef std::vector<int> TSlotSet;
126 typedef std::unordered_map<int, TSlotSet> TSlotSetMap;
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;
160 uint32_t computeTypeLocationSize(const TType& type, EShLanguage stage);
163 bool hasError = false;
166 TDefaultIoResolverBase(TDefaultIoResolverBase&);
167 TDefaultIoResolverBase& operator=(TDefaultIoResolverBase&);
168 const TIntermediate& referenceIntermediate;
169 int nextUniformLocation;
170 int nextInputLocation;
171 int nextOutputLocation;
172 bool stageMask[EShLangCount + 1];
173 const TIntermediate* stageIntermediates[EShLangCount];
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;
180 static int getLayoutSet(const glslang::TType& type) {
181 if (type.getQualifier().hasSet())
182 return type.getQualifier().layoutSet;
187 static bool isSamplerType(const glslang::TType& type) {
188 return type.getBasicType() == glslang::EbtSampler && type.getSampler().isPureSampler();
191 static bool isTextureType(const glslang::TType& type) {
192 return (type.getBasicType() == glslang::EbtSampler &&
193 (type.getSampler().isTexture() || type.getSampler().isSubpass()));
196 static bool isUboType(const glslang::TType& type) {
197 return type.getQualifier().storage == EvqUniform;
200 static bool isImageType(const glslang::TType& type) {
201 return type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage();
204 static bool isSsboType(const glslang::TType& type) {
205 return type.getQualifier().storage == EvqBuffer;
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;
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())
217 return (type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage()) ||
218 (type.getQualifier().storage == EvqBuffer);
222 // Default I/O resolver for OpenGL
223 struct TDefaultGlslIoResolver : public TDefaultIoResolverBase {
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;
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;
259 typedef std::map<TString, TVarEntryInfo> TVarLiveMap;
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)
265 // first = _Right.first;
266 // second = _Right.second;
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;
280 TVarLivePair(const TVarLivePair& src) : pair(src) { }
282 typedef std::vector<TVarLivePair> TVarLiveVector;
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; }
294 // I/O mapper for GLSL
295 class TGlslIoMapper : public TIoMapper {
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;
304 autoPushConstantMaxSize = 128;
305 autoPushConstantBlockPacking = ElpStd430;
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;
313 if (outVarMaps[stage] != nullptr) {
314 delete outVarMaps[stage];
315 outVarMaps[stage] = nullptr;
317 if (uniformVarMap[stage] != nullptr) {
318 delete uniformVarMap[stage];
319 uniformVarMap[stage] = nullptr;
321 if (intermediates[stage] != nullptr)
322 intermediates[stage] = nullptr;
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;
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;
343 TString autoPushConstantBlockName;
344 unsigned int autoPushConstantMaxSize;
345 TLayoutPacking autoPushConstantBlockPacking;
348 } // end namespace glslang
350 #endif // _IOMAPPER_INCLUDED
352 #endif // !GLSLANG_WEB && !GLSLANG_ANGLE