• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2013-2016 LunarG, Inc.
3 //
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
8 // are met:
9 //
10 //    Redistributions of source code must retain the above copyright
11 //    notice, this list of conditions and the following disclaimer.
12 //
13 //    Redistributions in binary form must reproduce the above
14 //    copyright notice, this list of conditions and the following
15 //    disclaimer in the documentation and/or other materials provided
16 //    with the distribution.
17 //
18 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19 //    contributors may be used to endorse or promote products derived
20 //    from this software without specific prior written permission.
21 //
22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 // POSSIBILITY OF SUCH DAMAGE.
34 //
35 
36 #include "../Include/Common.h"
37 #include "reflection.h"
38 #include "LiveTraverser.h"
39 #include "localintermediate.h"
40 
41 #include "gl_types.h"
42 
43 //
44 // Grow the reflection database through a friend traverser class of TReflection and a
45 // collection of functions to do a liveness traversal that note what uniforms are used
46 // in semantically non-dead code.
47 //
48 // Can be used multiple times, once per stage, to grow a program reflection.
49 //
50 // High-level algorithm for one stage:
51 //
52 // 1. Put the entry point on the list of live functions.
53 //
54 // 2. Traverse any live function, while skipping if-tests with a compile-time constant
55 //    condition of false, and while adding any encountered function calls to the live
56 //    function list.
57 //
58 //    Repeat until the live function list is empty.
59 //
60 // 3. Add any encountered uniform variables and blocks to the reflection database.
61 //
62 // Can be attempted with a failed link, but will return false if recursion had been detected, or
63 // there wasn't exactly one entry point.
64 //
65 
66 namespace glslang {
67 
68 //
69 // The traverser: mostly pass through, except
70 //  - processing binary nodes to see if they are dereferences of an aggregates to track
71 //  - processing symbol nodes to see if they are non-aggregate objects to track
72 //
73 // This ignores semantically dead code by using TLiveTraverser.
74 //
75 // This is in the glslang namespace directly so it can be a friend of TReflection.
76 //
77 
78 class TReflectionTraverser : public TLiveTraverser {
79 public:
TReflectionTraverser(const TIntermediate & i,TReflection & r)80     TReflectionTraverser(const TIntermediate& i, TReflection& r) :
81          TLiveTraverser(i), reflection(r) { }
82 
83     virtual bool visitBinary(TVisit, TIntermBinary* node);
84     virtual void visitSymbol(TIntermSymbol* base);
85 
86     // Add a simple reference to a uniform variable to the uniform database, no dereference involved.
87     // However, no dereference doesn't mean simple... it could be a complex aggregate.
addUniform(const TIntermSymbol & base)88     void addUniform(const TIntermSymbol& base)
89     {
90         if (processedDerefs.find(&base) == processedDerefs.end()) {
91             processedDerefs.insert(&base);
92 
93             // Use a degenerate (empty) set of dereferences to immediately put as at the end of
94             // the dereference change expected by blowUpActiveAggregate.
95             TList<TIntermBinary*> derefs;
96             blowUpActiveAggregate(base.getType(), base.getName(), derefs, derefs.end(), -1, -1, 0);
97         }
98     }
99 
addAttribute(const TIntermSymbol & base)100     void addAttribute(const TIntermSymbol& base)
101     {
102         if (processedDerefs.find(&base) == processedDerefs.end()) {
103             processedDerefs.insert(&base);
104 
105             const TString &name = base.getName();
106             const TType &type = base.getType();
107 
108             TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
109             if (it == reflection.nameToIndex.end()) {
110                 reflection.nameToIndex[name] = (int)reflection.indexToAttribute.size();
111                 reflection.indexToAttribute.push_back(TObjectReflection(name, type, 0, mapToGlType(type), 0, 0));
112             }
113         }
114     }
115 
116     // Lookup or calculate the offset of a block member, using the recursively
117     // defined block offset rules.
getOffset(const TType & type,int index)118     int getOffset(const TType& type, int index)
119     {
120         const TTypeList& memberList = *type.getStruct();
121 
122         // Don't calculate offset if one is present, it could be user supplied
123         // and different than what would be calculated.  That is, this is faster,
124         // but not just an optimization.
125         if (memberList[index].type->getQualifier().hasOffset())
126             return memberList[index].type->getQualifier().layoutOffset;
127 
128         int memberSize;
129         int dummyStride;
130         int offset = 0;
131         for (int m = 0; m <= index; ++m) {
132             // modify just the children's view of matrix layout, if there is one for this member
133             TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix;
134             int memberAlignment = intermediate.getMemberAlignment(*memberList[m].type, memberSize, dummyStride,
135                                                                   type.getQualifier().layoutPacking,
136                                                                   subMatrixLayout != ElmNone
137                                                                       ? subMatrixLayout == ElmRowMajor
138                                                                       : type.getQualifier().layoutMatrix == ElmRowMajor);
139             RoundToPow2(offset, memberAlignment);
140             if (m < index)
141                 offset += memberSize;
142         }
143 
144         return offset;
145     }
146 
147     // Calculate the block data size.
148     // Block arrayness is not taken into account, each element is backed by a separate buffer.
getBlockSize(const TType & blockType)149     int getBlockSize(const TType& blockType)
150     {
151         const TTypeList& memberList = *blockType.getStruct();
152         int lastIndex = (int)memberList.size() - 1;
153         int lastOffset = getOffset(blockType, lastIndex);
154 
155         int lastMemberSize;
156         int dummyStride;
157         intermediate.getMemberAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride,
158                                         blockType.getQualifier().layoutPacking,
159                                         blockType.getQualifier().layoutMatrix == ElmRowMajor);
160 
161         return lastOffset + lastMemberSize;
162     }
163 
164     // Traverse the provided deref chain, including the base, and
165     // - build a full reflection-granularity name, array size, etc. entry out of it, if it goes down to that granularity
166     // - recursively expand any variable array index in the middle of that traversal
167     // - recursively expand what's left at the end if the deref chain did not reach down to reflection granularity
168     //
169     // arraySize tracks, just for the final dereference in the chain, if there was a specific known size.
170     // A value of 0 for arraySize will mean to use the full array's size.
blowUpActiveAggregate(const TType & baseType,const TString & baseName,const TList<TIntermBinary * > & derefs,TList<TIntermBinary * >::const_iterator deref,int offset,int blockIndex,int arraySize)171     void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList<TIntermBinary*>& derefs,
172                                TList<TIntermBinary*>::const_iterator deref, int offset, int blockIndex, int arraySize)
173     {
174         // process the part of the dereference chain that was explicit in the shader
175         TString name = baseName;
176         const TType* terminalType = &baseType;
177         for (; deref != derefs.end(); ++deref) {
178             TIntermBinary* visitNode = *deref;
179             terminalType = &visitNode->getType();
180             int index;
181             switch (visitNode->getOp()) {
182             case EOpIndexIndirect:
183                 // Visit all the indices of this array, and for each one add on the remaining dereferencing
184                 for (int i = 0; i < std::max(visitNode->getLeft()->getType().getOuterArraySize(), 1); ++i) {
185                     TString newBaseName = name;
186                     if (baseType.getBasicType() != EbtBlock)
187                         newBaseName.append(TString("[") + String(i) + "]");
188                     TList<TIntermBinary*>::const_iterator nextDeref = deref;
189                     ++nextDeref;
190                     TType derefType(*terminalType, 0);
191                     blowUpActiveAggregate(derefType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize);
192                 }
193 
194                 // it was all completed in the recursive calls above
195                 return;
196             case EOpIndexDirect:
197                 index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
198                 if (baseType.getBasicType() != EbtBlock)
199                     name.append(TString("[") + String(index) + "]");
200                 break;
201             case EOpIndexDirectStruct:
202                 index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
203                 if (offset >= 0)
204                     offset += getOffset(visitNode->getLeft()->getType(), index);
205                 if (name.size() > 0)
206                     name.append(".");
207                 name.append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName());
208                 break;
209             default:
210                 break;
211             }
212         }
213 
214         // if the terminalType is still too coarse a granularity, this is still an aggregate to expand, expand it...
215         if (! isReflectionGranularity(*terminalType)) {
216             if (terminalType->isArray()) {
217                 // Visit all the indices of this array, and for each one,
218                 // fully explode the remaining aggregate to dereference
219                 for (int i = 0; i < std::max(terminalType->getOuterArraySize(), 1); ++i) {
220                     TString newBaseName = name;
221                     newBaseName.append(TString("[") + String(i) + "]");
222                     TType derefType(*terminalType, 0);
223                     blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0);
224                 }
225             } else {
226                 // Visit all members of this aggregate, and for each one,
227                 // fully explode the remaining aggregate to dereference
228                 const TTypeList& typeList = *terminalType->getStruct();
229                 for (int i = 0; i < (int)typeList.size(); ++i) {
230                     TString newBaseName = name;
231                     newBaseName.append(TString(".") + typeList[i].type->getFieldName());
232                     TType derefType(*terminalType, i);
233                     blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0);
234                 }
235             }
236 
237             // it was all completed in the recursive calls above
238             return;
239         }
240 
241         // Finally, add a full string to the reflection database, and update the array size if necessary.
242         // If the dereferenced entity to record is an array, compute the size and update the maximum size.
243 
244         // there might not be a final array dereference, it could have been copied as an array object
245         if (arraySize == 0)
246             arraySize = mapToGlArraySize(*terminalType);
247 
248         TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
249         if (it == reflection.nameToIndex.end()) {
250             reflection.nameToIndex[name] = (int)reflection.indexToUniform.size();
251             reflection.indexToUniform.push_back(TObjectReflection(name, *terminalType, offset,
252                                                                   mapToGlType(*terminalType),
253                                                                   arraySize, blockIndex));
254         } else if (arraySize > 1) {
255             int& reflectedArraySize = reflection.indexToUniform[it->second].size;
256             reflectedArraySize = std::max(arraySize, reflectedArraySize);
257         }
258     }
259 
260     // Add a uniform dereference where blocks/struct/arrays are involved in the access.
261     // Handles the situation where the left node is at the correct or too coarse a
262     // granularity for reflection.  (That is, further dereferences up the tree will be
263     // skipped.) Earlier dereferences, down the tree, will be handled
264     // at the same time, and logged to prevent reprocessing as the tree is traversed.
265     //
266     // Note: Other things like the following must be caught elsewhere:
267     //  - a simple non-array, non-struct variable (no dereference even conceivable)
268     //  - an aggregrate consumed en masse, without a dereference
269     //
270     // So, this code is for cases like
271     //   - a struct/block dereferencing a member (whether the member is array or not)
272     //   - an array of struct
273     //   - structs/arrays containing the above
274     //
addDereferencedUniform(TIntermBinary * topNode)275     void addDereferencedUniform(TIntermBinary* topNode)
276     {
277         // See if too fine-grained to process (wait to get further down the tree)
278         const TType& leftType = topNode->getLeft()->getType();
279         if ((leftType.isVector() || leftType.isMatrix()) && ! leftType.isArray())
280             return;
281 
282         // We have an array or structure or block dereference, see if it's a uniform
283         // based dereference (if not, skip it).
284         TIntermSymbol* base = findBase(topNode);
285         if (! base || ! base->getQualifier().isUniformOrBuffer())
286             return;
287 
288         // See if we've already processed this (e.g., in the middle of something
289         // we did earlier), and if so skip it
290         if (processedDerefs.find(topNode) != processedDerefs.end())
291             return;
292 
293         // Process this uniform dereference
294 
295         int offset = -1;
296         int blockIndex = -1;
297         bool anonymous = false;
298 
299         // See if we need to record the block itself
300         bool block = base->getBasicType() == EbtBlock;
301         if (block) {
302             offset = 0;
303             anonymous = IsAnonymous(base->getName());
304 
305             const TString& blockName = base->getType().getTypeName();
306 
307             if (base->getType().isArray()) {
308                 TType derefType(base->getType(), 0);
309 
310                 assert(! anonymous);
311                 for (int e = 0; e < base->getType().getCumulativeArraySize(); ++e)
312                     blockIndex = addBlockName(blockName + "[" + String(e) + "]", derefType,
313                                               getBlockSize(base->getType()));
314             } else
315                 blockIndex = addBlockName(blockName, base->getType(), getBlockSize(base->getType()));
316         }
317 
318         // Process the dereference chain, backward, accumulating the pieces for later forward traversal.
319         // If the topNode is a reflection-granularity-array dereference, don't include that last dereference.
320         TList<TIntermBinary*> derefs;
321         for (TIntermBinary* visitNode = topNode; visitNode; visitNode = visitNode->getLeft()->getAsBinaryNode()) {
322             if (isReflectionGranularity(visitNode->getLeft()->getType()))
323                 continue;
324 
325             derefs.push_front(visitNode);
326             processedDerefs.insert(visitNode);
327         }
328         processedDerefs.insert(base);
329 
330         // See if we have a specific array size to stick to while enumerating the explosion of the aggregate
331         int arraySize = 0;
332         if (isReflectionGranularity(topNode->getLeft()->getType()) && topNode->getLeft()->isArray()) {
333             if (topNode->getOp() == EOpIndexDirect)
334                 arraySize = topNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst() + 1;
335         }
336 
337         // Put the dereference chain together, forward
338         TString baseName;
339         if (! anonymous) {
340             if (block)
341                 baseName = base->getType().getTypeName();
342             else
343                 baseName = base->getName();
344         }
345         blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize);
346     }
347 
addBlockName(const TString & name,const TType & type,int size)348     int addBlockName(const TString& name, const TType& type, int size)
349     {
350         int blockIndex;
351         TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
352         if (reflection.nameToIndex.find(name) == reflection.nameToIndex.end()) {
353             blockIndex = (int)reflection.indexToUniformBlock.size();
354             reflection.nameToIndex[name] = blockIndex;
355             reflection.indexToUniformBlock.push_back(TObjectReflection(name, type, -1, -1, size, -1));
356         } else
357             blockIndex = it->second;
358 
359         return blockIndex;
360     }
361 
362     // Are we at a level in a dereference chain at which individual active uniform queries are made?
isReflectionGranularity(const TType & type)363     bool isReflectionGranularity(const TType& type)
364     {
365         return type.getBasicType() != EbtBlock && type.getBasicType() != EbtStruct;
366     }
367 
368     // For a binary operation indexing into an aggregate, chase down the base of the aggregate.
369     // Return 0 if the topology does not fit this situation.
findBase(const TIntermBinary * node)370     TIntermSymbol* findBase(const TIntermBinary* node)
371     {
372         TIntermSymbol *base = node->getLeft()->getAsSymbolNode();
373         if (base)
374             return base;
375         TIntermBinary* left = node->getLeft()->getAsBinaryNode();
376         if (! left)
377             return nullptr;
378 
379         return findBase(left);
380     }
381 
382     //
383     // Translate a glslang sampler type into the GL API #define number.
384     //
mapSamplerToGlType(TSampler sampler)385     int mapSamplerToGlType(TSampler sampler)
386     {
387         if (! sampler.image) {
388             // a sampler...
389             switch (sampler.type) {
390             case EbtFloat:
391                 switch ((int)sampler.dim) {
392                 case Esd1D:
393                     switch ((int)sampler.shadow) {
394                     case false: return sampler.arrayed ? GL_SAMPLER_1D_ARRAY : GL_SAMPLER_1D;
395                     case true:  return sampler.arrayed ? GL_SAMPLER_1D_ARRAY_SHADOW : GL_SAMPLER_1D_SHADOW;
396                     }
397                 case Esd2D:
398                     switch ((int)sampler.ms) {
399                     case false:
400                         switch ((int)sampler.shadow) {
401                         case false: return sampler.arrayed ? GL_SAMPLER_2D_ARRAY : GL_SAMPLER_2D;
402                         case true:  return sampler.arrayed ? GL_SAMPLER_2D_ARRAY_SHADOW : GL_SAMPLER_2D_SHADOW;
403                         }
404                     case true:      return sampler.arrayed ? GL_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_SAMPLER_2D_MULTISAMPLE;
405                     }
406                 case Esd3D:
407                     return GL_SAMPLER_3D;
408                 case EsdCube:
409                     switch ((int)sampler.shadow) {
410                     case false: return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY : GL_SAMPLER_CUBE;
411                     case true:  return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW : GL_SAMPLER_CUBE_SHADOW;
412                     }
413                 case EsdRect:
414                     return sampler.shadow ? GL_SAMPLER_2D_RECT_SHADOW : GL_SAMPLER_2D_RECT;
415                 case EsdBuffer:
416                     return GL_SAMPLER_BUFFER;
417                 }
418 #ifdef AMD_EXTENSIONS
419             case EbtFloat16:
420                 switch ((int)sampler.dim) {
421                 case Esd1D:
422                     switch ((int)sampler.shadow) {
423                     case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_AMD : GL_FLOAT16_SAMPLER_1D_AMD;
424                     case true:  return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_1D_SHADOW_AMD;
425                     }
426                 case Esd2D:
427                     switch ((int)sampler.ms) {
428                     case false:
429                         switch ((int)sampler.shadow) {
430                         case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_AMD;
431                         case true:  return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_2D_SHADOW_AMD;
432                         }
433                     case true:      return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_AMD;
434                     }
435                 case Esd3D:
436                     return GL_FLOAT16_SAMPLER_3D_AMD;
437                 case EsdCube:
438                     switch ((int)sampler.shadow) {
439                     case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_AMD : GL_FLOAT16_SAMPLER_CUBE_AMD;
440                     case true:  return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_CUBE_SHADOW_AMD;
441                     }
442                 case EsdRect:
443                     return sampler.shadow ? GL_FLOAT16_SAMPLER_2D_RECT_SHADOW_AMD : GL_FLOAT16_SAMPLER_2D_RECT_AMD;
444                 case EsdBuffer:
445                     return GL_FLOAT16_SAMPLER_BUFFER_AMD;
446                 }
447 #endif
448             case EbtInt:
449                 switch ((int)sampler.dim) {
450                 case Esd1D:
451                     return sampler.arrayed ? GL_INT_SAMPLER_1D_ARRAY : GL_INT_SAMPLER_1D;
452                 case Esd2D:
453                     switch ((int)sampler.ms) {
454                     case false:  return sampler.arrayed ? GL_INT_SAMPLER_2D_ARRAY : GL_INT_SAMPLER_2D;
455                     case true:   return sampler.arrayed ? GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY
456                                                         : GL_INT_SAMPLER_2D_MULTISAMPLE;
457                     }
458                 case Esd3D:
459                     return GL_INT_SAMPLER_3D;
460                 case EsdCube:
461                     return sampler.arrayed ? GL_INT_SAMPLER_CUBE_MAP_ARRAY : GL_INT_SAMPLER_CUBE;
462                 case EsdRect:
463                     return GL_INT_SAMPLER_2D_RECT;
464                 case EsdBuffer:
465                     return GL_INT_SAMPLER_BUFFER;
466                 }
467             case EbtUint:
468                 switch ((int)sampler.dim) {
469                 case Esd1D:
470                     return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_1D_ARRAY : GL_UNSIGNED_INT_SAMPLER_1D;
471                 case Esd2D:
472                     switch ((int)sampler.ms) {
473                     case false:  return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D;
474                     case true:   return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY
475                                                         : GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE;
476                     }
477                 case Esd3D:
478                     return GL_UNSIGNED_INT_SAMPLER_3D;
479                 case EsdCube:
480                     return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY : GL_UNSIGNED_INT_SAMPLER_CUBE;
481                 case EsdRect:
482                     return GL_UNSIGNED_INT_SAMPLER_2D_RECT;
483                 case EsdBuffer:
484                     return GL_UNSIGNED_INT_SAMPLER_BUFFER;
485                 }
486             default:
487                 return 0;
488             }
489         } else {
490             // an image...
491             switch (sampler.type) {
492             case EbtFloat:
493                 switch ((int)sampler.dim) {
494                 case Esd1D:
495                     return sampler.arrayed ? GL_IMAGE_1D_ARRAY : GL_IMAGE_1D;
496                 case Esd2D:
497                     switch ((int)sampler.ms) {
498                     case false:     return sampler.arrayed ? GL_IMAGE_2D_ARRAY : GL_IMAGE_2D;
499                     case true:      return sampler.arrayed ? GL_IMAGE_2D_MULTISAMPLE_ARRAY : GL_IMAGE_2D_MULTISAMPLE;
500                     }
501                 case Esd3D:
502                     return GL_IMAGE_3D;
503                 case EsdCube:
504                     return sampler.arrayed ? GL_IMAGE_CUBE_MAP_ARRAY : GL_IMAGE_CUBE;
505                 case EsdRect:
506                     return GL_IMAGE_2D_RECT;
507                 case EsdBuffer:
508                     return GL_IMAGE_BUFFER;
509                 }
510 #ifdef AMD_EXTENSIONS
511             case EbtFloat16:
512                 switch ((int)sampler.dim) {
513                 case Esd1D:
514                     return sampler.arrayed ? GL_FLOAT16_IMAGE_1D_ARRAY_AMD : GL_FLOAT16_IMAGE_1D_AMD;
515                 case Esd2D:
516                     switch ((int)sampler.ms) {
517                     case false:     return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_AMD;
518                     case true:      return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_MULTISAMPLE_AMD;
519                     }
520                 case Esd3D:
521                     return GL_FLOAT16_IMAGE_3D_AMD;
522                 case EsdCube:
523                     return sampler.arrayed ? GL_FLOAT16_IMAGE_CUBE_MAP_ARRAY_AMD : GL_FLOAT16_IMAGE_CUBE_AMD;
524                 case EsdRect:
525                     return GL_FLOAT16_IMAGE_2D_RECT_AMD;
526                 case EsdBuffer:
527                     return GL_FLOAT16_IMAGE_BUFFER_AMD;
528                 }
529 #endif
530             case EbtInt:
531                 switch ((int)sampler.dim) {
532                 case Esd1D:
533                     return sampler.arrayed ? GL_INT_IMAGE_1D_ARRAY : GL_INT_IMAGE_1D;
534                 case Esd2D:
535                     switch ((int)sampler.ms) {
536                     case false:  return sampler.arrayed ? GL_INT_IMAGE_2D_ARRAY : GL_INT_IMAGE_2D;
537                     case true:   return sampler.arrayed ? GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY : GL_INT_IMAGE_2D_MULTISAMPLE;
538                     }
539                 case Esd3D:
540                     return GL_INT_IMAGE_3D;
541                 case EsdCube:
542                     return sampler.arrayed ? GL_INT_IMAGE_CUBE_MAP_ARRAY : GL_INT_IMAGE_CUBE;
543                 case EsdRect:
544                     return GL_INT_IMAGE_2D_RECT;
545                 case EsdBuffer:
546                     return GL_INT_IMAGE_BUFFER;
547                 }
548             case EbtUint:
549                 switch ((int)sampler.dim) {
550                 case Esd1D:
551                     return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_1D_ARRAY : GL_UNSIGNED_INT_IMAGE_1D;
552                 case Esd2D:
553                     switch ((int)sampler.ms) {
554                     case false:  return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_ARRAY : GL_UNSIGNED_INT_IMAGE_2D;
555                     case true:   return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY
556                                                         : GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE;
557                     }
558                 case Esd3D:
559                     return GL_UNSIGNED_INT_IMAGE_3D;
560                 case EsdCube:
561                     return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY : GL_UNSIGNED_INT_IMAGE_CUBE;
562                 case EsdRect:
563                     return GL_UNSIGNED_INT_IMAGE_2D_RECT;
564                 case EsdBuffer:
565                     return GL_UNSIGNED_INT_IMAGE_BUFFER;
566                 }
567             default:
568                 return 0;
569             }
570         }
571     }
572 
573     //
574     // Translate a glslang type into the GL API #define number.
575     // Ignores arrayness.
576     //
mapToGlType(const TType & type)577     int mapToGlType(const TType& type)
578     {
579         switch (type.getBasicType()) {
580         case EbtSampler:
581             return mapSamplerToGlType(type.getSampler());
582         case EbtStruct:
583         case EbtBlock:
584         case EbtVoid:
585             return 0;
586         default:
587             break;
588         }
589 
590         if (type.isVector()) {
591             int offset = type.getVectorSize() - 2;
592             switch (type.getBasicType()) {
593             case EbtFloat:      return GL_FLOAT_VEC2                  + offset;
594             case EbtDouble:     return GL_DOUBLE_VEC2                 + offset;
595 #ifdef AMD_EXTENSIONS
596             case EbtFloat16:    return GL_FLOAT16_VEC2_NV             + offset;
597 #endif
598             case EbtInt:        return GL_INT_VEC2                    + offset;
599             case EbtUint:       return GL_UNSIGNED_INT_VEC2           + offset;
600             case EbtInt64:      return GL_INT64_ARB                   + offset;
601             case EbtUint64:     return GL_UNSIGNED_INT64_ARB          + offset;
602             case EbtBool:       return GL_BOOL_VEC2                   + offset;
603             case EbtAtomicUint: return GL_UNSIGNED_INT_ATOMIC_COUNTER + offset;
604             default:            return 0;
605             }
606         }
607         if (type.isMatrix()) {
608             switch (type.getBasicType()) {
609             case EbtFloat:
610                 switch (type.getMatrixCols()) {
611                 case 2:
612                     switch (type.getMatrixRows()) {
613                     case 2:    return GL_FLOAT_MAT2;
614                     case 3:    return GL_FLOAT_MAT2x3;
615                     case 4:    return GL_FLOAT_MAT2x4;
616                     default:   return 0;
617                     }
618                 case 3:
619                     switch (type.getMatrixRows()) {
620                     case 2:    return GL_FLOAT_MAT3x2;
621                     case 3:    return GL_FLOAT_MAT3;
622                     case 4:    return GL_FLOAT_MAT3x4;
623                     default:   return 0;
624                     }
625                 case 4:
626                     switch (type.getMatrixRows()) {
627                     case 2:    return GL_FLOAT_MAT4x2;
628                     case 3:    return GL_FLOAT_MAT4x3;
629                     case 4:    return GL_FLOAT_MAT4;
630                     default:   return 0;
631                     }
632                 }
633             case EbtDouble:
634                 switch (type.getMatrixCols()) {
635                 case 2:
636                     switch (type.getMatrixRows()) {
637                     case 2:    return GL_DOUBLE_MAT2;
638                     case 3:    return GL_DOUBLE_MAT2x3;
639                     case 4:    return GL_DOUBLE_MAT2x4;
640                     default:   return 0;
641                     }
642                 case 3:
643                     switch (type.getMatrixRows()) {
644                     case 2:    return GL_DOUBLE_MAT3x2;
645                     case 3:    return GL_DOUBLE_MAT3;
646                     case 4:    return GL_DOUBLE_MAT3x4;
647                     default:   return 0;
648                     }
649                 case 4:
650                     switch (type.getMatrixRows()) {
651                     case 2:    return GL_DOUBLE_MAT4x2;
652                     case 3:    return GL_DOUBLE_MAT4x3;
653                     case 4:    return GL_DOUBLE_MAT4;
654                     default:   return 0;
655                     }
656                 }
657 #ifdef AMD_EXTENSIONS
658             case EbtFloat16:
659                 switch (type.getMatrixCols()) {
660                 case 2:
661                     switch (type.getMatrixRows()) {
662                     case 2:    return GL_FLOAT16_MAT2_AMD;
663                     case 3:    return GL_FLOAT16_MAT2x3_AMD;
664                     case 4:    return GL_FLOAT16_MAT2x4_AMD;
665                     default:   return 0;
666                     }
667                 case 3:
668                     switch (type.getMatrixRows()) {
669                     case 2:    return GL_FLOAT16_MAT3x2_AMD;
670                     case 3:    return GL_FLOAT16_MAT3_AMD;
671                     case 4:    return GL_FLOAT16_MAT3x4_AMD;
672                     default:   return 0;
673                     }
674                 case 4:
675                     switch (type.getMatrixRows()) {
676                     case 2:    return GL_FLOAT16_MAT4x2_AMD;
677                     case 3:    return GL_FLOAT16_MAT4x3_AMD;
678                     case 4:    return GL_FLOAT16_MAT4_AMD;
679                     default:   return 0;
680                     }
681                 }
682 #endif
683             default:
684                 return 0;
685             }
686         }
687         if (type.getVectorSize() == 1) {
688             switch (type.getBasicType()) {
689             case EbtFloat:      return GL_FLOAT;
690             case EbtDouble:     return GL_DOUBLE;
691 #ifdef AMD_EXTENSIONS
692             case EbtFloat16:    return GL_FLOAT16_NV;
693 #endif
694             case EbtInt:        return GL_INT;
695             case EbtUint:       return GL_UNSIGNED_INT;
696             case EbtInt64:      return GL_INT64_ARB;
697             case EbtUint64:     return GL_UNSIGNED_INT64_ARB;
698             case EbtBool:       return GL_BOOL;
699             case EbtAtomicUint: return GL_UNSIGNED_INT_ATOMIC_COUNTER;
700             default:            return 0;
701             }
702         }
703 
704         return 0;
705     }
706 
mapToGlArraySize(const TType & type)707     int mapToGlArraySize(const TType& type)
708     {
709         return type.isArray() ? type.getOuterArraySize() : 1;
710     }
711 
712     TReflection& reflection;
713     std::set<const TIntermNode*> processedDerefs;
714 
715 protected:
716     TReflectionTraverser(TReflectionTraverser&);
717     TReflectionTraverser& operator=(TReflectionTraverser&);
718 };
719 
720 //
721 // Implement the traversal functions of interest.
722 //
723 
724 // To catch dereferenced aggregates that must be reflected.
725 // This catches them at the highest level possible in the tree.
visitBinary(TVisit,TIntermBinary * node)726 bool TReflectionTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
727 {
728     switch (node->getOp()) {
729     case EOpIndexDirect:
730     case EOpIndexIndirect:
731     case EOpIndexDirectStruct:
732         addDereferencedUniform(node);
733         break;
734     default:
735         break;
736     }
737 
738     // still need to visit everything below, which could contain sub-expressions
739     // containing different uniforms
740     return true;
741 }
742 
743 // To reflect non-dereferenced objects.
visitSymbol(TIntermSymbol * base)744 void TReflectionTraverser::visitSymbol(TIntermSymbol* base)
745 {
746     if (base->getQualifier().storage == EvqUniform)
747         addUniform(*base);
748 
749     if (intermediate.getStage() == EShLangVertex && base->getQualifier().isPipeInput())
750         addAttribute(*base);
751 }
752 
753 //
754 // Implement TReflection methods.
755 //
756 
757 // Track any required attribute reflection, such as compute shader numthreads.
758 //
buildAttributeReflection(EShLanguage stage,const TIntermediate & intermediate)759 void TReflection::buildAttributeReflection(EShLanguage stage, const TIntermediate& intermediate)
760 {
761     if (stage == EShLangCompute) {
762         // Remember thread dimensions
763         for (int dim=0; dim<3; ++dim)
764             localSize[dim] = intermediate.getLocalSize(dim);
765     }
766 }
767 
768 // build counter block index associations for buffers
buildCounterIndices(const TIntermediate & intermediate)769 void TReflection::buildCounterIndices(const TIntermediate& intermediate)
770 {
771     // search for ones that have counters
772     for (int i = 0; i < int(indexToUniformBlock.size()); ++i) {
773         const TString counterName(intermediate.addCounterBufferName(indexToUniformBlock[i].name));
774         const int index = getIndex(counterName);
775 
776         if (index >= 0)
777             indexToUniformBlock[i].counterIndex = index;
778     }
779 }
780 
781 // build Shader Stages mask for all uniforms
buildUniformStageMask(const TIntermediate & intermediate)782 void TReflection::buildUniformStageMask(const TIntermediate& intermediate)
783 {
784     for (int i = 0; i < int(indexToUniform.size()); ++i) {
785         indexToUniform[i].stages = static_cast<EShLanguageMask>(indexToUniform[i].stages | 1 << intermediate.getStage());
786     }
787 }
788 
789 // Merge live symbols from 'intermediate' into the existing reflection database.
790 //
791 // Returns false if the input is too malformed to do this.
addStage(EShLanguage stage,const TIntermediate & intermediate)792 bool TReflection::addStage(EShLanguage stage, const TIntermediate& intermediate)
793 {
794     if (intermediate.getTreeRoot() == nullptr ||
795         intermediate.getNumEntryPoints() != 1 ||
796         intermediate.isRecursive())
797         return false;
798 
799     buildAttributeReflection(stage, intermediate);
800 
801     TReflectionTraverser it(intermediate, *this);
802 
803     // put the entry point on the list of functions to process
804     it.pushFunction(intermediate.getEntryPointMangledName().c_str());
805 
806     // process all the functions
807     while (! it.functions.empty()) {
808         TIntermNode* function = it.functions.back();
809         it.functions.pop_back();
810         function->traverse(&it);
811     }
812 
813     buildCounterIndices(intermediate);
814     buildUniformStageMask(intermediate);
815 
816     return true;
817 }
818 
dump()819 void TReflection::dump()
820 {
821     printf("Uniform reflection:\n");
822     for (size_t i = 0; i < indexToUniform.size(); ++i)
823         indexToUniform[i].dump();
824     printf("\n");
825 
826     printf("Uniform block reflection:\n");
827     for (size_t i = 0; i < indexToUniformBlock.size(); ++i)
828         indexToUniformBlock[i].dump();
829     printf("\n");
830 
831     printf("Vertex attribute reflection:\n");
832     for (size_t i = 0; i < indexToAttribute.size(); ++i)
833         indexToAttribute[i].dump();
834     printf("\n");
835 
836     if (getLocalSize(0) > 1) {
837         static const char* axis[] = { "X", "Y", "Z" };
838 
839         for (int dim=0; dim<3; ++dim)
840             if (getLocalSize(dim) > 1)
841                 printf("Local size %s: %d\n", axis[dim], getLocalSize(dim));
842 
843         printf("\n");
844     }
845 
846     // printf("Live names\n");
847     // for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)
848     //    printf("%s: %d\n", it->first.c_str(), it->second);
849     // printf("\n");
850 }
851 
852 } // end namespace glslang
853