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