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 void clearNewAssignments() {
74 inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) { return l.id < r.id; }
77 struct TOrderByPriority {
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();
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);
94 if (lPoints == rPoints)
96 return lPoints > rPoints;
100 struct TOrderByPriorityAndLive {
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) {
109 const TQualifier& lq = l.symbol->getQualifier();
110 const TQualifier& rq = r.symbol->getQualifier();
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);
119 if (l.live != r.live)
120 return l.live > r.live;
122 if (lPoints != rPoints)
123 return lPoints > rPoints;
130 // Base class for shared TIoMapResolver services, used by several derivations.
131 struct TDefaultIoResolverBase : public glslang::TIoMapResolver {
133 TDefaultIoResolverBase(const TIntermediate& intermediate);
134 typedef std::vector<int> TSlotSet;
135 typedef std::unordered_map<int, TSlotSet> TSlotSetMap;
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;
169 uint32_t computeTypeLocationSize(const TType& type, EShLanguage stage);
172 bool hasError = false;
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];
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;
189 static int getLayoutSet(const glslang::TType& type) {
190 if (type.getQualifier().hasSet())
191 return type.getQualifier().layoutSet;
196 static bool isSamplerType(const glslang::TType& type) {
197 return type.getBasicType() == glslang::EbtSampler && type.getSampler().isPureSampler();
200 static bool isTextureType(const glslang::TType& type) {
201 return (type.getBasicType() == glslang::EbtSampler &&
202 (type.getSampler().isTexture() || type.getSampler().isSubpass()));
205 static bool isUboType(const glslang::TType& type) {
206 return type.getQualifier().storage == EvqUniform;
209 static bool isImageType(const glslang::TType& type) {
210 return type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage();
213 static bool isSsboType(const glslang::TType& type) {
214 return type.getQualifier().storage == EvqBuffer;
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;
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())
226 return (type.getBasicType() == glslang::EbtSampler && type.getSampler().isImage()) ||
227 (type.getQualifier().storage == EvqBuffer);
231 // Default I/O resolver for OpenGL
232 struct TDefaultGlslIoResolver : public TDefaultIoResolverBase {
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;
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;
268 typedef std::map<TString, TVarEntryInfo> TVarLiveMap;
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)
274 // first = _Right.first;
275 // second = _Right.second;
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;
289 TVarLivePair(const TVarLivePair& src) : pair(src) { }
291 typedef std::vector<TVarLivePair> TVarLiveVector;
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; }
303 // I/O mapper for GLSL
304 class TGlslIoMapper : public TIoMapper {
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;
313 autoPushConstantMaxSize = 128;
314 autoPushConstantBlockPacking = ElpStd430;
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;
322 if (outVarMaps[stage] != nullptr) {
323 delete outVarMaps[stage];
324 outVarMaps[stage] = nullptr;
326 if (uniformVarMap[stage] != nullptr) {
327 delete uniformVarMap[stage];
328 uniformVarMap[stage] = nullptr;
330 if (intermediates[stage] != nullptr)
331 intermediates[stage] = nullptr;
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;
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;
352 TString autoPushConstantBlockName;
353 unsigned int autoPushConstantMaxSize;
354 TLayoutPacking autoPushConstantBlockPacking;
357 } // end namespace glslang
359 #endif // _IOMAPPER_INCLUDED
361 #endif // !GLSLANG_WEB && !GLSLANG_ANGLE