a3c53f505d3dc8eaf1e6cb0ec3823e044cce24c4
[platform/upstream/glslang.git] / glslang / MachineIndependent / iomapper.cpp
1 //
2 // Copyright (C) 2016-2017 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 #include "../Include/Common.h"
39 #include "../Include/InfoSink.h"
40 #include "../Include/Types.h"
41
42 #include "gl_types.h"
43 #include "iomapper.h"
44 #include "SymbolTable.h"
45
46 //
47 // Map IO bindings.
48 //
49 // High-level algorithm for one stage:
50 //
51 // 1. Traverse all code (live+dead) to find the explicitly provided bindings.
52 //
53 // 2. Traverse (just) the live code to determine which non-provided bindings
54 //    require auto-numbering.  We do not auto-number dead ones.
55 //
56 // 3. Traverse all the code to apply the bindings:
57 //    a. explicitly given bindings are offset according to their type
58 //    b. implicit live bindings are auto-numbered into the holes, using
59 //       any open binding slot.
60 //    c. implicit dead bindings are left un-bound.
61 //
62
63 namespace glslang {
64
65 class TVarGatherTraverser : public TLiveTraverser {
66 public:
67     TVarGatherTraverser(const TIntermediate& i, bool traverseDeadCode, TVarLiveMap& inList, TVarLiveMap& outList, TVarLiveMap& uniformList)
68       : TLiveTraverser(i, traverseDeadCode, true, true, false)
69       , inputList(inList)
70       , outputList(outList)
71       , uniformList(uniformList)
72     {
73     }
74
75     virtual void visitSymbol(TIntermSymbol* base)
76     {
77         TVarLiveMap* target = nullptr;
78         if (base->getQualifier().storage == EvqVaryingIn)
79             target = &inputList;
80         else if (base->getQualifier().storage == EvqVaryingOut)
81             target = &outputList;
82         else if (base->getQualifier().isUniformOrBuffer() && !base->getQualifier().isPushConstant() && !base->getQualifier().isShaderRecord())
83             target = &uniformList;
84         // If a global is being visited, then we should also traverse it incase it's evaluation
85         // ends up visiting inputs we want to tag as live
86         else if (base->getQualifier().storage == EvqGlobal)
87             addGlobalReference(base->getAccessName());
88
89         if (target) {
90             TVarEntryInfo ent = {base->getId(), base, ! traverseAll};
91             ent.stage = intermediate.getStage();
92             TVarLiveMap::iterator at = target->find(
93                 ent.symbol->getAccessName()); // std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById());
94             if (at != target->end() && at->second.id == ent.id)
95                 at->second.live = at->second.live || ! traverseAll; // update live state
96             else
97                 (*target)[ent.symbol->getAccessName()] = ent;
98         }
99     }
100
101 private:
102     TVarLiveMap&    inputList;
103     TVarLiveMap&    outputList;
104     TVarLiveMap&    uniformList;
105 };
106
107 class TVarSetTraverser : public TLiveTraverser
108 {
109 public:
110     TVarSetTraverser(const TIntermediate& i, const TVarLiveMap& inList, const TVarLiveMap& outList, const TVarLiveMap& uniformList)
111       : TLiveTraverser(i, true, true, true, false)
112       , inputList(inList)
113       , outputList(outList)
114       , uniformList(uniformList)
115     {
116     }
117
118     virtual void visitSymbol(TIntermSymbol* base) {
119         const TVarLiveMap* source;
120         if (base->getQualifier().storage == EvqVaryingIn)
121             source = &inputList;
122         else if (base->getQualifier().storage == EvqVaryingOut)
123             source = &outputList;
124         else if (base->getQualifier().isUniformOrBuffer())
125             source = &uniformList;
126         else
127             return;
128
129         TVarEntryInfo ent = { base->getId() };
130         // Fix a defect, when block has no instance name, we need to find its block name
131         TVarLiveMap::const_iterator at = source->find(base->getAccessName());
132         if (at == source->end())
133             return;
134
135         if (at->second.id != ent.id)
136             return;
137
138         if (at->second.newBinding != -1)
139             base->getWritableType().getQualifier().layoutBinding = at->second.newBinding;
140         if (at->second.newSet != -1)
141             base->getWritableType().getQualifier().layoutSet = at->second.newSet;
142         if (at->second.newLocation != -1)
143             base->getWritableType().getQualifier().layoutLocation = at->second.newLocation;
144         if (at->second.newComponent != -1)
145             base->getWritableType().getQualifier().layoutComponent = at->second.newComponent;
146         if (at->second.newIndex != -1)
147             base->getWritableType().getQualifier().layoutIndex = at->second.newIndex;
148     }
149
150   private:
151     const TVarLiveMap&    inputList;
152     const TVarLiveMap&    outputList;
153     const TVarLiveMap&    uniformList;
154 };
155
156 struct TNotifyUniformAdaptor
157 {
158     EShLanguage stage;
159     TIoMapResolver& resolver;
160     inline TNotifyUniformAdaptor(EShLanguage s, TIoMapResolver& r)
161       : stage(s)
162       , resolver(r)
163     {
164     }
165
166     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
167     {
168         resolver.notifyBinding(stage, entKey.second);
169     }
170
171 private:
172     TNotifyUniformAdaptor& operator=(TNotifyUniformAdaptor&) = delete;
173 };
174
175 struct TNotifyInOutAdaptor
176 {
177     EShLanguage stage;
178     TIoMapResolver& resolver;
179     inline TNotifyInOutAdaptor(EShLanguage s, TIoMapResolver& r) 
180       : stage(s)
181       , resolver(r)
182     {
183     }
184
185     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
186     {
187         resolver.notifyInOut(entKey.second.stage, entKey.second);
188     }
189
190 private:
191     TNotifyInOutAdaptor& operator=(TNotifyInOutAdaptor&) = delete;
192 };
193
194 struct TResolverUniformAdaptor {
195     TResolverUniformAdaptor(EShLanguage s, TIoMapResolver& r, TVarLiveMap* uniform[EShLangCount], TInfoSink& i, bool& e)
196       : stage(s)
197       , resolver(r)
198       , infoSink(i)
199       , error(e)
200     {
201         memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*)));
202     }
203
204     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
205         TVarEntryInfo& ent = entKey.second;
206         ent.newLocation = -1;
207         ent.newComponent = -1;
208         ent.newBinding = -1;
209         ent.newSet = -1;
210         ent.newIndex = -1;
211         const bool isValid = resolver.validateBinding(stage, ent);
212         if (isValid) {
213             resolver.resolveSet(ent.stage, ent);
214             resolver.resolveBinding(ent.stage, ent);
215             resolver.resolveUniformLocation(ent.stage, ent);
216
217             if (ent.newBinding != -1) {
218                 if (ent.newBinding >= int(TQualifier::layoutBindingEnd)) {
219                     TString err = "mapped binding out of range: " + entKey.first;
220
221                     infoSink.info.message(EPrefixInternalError, err.c_str());
222                     error = true;
223                 }
224
225                 if (ent.symbol->getQualifier().hasBinding()) {
226                     for (uint32_t idx = EShLangVertex; idx < EShLangCount; ++idx) {
227                         if (idx == ent.stage || uniformVarMap[idx] == nullptr)
228                             continue;
229                         auto entKey2 = uniformVarMap[idx]->find(entKey.first);
230                         if (entKey2 != uniformVarMap[idx]->end()) {
231                             entKey2->second.newBinding = ent.newBinding;
232                         }
233                     }
234                 }
235             }
236             if (ent.newSet != -1) {
237                 if (ent.newSet >= int(TQualifier::layoutSetEnd)) {
238                     TString err = "mapped set out of range: " + entKey.first;
239
240                     infoSink.info.message(EPrefixInternalError, err.c_str());
241                     error = true;
242                 }
243                 if (ent.symbol->getQualifier().hasSet()) {
244                     for (uint32_t idx = EShLangVertex; idx < EShLangCount; ++idx) {
245                         if ((idx == stage) || (uniformVarMap[idx] == nullptr))
246                             continue;
247                         auto entKey2 = uniformVarMap[idx]->find(entKey.first);
248                         if (entKey2 != uniformVarMap[idx]->end()) {
249                             entKey2->second.newSet = ent.newSet;
250                         }
251                     }
252                 }
253             }
254         } else {
255             TString errorMsg = "Invalid binding: " + entKey.first;
256             infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
257             error = true;
258         }
259     }
260
261     inline void setStage(EShLanguage s) { stage = s; }
262
263     EShLanguage     stage;
264     TIoMapResolver& resolver;
265     TInfoSink&      infoSink;
266     bool&           error;
267     TVarLiveMap*    uniformVarMap[EShLangCount];
268 private:
269     TResolverUniformAdaptor& operator=(TResolverUniformAdaptor&) = delete;
270 };
271
272 struct TResolverInOutAdaptor {
273     TResolverInOutAdaptor(EShLanguage s, TIoMapResolver& r, TInfoSink& i, bool& e)
274       : stage(s)
275       , resolver(r)
276       , infoSink(i)
277       , error(e)
278     {
279     }
280
281     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey)
282     {
283         TVarEntryInfo& ent = entKey.second;
284         ent.newLocation = -1;
285         ent.newComponent = -1;
286         ent.newBinding = -1;
287         ent.newSet = -1;
288         ent.newIndex = -1;
289         const bool isValid = resolver.validateInOut(ent.stage, ent);
290         if (isValid) {
291             resolver.resolveInOutLocation(stage, ent);
292             resolver.resolveInOutComponent(stage, ent);
293             resolver.resolveInOutIndex(stage, ent);
294         } else {
295             TString errorMsg;
296             if (ent.symbol->getType().getQualifier().semanticName != nullptr) {
297                 errorMsg = "Invalid shader In/Out variable semantic: ";
298                 errorMsg += ent.symbol->getType().getQualifier().semanticName;
299             } else {
300                 errorMsg = "Invalid shader In/Out variable: ";
301                 errorMsg += ent.symbol->getName();
302             }
303             infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
304             error = true;
305         }
306     }
307
308     inline void setStage(EShLanguage s) { stage = s; }
309
310     EShLanguage     stage;
311     TIoMapResolver& resolver;
312     TInfoSink&      infoSink;
313     bool&           error;
314
315 private:
316     TResolverInOutAdaptor& operator=(TResolverInOutAdaptor&) = delete;
317 };
318
319 // The class is used for reserving explicit uniform locations and ubo/ssbo/opaque bindings
320 // xxTODO: maybe this logic should be moved into the resolver's "validateInOut" and "validateUniform"
321
322 struct TSymbolValidater
323 {
324     TSymbolValidater(TIoMapResolver& r, TInfoSink& i, TVarLiveMap* in[EShLangCount], TVarLiveMap* out[EShLangCount],
325                      TVarLiveMap* uniform[EShLangCount], bool& hadError, EProfile profile, int version)
326         : resolver(r)
327         , infoSink(i)
328         , hadError(hadError)
329         , profile(profile)
330         , version(version)
331     {
332         memcpy(inVarMaps, in, EShLangCount * (sizeof(TVarLiveMap*)));
333         memcpy(outVarMaps, out, EShLangCount * (sizeof(TVarLiveMap*)));
334         memcpy(uniformVarMap, uniform, EShLangCount * (sizeof(TVarLiveMap*)));
335
336         std::map<TString, TString> anonymousMemberMap;
337         std::vector<TRange> usedUniformLocation;
338         std::vector<TString> usedUniformName;
339         usedUniformLocation.clear();
340         usedUniformName.clear();
341         for (int i = 0; i < EShLangCount; i++) {
342             if (uniformVarMap[i]) {
343                 for (auto uniformVar : *uniformVarMap[i])
344                 {
345                     TIntermSymbol* pSymbol = uniformVar.second.symbol;
346                     TQualifier qualifier = uniformVar.second.symbol->getQualifier();
347                     TString symbolName = pSymbol->getAccessName();
348
349                     // All the uniform needs multi-stage location check (block/default)
350                     int uniformLocation = qualifier.layoutLocation;
351
352                     if (uniformLocation != TQualifier::layoutLocationEnd) {
353                         // Total size of current uniform, could be block, struct or other types.
354                         int size = TIntermediate::computeTypeUniformLocationSize(pSymbol->getType());
355
356                         TRange locationRange(uniformLocation, uniformLocation + size - 1);
357
358                         // Combine location and component ranges
359                         int overlapLocation = -1;
360                         bool diffLocation = false;
361
362                         // Check for collisions, except for vertex inputs on desktop targeting OpenGL
363                         overlapLocation = checkLocationOverlap(locationRange, usedUniformLocation, symbolName, usedUniformName, diffLocation);
364
365                         // Overlap locations of uniforms, regardless of components (multi stages)
366                         if (overlapLocation == -1) {
367                             usedUniformLocation.push_back(locationRange);
368                             usedUniformName.push_back(symbolName);
369                         }
370                         else if (overlapLocation >= 0) {
371                             if (diffLocation == true) {
372                                 TString err = ("Uniform location should be equal for same uniforms: " +std::to_string(overlapLocation)).c_str();
373                                 infoSink.info.message(EPrefixInternalError, err.c_str());
374                                 hadError = true;
375                                 break;
376                             }
377                             else {
378                                 TString err = ("Uniform location overlaps across stages: " + std::to_string(overlapLocation)).c_str();
379                                 infoSink.info.message(EPrefixInternalError, err.c_str());
380                                 hadError = true;
381                                 break;
382                             }
383                         }
384                     }
385
386                     if ((uniformVar.second.symbol->getBasicType() == EbtBlock) &&
387                         IsAnonymous(uniformVar.second.symbol->getName()))
388                     {
389                         auto blockType = uniformVar.second.symbol->getType().getStruct();
390                         for (size_t memberIdx = 0; memberIdx < blockType->size(); ++memberIdx) {
391                             auto memberName = (*blockType)[memberIdx].type->getFieldName();
392                             if (anonymousMemberMap.find(memberName) != anonymousMemberMap.end())
393                             {
394                                 if (anonymousMemberMap[memberName] != uniformVar.second.symbol->getType().getTypeName())
395                                 {
396                                     TString err = "Invalid block member name: " + memberName;
397                                     infoSink.info.message(EPrefixInternalError, err.c_str());
398                                     hadError = true;
399                                     break;
400                                 }
401                             }
402                             else
403                             {
404                                 anonymousMemberMap[memberName] = uniformVar.second.symbol->getType().getTypeName();
405                             }
406                         }
407                     }
408                     if (hadError)
409                         break;
410                 }
411             }
412         }
413     }
414
415     // In case we need to new an intermediate, which costs too much
416     int checkLocationOverlap(const TRange& locationRange, std::vector<TRange>& usedUniformLocation, const TString symbolName, std::vector<TString>& usedUniformName, bool& diffLocation)
417     {
418         for (size_t r = 0; r < usedUniformLocation.size(); ++r) {
419             if (usedUniformName[r] == symbolName) {
420                 diffLocation = true;
421                 return (usedUniformLocation[r].start == locationRange.start &&
422                         usedUniformLocation[r].last == locationRange.last)
423                        ? -2 : std::max(locationRange.start, usedUniformLocation[r].start);
424             }
425             if (locationRange.overlap(usedUniformLocation[r])) {
426                 // there is a collision; pick one
427                 return std::max(locationRange.start, usedUniformLocation[r].start);
428             }
429         }
430
431         return -1; // no collision
432     }
433
434     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
435         TVarEntryInfo& ent1 = entKey.second;
436         TIntermSymbol* base = ent1.symbol;
437         const TType& type = ent1.symbol->getType();
438         const TString& name = entKey.first;
439         TString mangleName1, mangleName2;
440         EShLanguage stage = ent1.stage;
441         EShLanguage preStage, currentStage, nextStage;
442
443         preStage = EShLangCount;
444         for (int i = stage - 1; i >= 0; i--) {
445             if (inVarMaps[i] != nullptr) {
446                 preStage = static_cast<EShLanguage>(i);
447                 break;
448             }
449         }
450         currentStage = stage;
451         nextStage = EShLangCount;
452         for (int i = stage + 1; i < EShLangCount; i++) {
453             if (inVarMaps[i] != nullptr) {
454                 nextStage = static_cast<EShLanguage>(i);
455                 break;
456             }
457         }
458
459         if (type.getQualifier().isArrayedIo(stage)) {
460             TType subType(type, 0);
461             subType.appendMangledName(mangleName1);
462         } else {
463             type.appendMangledName(mangleName1);
464         }
465
466
467         // basic checking that symbols match
468         // more extensive checking in the link stage
469         if (base->getQualifier().storage == EvqVaryingIn) {
470             // validate stage in;
471             if (preStage == EShLangCount)
472                 return;
473             if (TSymbolTable::isBuiltInSymbol(base->getId()))
474                 return;
475             if (outVarMaps[preStage] != nullptr) {
476                 auto ent2 = outVarMaps[preStage]->find(name);
477                 uint32_t location = base->getType().getQualifier().layoutLocation;
478                 if (ent2 == outVarMaps[preStage]->end() &&
479                     location != glslang::TQualifier::layoutLocationEnd) {
480                     for (auto var = outVarMaps[preStage]->begin(); var != ent2; var++) {
481                         if (var->second.symbol->getType().getQualifier().layoutLocation == location) {
482                             ent2 = var;
483                             break;
484                         }
485                     }
486                 }
487                 if (ent2 != outVarMaps[preStage]->end()) {
488                     auto& type1 = base->getType();
489                     auto& type2 = ent2->second.symbol->getType();
490                     hadError = hadError || typeCheck(&type1, &type2, name.c_str(), false);
491                     if (ent2->second.symbol->getType().getQualifier().isArrayedIo(preStage)) {
492                         TType subType(ent2->second.symbol->getType(), 0);
493                         subType.appendMangledName(mangleName2);
494                     } else {
495                         ent2->second.symbol->getType().appendMangledName(mangleName2);
496                     }
497
498                     if (mangleName1 == mangleName2) {
499                         // For ES 3.0 only, other versions have no such restrictions
500                         // According to ES 3.0 spec: The type and presence of the interpolation qualifiers and
501                         // storage qualifiers  of variables with the same name declared in all linked shaders must
502                         // match, otherwise the link command will fail.
503                         if (profile == EEsProfile && version == 300) {
504                             // Don't need to check smooth qualifier, as it uses the default interpolation mode
505                             if (ent1.stage == EShLangFragment && type1.isBuiltIn() == false) {
506                                 if (type1.getQualifier().flat != type2.getQualifier().flat ||
507                                     type1.getQualifier().nopersp != type2.getQualifier().nopersp) {
508                                     TString err = "Interpolation qualifier mismatch : " + entKey.first;
509                                     infoSink.info.message(EPrefixInternalError, err.c_str());
510                                     hadError = true;
511                                 }
512                             }
513                         }
514                         return;
515                     }
516                     else {
517                         // Deal with input/output pairs where one is a block member but the other is loose,
518                         // e.g. with ARB_separate_shader_objects
519                         if (type1.getBasicType() == EbtBlock &&
520                             type1.isStruct() && !type2.isStruct()) {
521                             // Iterate through block members tracking layout
522                             glslang::TString name;
523                             type1.getStruct()->begin()->type->appendMangledName(name);
524                             if (name == mangleName2
525                                 && type1.getQualifier().layoutLocation == type2.getQualifier().layoutLocation) return;
526                         }
527                         if (type2.getBasicType() == EbtBlock &&
528                             type2.isStruct() && !type1.isStruct()) {
529                             // Iterate through block members tracking layout
530                             glslang::TString name;
531                             type2.getStruct()->begin()->type->appendMangledName(name);
532                             if (name == mangleName1
533                                 && type1.getQualifier().layoutLocation == type2.getQualifier().layoutLocation) return;
534                         }
535                         TString err = "Invalid In/Out variable type : " + entKey.first;
536                         infoSink.info.message(EPrefixInternalError, err.c_str());
537                         hadError = true;
538                     }
539                 }
540                 else if (!base->getType().isBuiltIn()) {
541                     // According to spec: A link error is generated if any statically referenced input variable
542                     // or block does not have a matching output
543                     if (profile == EEsProfile && ent1.live) {
544                         hadError = true;
545                         TString errorStr = name + ": not been declare as a output variable in pre shader stage.";
546                         infoSink.info.message(EPrefixError, errorStr.c_str());
547                     }
548                 }
549                 return;
550             }
551         } else if (base->getQualifier().storage == EvqVaryingOut) {
552             // validate stage out;
553             if (nextStage == EShLangCount)
554                 return;
555             if (TSymbolTable::isBuiltInSymbol(base->getId()))
556                 return;
557             if (inVarMaps[nextStage] != nullptr) {
558                 auto ent2 = inVarMaps[nextStage]->find(name);
559                 if (ent2 != inVarMaps[nextStage]->end()) {
560                     if (ent2->second.symbol->getType().getQualifier().isArrayedIo(nextStage)) {
561                         TType subType(ent2->second.symbol->getType(), 0);
562                         subType.appendMangledName(mangleName2);
563                     } else {
564                         ent2->second.symbol->getType().appendMangledName(mangleName2);
565                     }
566                     if (mangleName1 == mangleName2)
567                         return;
568                     else {
569                         TString err = "Invalid In/Out variable type : " + entKey.first;
570                         infoSink.info.message(EPrefixInternalError, err.c_str());
571                         hadError = true;
572                     }
573                 }
574                 return;
575             }
576         } else if (base->getQualifier().isUniformOrBuffer() && !base->getQualifier().isPushConstant()) {
577             // validate uniform type;
578             for (int i = 0; i < EShLangCount; i++) {
579                 if (i != currentStage && outVarMaps[i] != nullptr) {
580                     auto ent2 = uniformVarMap[i]->find(name);
581                     if (ent2 != uniformVarMap[i]->end()) {
582                         ent2->second.symbol->getType().appendMangledName(mangleName2);
583                         if (mangleName1 != mangleName2) {
584                             ent2->second.symbol->getType().sameElementType(type);
585                             TString err = "Invalid Uniform variable type : " + entKey.first;
586                             infoSink.info.message(EPrefixInternalError, err.c_str());
587                             hadError = true;
588                         }
589                         mangleName2.clear();
590
591                         // validate instance name of blocks
592                         if (hadError == false &&
593                             base->getType().getBasicType() == EbtBlock &&
594                             IsAnonymous(base->getName()) != IsAnonymous(ent2->second.symbol->getName())) {
595                             TString err = "Matched uniform block names must also either all be lacking "
596                                           "an instance name or all having an instance name: " + entKey.first;
597                             infoSink.info.message(EPrefixInternalError, err.c_str());
598                             hadError = true;
599                         }
600
601                         // validate uniform block member qualifier and member names
602                         auto& type1 = base->getType();
603                         auto& type2 = ent2->second.symbol->getType();
604                         if (hadError == false && base->getType().getBasicType() == EbtBlock) {
605                             hadError = hadError || typeCheck(&type1, &type2, name.c_str(), true);
606                         }
607                         else {
608                             hadError = hadError || typeCheck(&type1, &type2, name.c_str(), false);
609                         }
610                     }
611                     else if (base->getBasicType() == EbtBlock)
612                     {
613                         if (IsAnonymous(base->getName()))
614                         {
615                             // The name of anonymous block member can't same with default uniform variable.
616                             auto blockType1 = base->getType().getStruct();
617                             for (size_t memberIdx = 0; memberIdx < blockType1->size(); ++memberIdx) {
618                                 auto memberName = (*blockType1)[memberIdx].type->getFieldName();
619                                 if (uniformVarMap[i]->find(memberName) != uniformVarMap[i]->end())
620                                 {
621                                     TString err = "Invalid Uniform variable name : " + memberName;
622                                     infoSink.info.message(EPrefixInternalError, err.c_str());
623                                     hadError = true;
624                                     break;
625                                 }
626                             }
627                         }
628                     }
629                 }
630             }
631         }
632     }
633
634     TVarLiveMap *inVarMaps[EShLangCount], *outVarMaps[EShLangCount], *uniformVarMap[EShLangCount];
635
636     // Use for mark current shader stage for resolver
637     TIoMapResolver& resolver;
638     TInfoSink& infoSink;
639     bool& hadError;
640     EProfile profile;
641     int version;
642
643 private:
644     TSymbolValidater& operator=(TSymbolValidater&) = delete;
645
646     bool qualifierCheck(const TType* const type1, const TType* const type2, const std::string& name, bool isBlock)
647     {
648         bool hasError = false;
649         const TQualifier& qualifier1 = type1->getQualifier();
650         const TQualifier& qualifier2 = type2->getQualifier();
651
652         if (((isBlock == false) &&
653             (type1->getQualifier().storage == EvqUniform && type2->getQualifier().storage == EvqUniform)) ||
654             (type1->getQualifier().storage == EvqGlobal && type2->getQualifier().storage == EvqGlobal)) {
655             if (qualifier1.precision != qualifier2.precision) {
656                 hasError = true;
657                 std::string errorStr = name + ": have precision conflict cross stage.";
658                 infoSink.info.message(EPrefixError, errorStr.c_str());
659             }
660             if (qualifier1.hasFormat() && qualifier2.hasFormat()) {
661                 if (qualifier1.layoutFormat != qualifier2.layoutFormat) {
662                     hasError = true;
663                     std::string errorStr = name + ": have layout format conflict cross stage.";
664                     infoSink.info.message(EPrefixError, errorStr.c_str());
665                 }
666
667             }
668         }
669
670         if (isBlock == true) {
671             if (qualifier1.layoutPacking != qualifier2.layoutPacking) {
672                 hasError = true;
673                 std::string errorStr = name + ": have layoutPacking conflict cross stage.";
674                 infoSink.info.message(EPrefixError, errorStr.c_str());
675             }
676             if (qualifier1.layoutMatrix != qualifier2.layoutMatrix) {
677                 hasError = true;
678                 std::string errorStr = name + ": have layoutMatrix conflict cross stage.";
679                 infoSink.info.message(EPrefixError, errorStr.c_str());
680             }
681             if (qualifier1.layoutOffset != qualifier2.layoutOffset) {
682                 hasError = true;
683                 std::string errorStr = name + ": have layoutOffset conflict cross stage.";
684                 infoSink.info.message(EPrefixError, errorStr.c_str());
685             }
686             if (qualifier1.layoutAlign != qualifier2.layoutAlign) {
687                 hasError = true;
688                 std::string errorStr = name + ": have layoutAlign conflict cross stage.";
689                 infoSink.info.message(EPrefixError, errorStr.c_str());
690             }
691         }
692
693         return hasError;
694     }
695
696     bool typeCheck(const TType* const type1, const TType* const type2, const std::string& name, bool isBlock)
697     {
698         bool hasError = false;
699         if (!(type1->isStruct() && type2->isStruct())) {
700             hasError = hasError || qualifierCheck(type1, type2, name, isBlock);
701         }
702         else {
703             if (type1->getBasicType() == EbtBlock && type2->getBasicType() == EbtBlock)
704                 isBlock = true;
705             const TTypeList* typeList1 = type1->getStruct();
706             const TTypeList* typeList2 = type2->getStruct();
707
708             std::string newName = name;
709             size_t memberCount = typeList1->size();
710             size_t index2 = 0;
711             for (size_t index = 0; index < memberCount; index++, index2++) {
712                 // Skip inactive member
713                 if (typeList1->at(index).type->getBasicType() == EbtVoid)
714                     continue;
715                 while (index2 < typeList2->size() && typeList2->at(index2).type->getBasicType() == EbtVoid) {
716                     ++index2;
717                 }
718
719                 // TypeList1 has more members in list
720                 if (index2 == typeList2->size()) {
721                     std::string errorStr = name + ": struct mismatch.";
722                     infoSink.info.message(EPrefixError, errorStr.c_str());
723                     hasError = true;
724                     break;
725                 }
726
727                 if (typeList1->at(index).type->getFieldName() != typeList2->at(index2).type->getFieldName()) {
728                     std::string errorStr = name + ": member name mismatch.";
729                     infoSink.info.message(EPrefixError, errorStr.c_str());
730                     hasError = true;
731                 }
732                 else {
733                     newName = typeList1->at(index).type->getFieldName().c_str();
734                 }
735                 hasError = hasError || typeCheck(typeList1->at(index).type, typeList2->at(index2).type, newName, isBlock);
736             }
737
738             while (index2 < typeList2->size())
739             {
740                 // TypeList2 has more members
741                 if (typeList2->at(index2).type->getBasicType() != EbtVoid) {
742                     std::string errorStr = name + ": struct mismatch.";
743                     infoSink.info.message(EPrefixError, errorStr.c_str());
744                     hasError = true;
745                     break;
746                 }
747                 ++index2;
748             }
749         }
750         return hasError;
751     }
752 };
753
754 struct TSlotCollector {
755     TSlotCollector(TIoMapResolver& r, TInfoSink& i) : resolver(r), infoSink(i) { }
756
757     inline void operator()(std::pair<const TString, TVarEntryInfo>& entKey) {
758         resolver.reserverStorageSlot(entKey.second, infoSink);
759         resolver.reserverResourceSlot(entKey.second, infoSink);
760     }
761     TIoMapResolver& resolver;
762     TInfoSink& infoSink;
763
764 private:
765     TSlotCollector& operator=(TSlotCollector&) = delete;
766 };
767
768 TDefaultIoResolverBase::TDefaultIoResolverBase(const TIntermediate& intermediate)
769     : referenceIntermediate(intermediate)
770     , nextUniformLocation(intermediate.getUniformLocationBase())
771     , nextInputLocation(0)
772     , nextOutputLocation(0)
773 {
774     memset(stageMask, false, sizeof(bool) * (EShLangCount + 1));
775     memset(stageIntermediates, 0, sizeof(TIntermediate*) * (EShLangCount));
776     stageIntermediates[intermediate.getStage()] = &intermediate;
777 }
778
779 int TDefaultIoResolverBase::getBaseBinding(EShLanguage stage, TResourceType res, unsigned int set) const {
780     return stageIntermediates[stage] ? selectBaseBinding(stageIntermediates[stage]->getShiftBinding(res), stageIntermediates[stage]->getShiftBindingForSet(res, set))
781                                      : selectBaseBinding(referenceIntermediate.getShiftBinding(res), referenceIntermediate.getShiftBindingForSet(res, set));
782 }
783
784 const std::vector<std::string>& TDefaultIoResolverBase::getResourceSetBinding(EShLanguage stage) const {
785     return stageIntermediates[stage] ? stageIntermediates[stage]->getResourceSetBinding()
786                                      : referenceIntermediate.getResourceSetBinding();
787 }
788
789 bool TDefaultIoResolverBase::doAutoBindingMapping() const { return referenceIntermediate.getAutoMapBindings(); }
790
791 bool TDefaultIoResolverBase::doAutoLocationMapping() const { return referenceIntermediate.getAutoMapLocations(); }
792
793 TDefaultIoResolverBase::TSlotSet::iterator TDefaultIoResolverBase::findSlot(int set, int slot) {
794     return std::lower_bound(slots[set].begin(), slots[set].end(), slot);
795 }
796
797 bool TDefaultIoResolverBase::checkEmpty(int set, int slot) {
798     TSlotSet::iterator at = findSlot(set, slot);
799     return ! (at != slots[set].end() && *at == slot);
800 }
801
802 int TDefaultIoResolverBase::reserveSlot(int set, int slot, int size) {
803     TSlotSet::iterator at = findSlot(set, slot);
804     // tolerate aliasing, by not double-recording aliases
805     // (policy about appropriateness of the alias is higher up)
806     for (int i = 0; i < size; i++) {
807         if (at == slots[set].end() || *at != slot + i)
808             at = slots[set].insert(at, slot + i);
809         ++at;
810     }
811     return slot;
812 }
813
814 int TDefaultIoResolverBase::getFreeSlot(int set, int base, int size) {
815     TSlotSet::iterator at = findSlot(set, base);
816     if (at == slots[set].end())
817         return reserveSlot(set, base, size);
818     // look for a big enough gap
819     for (; at != slots[set].end(); ++at) {
820         if (*at - base >= size)
821             break;
822         base = *at + 1;
823     }
824     return reserveSlot(set, base, size);
825 }
826
827 int TDefaultIoResolverBase::resolveSet(EShLanguage stage, TVarEntryInfo& ent) {
828     const TType& type = ent.symbol->getType();
829     if (type.getQualifier().hasSet()) {
830         return ent.newSet = type.getQualifier().layoutSet;
831     }
832     // If a command line or API option requested a single descriptor set, use that (if not overrided by spaceN)
833     if (getResourceSetBinding(stage).size() == 1) {
834         return ent.newSet = atoi(getResourceSetBinding(stage)[0].c_str());
835     }
836     return ent.newSet = 0;
837 }
838
839 int TDefaultIoResolverBase::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
840     const TType& type = ent.symbol->getType();
841     const char* name =  ent.symbol->getAccessName().c_str();
842     // kick out of not doing this
843     if (! doAutoLocationMapping()) {
844         return ent.newLocation = -1;
845     }
846     // no locations added if already present, a built-in variable, a block, or an opaque
847     if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getBasicType() == EbtBlock ||
848         type.isAtomic() || type.isSpirvType() || (type.containsOpaque() && referenceIntermediate.getSpv().openGl == 0)) {
849         return ent.newLocation = -1;
850     }
851     // no locations on blocks of built-in variables
852     if (type.isStruct()) {
853         if (type.getStruct()->size() < 1) {
854             return ent.newLocation = -1;
855         }
856         if ((*type.getStruct())[0].type->isBuiltIn()) {
857             return ent.newLocation = -1;
858         }
859     }
860     int location = referenceIntermediate.getUniformLocationOverride(name);
861     if (location != -1) {
862         return ent.newLocation = location;
863     }
864     location = nextUniformLocation;
865     nextUniformLocation += TIntermediate::computeTypeUniformLocationSize(type);
866     return ent.newLocation = location;
867 }
868
869 int TDefaultIoResolverBase::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) {
870     const TType& type = ent.symbol->getType();
871     // kick out of not doing this
872     if (! doAutoLocationMapping()) {
873         return ent.newLocation = -1;
874     }
875
876     // no locations added if already present, a built-in variable, or a variable with SPIR-V decorate
877     if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getQualifier().hasSprivDecorate()) {
878         return ent.newLocation = -1;
879     }
880
881     // no locations on blocks of built-in variables
882     if (type.isStruct()) {
883         if (type.getStruct()->size() < 1) {
884             return ent.newLocation = -1;
885         }
886         if ((*type.getStruct())[0].type->isBuiltIn()) {
887             return ent.newLocation = -1;
888         }
889     }
890     // point to the right input or output location counter
891     int& nextLocation = type.getQualifier().isPipeInput() ? nextInputLocation : nextOutputLocation;
892     // Placeholder. This does not do proper cross-stage lining up, nor
893     // work with mixed location/no-location declarations.
894     int location = nextLocation;
895     int typeLocationSize;
896     // Don’t take into account the outer-most array if the stage’s
897     // interface is automatically an array.
898     typeLocationSize = computeTypeLocationSize(type, stage);
899     nextLocation += typeLocationSize;
900     return ent.newLocation = location;
901 }
902
903 int TDefaultIoResolverBase::resolveInOutComponent(EShLanguage /*stage*/, TVarEntryInfo& ent) {
904     return ent.newComponent = -1;
905 }
906
907 int TDefaultIoResolverBase::resolveInOutIndex(EShLanguage /*stage*/, TVarEntryInfo& ent) { return ent.newIndex = -1; }
908
909 uint32_t TDefaultIoResolverBase::computeTypeLocationSize(const TType& type, EShLanguage stage) {
910     int typeLocationSize;
911     // Don’t take into account the outer-most array if the stage’s
912     // interface is automatically an array.
913     if (type.getQualifier().isArrayedIo(stage)) {
914         TType elementType(type, 0);
915         typeLocationSize = TIntermediate::computeTypeLocationSize(elementType, stage);
916     } else {
917         typeLocationSize = TIntermediate::computeTypeLocationSize(type, stage);
918     }
919     return typeLocationSize;
920 }
921
922 //TDefaultGlslIoResolver
923 TResourceType TDefaultGlslIoResolver::getResourceType(const glslang::TType& type) {
924     if (isImageType(type)) {
925         return EResImage;
926     }
927     if (isTextureType(type)) {
928         return EResTexture;
929     }
930     if (isSsboType(type)) {
931         return EResSsbo;
932     }
933     if (isSamplerType(type)) {
934         return EResSampler;
935     }
936     if (isUboType(type)) {
937         return EResUbo;
938     }
939     return EResCount;
940 }
941
942 TDefaultGlslIoResolver::TDefaultGlslIoResolver(const TIntermediate& intermediate)
943     : TDefaultIoResolverBase(intermediate)
944     , preStage(EShLangCount)
945     , currentStage(EShLangCount)
946 { }
947
948 int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInfo& ent) {
949     const TType& type = ent.symbol->getType();
950     const TString& name = ent.symbol->getAccessName();
951     if (currentStage != stage) {
952         preStage = currentStage;
953         currentStage = stage;
954     }
955     // kick out if not doing this
956     if (! doAutoLocationMapping()) {
957         return ent.newLocation = -1;
958     }
959     // expand the location to each element if the symbol is a struct or array
960     if (type.getQualifier().hasLocation()) {
961         return ent.newLocation = type.getQualifier().layoutLocation;
962     }
963     // no locations added if already present, a built-in variable, or a variable with SPIR-V decorate
964     if (type.isBuiltIn() || type.getQualifier().hasSprivDecorate()) {
965         return ent.newLocation = -1;
966     }
967     // no locations on blocks of built-in variables
968     if (type.isStruct()) {
969         if (type.getStruct()->size() < 1) {
970             return ent.newLocation = -1;
971         }
972         if ((*type.getStruct())[0].type->isBuiltIn()) {
973             return ent.newLocation = -1;
974         }
975     }
976     int typeLocationSize = computeTypeLocationSize(type, stage);
977     int location = type.getQualifier().layoutLocation;
978     bool hasLocation = false;
979     EShLanguage keyStage(EShLangCount);
980     TStorageQualifier storage;
981     storage = EvqInOut;
982     if (type.getQualifier().isPipeInput()) {
983         // If this symbol is a input, search pre stage's out
984         keyStage = preStage;
985     }
986     if (type.getQualifier().isPipeOutput()) {
987         // If this symbol is a output, search next stage's in
988         keyStage = currentStage;
989     }
990     // The in/out in current stage is not declared with location, but it is possible declared
991     // with explicit location in other stages, find the storageSlotMap firstly to check whether
992     // the in/out has location
993     int resourceKey = buildStorageKey(keyStage, storage);
994     if (! storageSlotMap[resourceKey].empty()) {
995         TVarSlotMap::iterator iter = storageSlotMap[resourceKey].find(name);
996         if (iter != storageSlotMap[resourceKey].end()) {
997             // If interface resource be found, set it has location and this symbol's new location
998             // equal the symbol's explicit location declaration in pre or next stage.
999             //
1000             // vs:    out vec4 a;
1001             // fs:    layout(..., location = 3,...) in vec4 a;
1002             hasLocation = true;
1003             location = iter->second;
1004             // if we want deal like that:
1005             // vs:    layout(location=4) out vec4 a;
1006             //        out vec4 b;
1007             //
1008             // fs:    in vec4 a;
1009             //        layout(location = 4) in vec4 b;
1010             // we need retraverse the map.
1011         }
1012         if (! hasLocation) {
1013             // If interface resource note found, It's mean the location in two stage are both implicit declarat.
1014             // So we should find a new slot for this interface.
1015             //
1016             // vs: out vec4 a;
1017             // fs: in vec4 a;
1018             location = getFreeSlot(resourceKey, 0, typeLocationSize);
1019             storageSlotMap[resourceKey][name] = location;
1020         }
1021     } else {
1022         // the first interface declarated in a program.
1023         TVarSlotMap varSlotMap;
1024         location = getFreeSlot(resourceKey, 0, typeLocationSize);
1025         varSlotMap[name] = location;
1026         storageSlotMap[resourceKey] = varSlotMap;
1027     }
1028     //Update location
1029     return ent.newLocation = location;
1030 }
1031
1032 int TDefaultGlslIoResolver::resolveUniformLocation(EShLanguage /*stage*/, TVarEntryInfo& ent) {
1033     const TType& type = ent.symbol->getType();
1034     const TString& name = ent.symbol->getAccessName();
1035     // kick out of not doing this
1036     if (! doAutoLocationMapping()) {
1037         return ent.newLocation = -1;
1038     }
1039     // expand the location to each element if the symbol is a struct or array
1040     if (type.getQualifier().hasLocation() && (type.isStruct() || type.isArray())) {
1041         return ent.newLocation = type.getQualifier().layoutLocation;
1042     } else {
1043         // no locations added if already present, a built-in variable, a block, or an opaque
1044         if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getBasicType() == EbtBlock ||
1045             type.isAtomic() || type.isSpirvType() ||
1046             (type.containsOpaque() && referenceIntermediate.getSpv().openGl == 0)) {
1047             return ent.newLocation = -1;
1048         }
1049         // no locations on blocks of built-in variables
1050         if (type.isStruct()) {
1051             if (type.getStruct()->size() < 1) {
1052                 return ent.newLocation = -1;
1053             }
1054             if ((*type.getStruct())[0].type->isBuiltIn()) {
1055                 return ent.newLocation = -1;
1056             }
1057         }
1058     }
1059     int location = referenceIntermediate.getUniformLocationOverride(name.c_str());
1060     if (location != -1) {
1061         return ent.newLocation = location;
1062     }
1063
1064     int size = TIntermediate::computeTypeUniformLocationSize(type);
1065
1066     // The uniform in current stage is not declared with location, but it is possible declared
1067     // with explicit location in other stages, find the storageSlotMap firstly to check whether
1068     // the uniform has location
1069     bool hasLocation = false;
1070     int resourceKey = buildStorageKey(EShLangCount, EvqUniform);
1071     TVarSlotMap& slotMap = storageSlotMap[resourceKey];
1072     // Check dose shader program has uniform resource
1073     if (! slotMap.empty()) {
1074         // If uniform resource not empty, try find a same name uniform
1075         TVarSlotMap::iterator iter = slotMap.find(name);
1076         if (iter != slotMap.end()) {
1077             // If uniform resource be found, set it has location and this symbol's new location
1078             // equal the uniform's explicit location declaration in other stage.
1079             //
1080             // vs:    uniform vec4 a;
1081             // fs:    layout(..., location = 3,...) uniform vec4 a;
1082             hasLocation = true;
1083             location = iter->second;
1084         }
1085         if (! hasLocation) {
1086             // No explicit location declaration in other stage.
1087             // So we should find a new slot for this uniform.
1088             //
1089             // vs:    uniform vec4 a;
1090             // fs:    uniform vec4 a;
1091             location = getFreeSlot(resourceKey, 0, computeTypeLocationSize(type, currentStage));
1092             storageSlotMap[resourceKey][name] = location;
1093         }
1094     } else {
1095         // the first uniform declaration in a program.
1096         TVarSlotMap varSlotMap;
1097         location = getFreeSlot(resourceKey, 0, size);
1098         varSlotMap[name] = location;
1099         storageSlotMap[resourceKey] = varSlotMap;
1100     }
1101     return ent.newLocation = location;
1102 }
1103
1104 int TDefaultGlslIoResolver::resolveBinding(EShLanguage stage, TVarEntryInfo& ent) {
1105     const TType& type = ent.symbol->getType();
1106     const TString& name = ent.symbol->getAccessName();
1107     // On OpenGL arrays of opaque types take a separate binding for each element
1108     int numBindings = referenceIntermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1;
1109     TResourceType resource = getResourceType(type);
1110     // don't need to handle uniform symbol, it will be handled in resolveUniformLocation
1111     if (resource == EResUbo && type.getBasicType() != EbtBlock) {
1112         return ent.newBinding = -1;
1113     }
1114     // There is no 'set' qualifier in OpenGL shading language, each resource has its own
1115     // binding name space, so remap the 'set' to resource type which make each resource
1116     // binding is valid from 0 to MAX_XXRESOURCE_BINDINGS
1117     int set = referenceIntermediate.getSpv().openGl != 0 ? resource : ent.newSet;
1118     int resourceKey = set;
1119     if (resource < EResCount) {
1120         if (type.getQualifier().hasBinding()) {
1121             int newBinding = reserveSlot(resourceKey, getBaseBinding(stage, resource, set) + type.getQualifier().layoutBinding, numBindings);
1122             return ent.newBinding = newBinding;
1123
1124         } else {
1125             // The resource in current stage is not declared with binding, but it is possible declared
1126             // with explicit binding in other stages, find the resourceSlotMap firstly to check whether
1127             // the resource has binding, don't need to allocate if it already has a binding
1128             bool hasBinding = false;
1129             ent.newBinding = -1; // leave as -1 if it isn't set below
1130
1131             if (! resourceSlotMap[resourceKey].empty()) {
1132                 TVarSlotMap::iterator iter = resourceSlotMap[resourceKey].find(name);
1133                 if (iter != resourceSlotMap[resourceKey].end()) {
1134                     hasBinding = true;
1135                     ent.newBinding = iter->second;
1136                 }
1137             }
1138             if (!hasBinding && (ent.live && doAutoBindingMapping())) {
1139                 // find free slot, the caller did make sure it passes all vars with binding
1140                 // first and now all are passed that do not have a binding and needs one
1141                 int binding = getFreeSlot(resourceKey, getBaseBinding(stage, resource, set), numBindings);
1142                 resourceSlotMap[resourceKey][name] = binding;
1143                 ent.newBinding = binding;
1144             }
1145             return ent.newBinding;
1146         }
1147     }
1148     return ent.newBinding = -1;
1149 }
1150
1151 void TDefaultGlslIoResolver::beginResolve(EShLanguage stage) {
1152     // reset stage state
1153     if (stage == EShLangCount)
1154         preStage = currentStage = stage;
1155     // update stage state
1156     else if (currentStage != stage) {
1157         preStage = currentStage;
1158         currentStage = stage;
1159     }
1160 }
1161
1162 void TDefaultGlslIoResolver::endResolve(EShLanguage /*stage*/) {
1163     // TODO nothing
1164 }
1165
1166 void TDefaultGlslIoResolver::beginCollect(EShLanguage stage) {
1167     // reset stage state
1168     if (stage == EShLangCount)
1169         preStage = currentStage = stage;
1170     // update stage state
1171     else if (currentStage != stage) {
1172         preStage = currentStage;
1173         currentStage = stage;
1174     }
1175 }
1176
1177 void TDefaultGlslIoResolver::endCollect(EShLanguage /*stage*/) {
1178     // TODO nothing
1179 }
1180
1181 void TDefaultGlslIoResolver::reserverStorageSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
1182     const TType& type = ent.symbol->getType();
1183     const TString& name = ent.symbol->getAccessName();
1184     TStorageQualifier storage = type.getQualifier().storage;
1185     EShLanguage stage(EShLangCount);
1186     switch (storage) {
1187     case EvqUniform:
1188         if (type.getBasicType() != EbtBlock && type.getQualifier().hasLocation()) {
1189             //
1190             // Reserve the slots for the uniforms who has explicit location
1191             int storageKey = buildStorageKey(EShLangCount, EvqUniform);
1192             int location = type.getQualifier().layoutLocation;
1193             TVarSlotMap& varSlotMap = storageSlotMap[storageKey];
1194             TVarSlotMap::iterator iter = varSlotMap.find(name);
1195             if (iter == varSlotMap.end()) {
1196                 int numLocations = TIntermediate::computeTypeUniformLocationSize(type);
1197                 reserveSlot(storageKey, location, numLocations);
1198                 varSlotMap[name] = location;
1199             } else {
1200                 // Allocate location by name for OpenGL driver, so the uniform in different
1201                 // stages should be declared with the same location
1202                 if (iter->second != location) {
1203                     TString errorMsg = "Invalid location: " + name;
1204                     infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
1205                     hasError = true;
1206                 }
1207             }
1208         }
1209         break;
1210     case EvqVaryingIn:
1211     case EvqVaryingOut:
1212         //
1213         // Reserve the slots for the inout who has explicit location
1214         if (type.getQualifier().hasLocation()) {
1215             stage = storage == EvqVaryingIn ? preStage : stage;
1216             stage = storage == EvqVaryingOut ? currentStage : stage;
1217             int storageKey = buildStorageKey(stage, EvqInOut);
1218             int location = type.getQualifier().layoutLocation;
1219             TVarSlotMap& varSlotMap = storageSlotMap[storageKey];
1220             TVarSlotMap::iterator iter = varSlotMap.find(name);
1221             if (iter == varSlotMap.end()) {
1222                 int numLocations = TIntermediate::computeTypeUniformLocationSize(type);
1223                 reserveSlot(storageKey, location, numLocations);
1224                 varSlotMap[name] = location;
1225             } else {
1226                 // Allocate location by name for OpenGL driver, so the uniform in different
1227                 // stages should be declared with the same location
1228                 if (iter->second != location) {
1229                     TString errorMsg = "Invalid location: " + name;
1230                     infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
1231                     hasError = true;
1232                 }
1233             }
1234         }
1235         break;
1236     default:
1237         break;
1238     }
1239 }
1240
1241 void TDefaultGlslIoResolver::reserverResourceSlot(TVarEntryInfo& ent, TInfoSink& infoSink) {
1242     const TType& type = ent.symbol->getType();
1243     const TString& name = ent.symbol->getAccessName();
1244     TResourceType resource = getResourceType(type);
1245     int set = referenceIntermediate.getSpv().openGl != 0 ? resource : resolveSet(ent.stage, ent);
1246     int resourceKey = set;
1247
1248     if (type.getQualifier().hasBinding()) {
1249         TVarSlotMap& varSlotMap = resourceSlotMap[resourceKey];
1250         TVarSlotMap::iterator iter = varSlotMap.find(name);
1251         int binding = type.getQualifier().layoutBinding + getBaseBinding(ent.stage, resource, set);
1252
1253         if (iter == varSlotMap.end()) {
1254             // Reserve the slots for the ubo, ssbo and opaques who has explicit binding
1255             int numBindings = referenceIntermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1;
1256             varSlotMap[name] = binding;
1257             reserveSlot(resourceKey, binding, numBindings);
1258         } else {
1259             // Allocate binding by name for OpenGL driver, so the resource in different
1260             // stages should be declared with the same binding
1261             if (iter->second != binding) {
1262                 TString errorMsg = "Invalid binding: " + name;
1263                 infoSink.info.message(EPrefixInternalError, errorMsg.c_str());
1264                 hasError = true;
1265             }
1266         }
1267     }
1268 }
1269
1270 //TDefaultGlslIoResolver end
1271
1272 /*
1273  * Basic implementation of glslang::TIoMapResolver that replaces the
1274  * previous offset behavior.
1275  * It does the same, uses the offsets for the corresponding uniform
1276  * types. Also respects the EOptionAutoMapBindings flag and binds
1277  * them if needed.
1278  */
1279 /*
1280  * Default resolver
1281  */
1282 struct TDefaultIoResolver : public TDefaultIoResolverBase {
1283     TDefaultIoResolver(const TIntermediate& intermediate) : TDefaultIoResolverBase(intermediate) { }
1284
1285     bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; }
1286
1287     TResourceType getResourceType(const glslang::TType& type) override {
1288         if (isImageType(type)) {
1289             return EResImage;
1290         }
1291         if (isTextureType(type)) {
1292             return EResTexture;
1293         }
1294         if (isSsboType(type)) {
1295             return EResSsbo;
1296         }
1297         if (isSamplerType(type)) {
1298             return EResSampler;
1299         }
1300         if (isUboType(type)) {
1301             return EResUbo;
1302         }
1303         return EResCount;
1304     }
1305
1306     int resolveBinding(EShLanguage stage, TVarEntryInfo& ent) override {
1307         const TType& type = ent.symbol->getType();
1308         const int set = getLayoutSet(type);
1309         // On OpenGL arrays of opaque types take a seperate binding for each element
1310         int numBindings = referenceIntermediate.getSpv().openGl != 0 && type.isSizedArray() ? type.getCumulativeArraySize() : 1;
1311         TResourceType resource = getResourceType(type);
1312         if (resource < EResCount) {
1313             if (type.getQualifier().hasBinding()) {
1314                 return ent.newBinding = reserveSlot(
1315                            set, getBaseBinding(stage, resource, set) + type.getQualifier().layoutBinding, numBindings);
1316             } else if (ent.live && doAutoBindingMapping()) {
1317                 // find free slot, the caller did make sure it passes all vars with binding
1318                 // first and now all are passed that do not have a binding and needs one
1319                 return ent.newBinding = getFreeSlot(set, getBaseBinding(stage, resource, set), numBindings);
1320             }
1321         }
1322         return ent.newBinding = -1;
1323     }
1324 };
1325
1326 #ifdef ENABLE_HLSL
1327 /********************************************************************************
1328 The following IO resolver maps types in HLSL register space, as follows:
1329
1330 t - for shader resource views (SRV)
1331    TEXTURE1D
1332    TEXTURE1DARRAY
1333    TEXTURE2D
1334    TEXTURE2DARRAY
1335    TEXTURE3D
1336    TEXTURECUBE
1337    TEXTURECUBEARRAY
1338    TEXTURE2DMS
1339    TEXTURE2DMSARRAY
1340    STRUCTUREDBUFFER
1341    BYTEADDRESSBUFFER
1342    BUFFER
1343    TBUFFER
1344
1345 s - for samplers
1346    SAMPLER
1347    SAMPLER1D
1348    SAMPLER2D
1349    SAMPLER3D
1350    SAMPLERCUBE
1351    SAMPLERSTATE
1352    SAMPLERCOMPARISONSTATE
1353
1354 u - for unordered access views (UAV)
1355    RWBYTEADDRESSBUFFER
1356    RWSTRUCTUREDBUFFER
1357    APPENDSTRUCTUREDBUFFER
1358    CONSUMESTRUCTUREDBUFFER
1359    RWBUFFER
1360    RWTEXTURE1D
1361    RWTEXTURE1DARRAY
1362    RWTEXTURE2D
1363    RWTEXTURE2DARRAY
1364    RWTEXTURE3D
1365
1366 b - for constant buffer views (CBV)
1367    CBUFFER
1368    CONSTANTBUFFER
1369  ********************************************************************************/
1370 struct TDefaultHlslIoResolver : public TDefaultIoResolverBase {
1371     TDefaultHlslIoResolver(const TIntermediate& intermediate) : TDefaultIoResolverBase(intermediate) { }
1372
1373     bool validateBinding(EShLanguage /*stage*/, TVarEntryInfo& /*ent*/) override { return true; }
1374
1375     TResourceType getResourceType(const glslang::TType& type) override {
1376         if (isUavType(type)) {
1377             return EResUav;
1378         }
1379         if (isSrvType(type)) {
1380             return EResTexture;
1381         }
1382         if (isSamplerType(type)) {
1383             return EResSampler;
1384         }
1385         if (isUboType(type)) {
1386             return EResUbo;
1387         }
1388         return EResCount;
1389     }
1390
1391     int resolveBinding(EShLanguage stage, TVarEntryInfo& ent) override {
1392         const TType& type = ent.symbol->getType();
1393         const int set = getLayoutSet(type);
1394         TResourceType resource = getResourceType(type);
1395         if (resource < EResCount) {
1396             if (type.getQualifier().hasBinding()) {
1397                 return ent.newBinding = reserveSlot(set, getBaseBinding(stage, resource, set) + type.getQualifier().layoutBinding);
1398             } else if (ent.live && doAutoBindingMapping()) {
1399                 // find free slot, the caller did make sure it passes all vars with binding
1400                 // first and now all are passed that do not have a binding and needs one
1401                 return ent.newBinding = getFreeSlot(set, getBaseBinding(stage, resource, set));
1402             }
1403         }
1404         return ent.newBinding = -1;
1405     }
1406 };
1407 #endif
1408
1409 // Map I/O variables to provided offsets, and make bindings for
1410 // unbound but live variables.
1411 //
1412 // Returns false if the input is too malformed to do this.
1413 bool TIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) {
1414     bool somethingToDo = ! intermediate.getResourceSetBinding().empty() || intermediate.getAutoMapBindings() ||
1415                          intermediate.getAutoMapLocations();
1416     // Restrict the stricter condition to further check 'somethingToDo' only if 'somethingToDo' has not been set, reduce
1417     // unnecessary or insignificant for-loop operation after 'somethingToDo' have been true.
1418     for (int res = 0; (res < EResCount && !somethingToDo); ++res) {
1419         somethingToDo = somethingToDo || (intermediate.getShiftBinding(TResourceType(res)) != 0) ||
1420                         intermediate.hasShiftBindingForSet(TResourceType(res));
1421     }
1422     if (! somethingToDo && resolver == nullptr)
1423         return true;
1424     if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive())
1425         return false;
1426     TIntermNode* root = intermediate.getTreeRoot();
1427     if (root == nullptr)
1428         return false;
1429     // if no resolver is provided, use the default resolver with the given shifts and auto map settings
1430     TDefaultIoResolver defaultResolver(intermediate);
1431 #ifdef ENABLE_HLSL
1432     TDefaultHlslIoResolver defaultHlslResolver(intermediate);
1433     if (resolver == nullptr) {
1434         // TODO: use a passed in IO mapper for this
1435         if (intermediate.usingHlslIoMapping())
1436             resolver = &defaultHlslResolver;
1437         else
1438             resolver = &defaultResolver;
1439     }
1440 #else
1441     resolver = &defaultResolver;
1442 #endif
1443     resolver->addStage(stage, intermediate);
1444
1445     TVarLiveMap inVarMap, outVarMap, uniformVarMap;
1446     TVarLiveVector inVector, outVector, uniformVector;
1447     TVarGatherTraverser iter_binding_all(intermediate, true, inVarMap, outVarMap, uniformVarMap);
1448     TVarGatherTraverser iter_binding_live(intermediate, false, inVarMap, outVarMap, uniformVarMap);
1449     root->traverse(&iter_binding_all);
1450     iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str());
1451     while (! iter_binding_live.destinations.empty()) {
1452         TIntermNode* destination = iter_binding_live.destinations.back();
1453         iter_binding_live.destinations.pop_back();
1454         destination->traverse(&iter_binding_live);
1455     }
1456
1457     // sort entries by priority. see TVarEntryInfo::TOrderByPriority for info.
1458     for (auto& var : inVarMap) { inVector.push_back(var); }
1459     std::sort(inVector.begin(), inVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1460         return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1461     });
1462     for (auto& var : outVarMap) { outVector.push_back(var); }
1463     std::sort(outVector.begin(), outVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1464         return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1465     });
1466     for (auto& var : uniformVarMap) { uniformVector.push_back(var); }
1467     std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1468         return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1469     });
1470     bool hadError = false;
1471     TVarLiveMap* dummyUniformVarMap[EShLangCount] = {};
1472     TNotifyInOutAdaptor inOutNotify(stage, *resolver);
1473     TNotifyUniformAdaptor uniformNotify(stage, *resolver);
1474     TResolverUniformAdaptor uniformResolve(stage, *resolver, dummyUniformVarMap, infoSink, hadError);
1475     TResolverInOutAdaptor inOutResolve(stage, *resolver, infoSink, hadError);
1476     resolver->beginNotifications(stage);
1477     std::for_each(inVector.begin(), inVector.end(), inOutNotify);
1478     std::for_each(outVector.begin(), outVector.end(), inOutNotify);
1479     std::for_each(uniformVector.begin(), uniformVector.end(), uniformNotify);
1480     resolver->endNotifications(stage);
1481     resolver->beginResolve(stage);
1482     for (auto& var : inVector) { inOutResolve(var); }
1483     std::for_each(inVector.begin(), inVector.end(), [&inVarMap](TVarLivePair p) {
1484         auto at = inVarMap.find(p.second.symbol->getAccessName());
1485         if (at != inVarMap.end() && p.second.id == at->second.id)
1486             at->second = p.second;
1487     });
1488     for (auto& var : outVector) { inOutResolve(var); }
1489     std::for_each(outVector.begin(), outVector.end(), [&outVarMap](TVarLivePair p) {
1490         auto at = outVarMap.find(p.second.symbol->getAccessName());
1491         if (at != outVarMap.end() && p.second.id == at->second.id)
1492             at->second = p.second;
1493     });
1494     std::for_each(uniformVector.begin(), uniformVector.end(), uniformResolve);
1495     std::for_each(uniformVector.begin(), uniformVector.end(), [&uniformVarMap](TVarLivePair p) {
1496         auto at = uniformVarMap.find(p.second.symbol->getAccessName());
1497         if (at != uniformVarMap.end() && p.second.id == at->second.id)
1498             at->second = p.second;
1499     });
1500     resolver->endResolve(stage);
1501     if (!hadError) {
1502         TVarSetTraverser iter_iomap(intermediate, inVarMap, outVarMap, uniformVarMap);
1503         root->traverse(&iter_iomap);
1504     }
1505     return !hadError;
1506 }
1507
1508 // Map I/O variables to provided offsets, and make bindings for
1509 // unbound but live variables.
1510 //
1511 // Returns false if the input is too malformed to do this.
1512 bool TGlslIoMapper::addStage(EShLanguage stage, TIntermediate& intermediate, TInfoSink& infoSink, TIoMapResolver* resolver) {
1513     bool somethingToDo = !intermediate.getResourceSetBinding().empty() ||
1514         intermediate.getAutoMapBindings() ||
1515         intermediate.getAutoMapLocations();
1516
1517     // Profile and version are use for symbol validate.
1518     profile = intermediate.getProfile();
1519     version = intermediate.getVersion();
1520
1521     // Restrict the stricter condition to further check 'somethingToDo' only if 'somethingToDo' has not been set, reduce
1522     // unnecessary or insignificant for-loop operation after 'somethingToDo' have been true.
1523     for (int res = 0; (res < EResCount && !somethingToDo); ++res) {
1524         somethingToDo = somethingToDo || (intermediate.getShiftBinding(TResourceType(res)) != 0) ||
1525                         intermediate.hasShiftBindingForSet(TResourceType(res));
1526     }
1527     if (! somethingToDo && resolver == nullptr) {
1528         return true;
1529     }
1530     if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive()) {
1531         return false;
1532     }
1533     TIntermNode* root = intermediate.getTreeRoot();
1534     if (root == nullptr) {
1535         return false;
1536     }
1537     // if no resolver is provided, use the default resolver with the given shifts and auto map settings
1538     TDefaultGlslIoResolver defaultResolver(intermediate);
1539 #ifdef ENABLE_HLSL
1540     TDefaultHlslIoResolver defaultHlslResolver(intermediate);
1541     if (resolver == nullptr) {
1542         // TODO: use a passed in IO mapper for this
1543         if (intermediate.usingHlslIoMapping())
1544             resolver = &defaultHlslResolver;
1545         else
1546             resolver = &defaultResolver;
1547     }
1548 #else
1549     if (resolver == nullptr) {
1550         resolver = &defaultResolver;
1551     }
1552 #endif
1553     resolver->addStage(stage, intermediate);
1554     inVarMaps[stage] = new TVarLiveMap(); outVarMaps[stage] = new TVarLiveMap(); uniformVarMap[stage] = new TVarLiveMap();
1555     TVarGatherTraverser iter_binding_all(intermediate, true, *inVarMaps[stage], *outVarMaps[stage],
1556                                          *uniformVarMap[stage]);
1557     TVarGatherTraverser iter_binding_live(intermediate, false, *inVarMaps[stage], *outVarMaps[stage],
1558                                           *uniformVarMap[stage]);
1559     root->traverse(&iter_binding_all);
1560     iter_binding_live.pushFunction(intermediate.getEntryPointMangledName().c_str());
1561     while (! iter_binding_live.destinations.empty()) {
1562         TIntermNode* destination = iter_binding_live.destinations.back();
1563         iter_binding_live.destinations.pop_back();
1564         destination->traverse(&iter_binding_live);
1565     }
1566
1567     TNotifyInOutAdaptor inOutNotify(stage, *resolver);
1568     TNotifyUniformAdaptor uniformNotify(stage, *resolver);
1569     // Resolve current stage input symbol location with previous stage output here,
1570     // uniform symbol, ubo, ssbo and opaque symbols are per-program resource,
1571     // will resolve uniform symbol location and ubo/ssbo/opaque binding in doMap()
1572     resolver->beginNotifications(stage);
1573     std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), inOutNotify);
1574     std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), inOutNotify);
1575     std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(), uniformNotify);
1576     resolver->endNotifications(stage);
1577     TSlotCollector slotCollector(*resolver, infoSink);
1578     resolver->beginCollect(stage);
1579     std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(), slotCollector);
1580     std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(), slotCollector);
1581     std::for_each(uniformVarMap[stage]->begin(), uniformVarMap[stage]->end(), slotCollector);
1582     resolver->endCollect(stage);
1583     intermediates[stage] = &intermediate;
1584     return !hadError;
1585 }
1586
1587 bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) {
1588     resolver->endResolve(EShLangCount);
1589     if (!hadError) {
1590         //Resolve uniform location, ubo/ssbo/opaque bindings across stages
1591         TResolverUniformAdaptor uniformResolve(EShLangCount, *resolver, uniformVarMap, infoSink, hadError);
1592         TResolverInOutAdaptor inOutResolve(EShLangCount, *resolver, infoSink, hadError);
1593         TSymbolValidater symbolValidater(*resolver, infoSink, inVarMaps,
1594                                          outVarMaps, uniformVarMap, hadError, profile, version);
1595
1596         TVarLiveVector inVectors[EShLangCount];
1597         TVarLiveVector outVectors[EShLangCount];
1598         TVarLiveVector uniformVector;
1599
1600         resolver->beginResolve(EShLangCount);
1601         for (int stage = EShLangVertex; stage < EShLangCount; stage++) {
1602             if (inVarMaps[stage] != nullptr) {
1603                 inOutResolve.setStage(EShLanguage(stage));
1604
1605                 // copy vars into a sorted list
1606                 std::for_each(inVarMaps[stage]->begin(), inVarMaps[stage]->end(),
1607                         [&inVectors, stage](TVarLivePair p) { inVectors[stage].push_back(p); });
1608                 std::sort(inVectors[stage].begin(), inVectors[stage].end(),
1609                         [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1610                             return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1611                 });
1612
1613                 std::for_each(outVarMaps[stage]->begin(), outVarMaps[stage]->end(),
1614                         [&outVectors, stage](TVarLivePair p) { outVectors[stage].push_back(p); });
1615                 std::sort(outVectors[stage].begin(), outVectors[stage].end(),
1616                         [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1617                             return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1618                 });
1619
1620                 for (auto& var : inVectors[stage]) { symbolValidater(var); }
1621                 for (auto& var : inVectors[stage]) { inOutResolve(var); }
1622                 for (auto& var : outVectors[stage]) { symbolValidater(var); }
1623                 for (auto& var : outVectors[stage]) { inOutResolve(var); }
1624
1625                 // copy results back into maps
1626                 std::for_each(inVectors[stage].begin(), inVectors[stage].end(),
1627                     [this, stage](TVarLivePair p) {
1628                         auto at = inVarMaps[stage]->find(p.first);
1629                         if (at != inVarMaps[stage]->end())
1630                             at->second = p.second;
1631                 });
1632
1633                 std::for_each(outVectors[stage].begin(), outVectors[stage].end(),
1634                     [this, stage](TVarLivePair p) {
1635                         auto at = outVarMaps[stage]->find(p.first);
1636                         if (at != outVarMaps[stage]->end())
1637                             at->second = p.second;
1638                 });
1639
1640             }
1641             if (uniformVarMap[stage] != nullptr) {
1642                 uniformResolve.setStage(EShLanguage(stage));
1643                 for (auto& var : *(uniformVarMap[stage])) { uniformVector.push_back(var); }
1644             }
1645         }
1646         std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1647             return TVarEntryInfo::TOrderByPriorityAndLive()(p1.second, p2.second);
1648         });
1649         for (auto& var : uniformVector) { symbolValidater(var); }
1650         for (auto& var : uniformVector) { uniformResolve(var); }
1651         std::sort(uniformVector.begin(), uniformVector.end(), [](const TVarLivePair& p1, const TVarLivePair& p2) -> bool {
1652             return TVarEntryInfo::TOrderByPriority()(p1.second, p2.second);
1653         });
1654         resolver->endResolve(EShLangCount);
1655         if (autoPushConstantBlockName.length()) {
1656             bool upgraded = false;
1657             for (size_t stage = 0; stage < EShLangCount; stage++) {
1658                 if (intermediates[stage] != nullptr) {
1659                     TVarLiveMap** pUniformVarMap = uniformResolve.uniformVarMap;
1660                     auto at = pUniformVarMap[stage]->find(autoPushConstantBlockName);
1661                     if (at == pUniformVarMap[stage]->end())
1662                         continue;
1663                     TQualifier& qualifier = at->second.symbol->getQualifier();
1664                     if (!qualifier.isUniform())
1665                         continue;
1666                     TType& t = at->second.symbol->getWritableType();
1667                     int size, stride;
1668                     TIntermediate::getBaseAlignment(t, size, stride, autoPushConstantBlockPacking,
1669                                                     qualifier.layoutMatrix == ElmRowMajor);
1670                     if (size <= int(autoPushConstantMaxSize)) {
1671                         qualifier.setBlockStorage(EbsPushConstant);
1672                         qualifier.layoutPacking = autoPushConstantBlockPacking;
1673                         upgraded = true;
1674                     }
1675                 }
1676             }
1677             // If it's been upgraded to push_constant, then remove it from the uniformVector
1678             // so it doesn't get a set/binding assigned to it.
1679             if (upgraded) {
1680                 auto at = std::find_if(uniformVector.begin(), uniformVector.end(),
1681                                        [this](const TVarLivePair& p) { return p.first == autoPushConstantBlockName; });
1682                 if (at != uniformVector.end())
1683                     uniformVector.erase(at);
1684             }
1685         }
1686         for (size_t stage = 0; stage < EShLangCount; stage++) {
1687             if (intermediates[stage] != nullptr) {
1688                 // traverse each stage, set new location to each input/output and unifom symbol, set new binding to
1689                 // ubo, ssbo and opaque symbols
1690                 TVarLiveMap** pUniformVarMap = uniformResolve.uniformVarMap;
1691                 std::for_each(uniformVector.begin(), uniformVector.end(), [pUniformVarMap, stage](TVarLivePair p) {
1692                     auto at = pUniformVarMap[stage]->find(p.second.symbol->getAccessName());
1693                     if (at != pUniformVarMap[stage]->end() && at->second.id == p.second.id){
1694                         int resolvedBinding = at->second.newBinding;
1695                         at->second = p.second;
1696                         if (resolvedBinding > 0)
1697                             at->second.newBinding = resolvedBinding;
1698                     }
1699                 });
1700                 TVarSetTraverser iter_iomap(*intermediates[stage], *inVarMaps[stage], *outVarMaps[stage],
1701                                             *uniformResolve.uniformVarMap[stage]);
1702                 intermediates[stage]->getTreeRoot()->traverse(&iter_iomap);
1703             }
1704         }
1705         return !hadError;
1706     } else {
1707         return false;
1708     }
1709 }
1710
1711 } // end namespace glslang
1712
1713 #endif // !GLSLANG_WEB && !GLSLANG_ANGLE