1 //
2 // Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
3 // Copyright (C) 2012-2016 LunarG, Inc.
4 // Copyright (C) 2015-2016 Google, Inc.
5 // Copyright (C) 2017 ARM Limited.
6 // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
7 //
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions
12 // are met:
13 //
14 // Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // Redistributions in binary form must reproduce the above
18 // copyright notice, this list of conditions and the following
19 // disclaimer in the documentation and/or other materials provided
20 // with the distribution.
21 //
22 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
23 // contributors may be used to endorse or promote products derived
24 // from this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 // POSSIBILITY OF SUCH DAMAGE.
38 //
39
40 #ifndef _TYPES_INCLUDED
41 #define _TYPES_INCLUDED
42
43 #include "../Include/Common.h"
44 #include "../Include/BaseTypes.h"
45 #include "../Public/ShaderLang.h"
46 #include "arrays.h"
47 #include "SpirvIntrinsics.h"
48
49 #include <algorithm>
50
51 namespace glslang {
52
53 class TIntermAggregate;
54
55 const int GlslangMaxTypeLength = 200; // TODO: need to print block/struct one member per line, so this can stay bounded
56
57 const char* const AnonymousPrefix = "anon@"; // for something like a block whose members can be directly accessed
IsAnonymous(const TString & name)58 inline bool IsAnonymous(const TString& name)
59 {
60 return name.compare(0, 5, AnonymousPrefix) == 0;
61 }
62
63 //
64 // Details within a sampler type
65 //
66 enum TSamplerDim {
67 EsdNone,
68 Esd1D,
69 Esd2D,
70 Esd3D,
71 EsdCube,
72 EsdRect,
73 EsdBuffer,
74 EsdSubpass, // goes only with non-sampled image (image is true)
75 EsdAttachmentEXT,
76 EsdNumDims
77 };
78
79 struct TSampler { // misnomer now; includes images, textures without sampler, and textures with sampler
80 TBasicType type : 8; // type returned by sampler
81 TSamplerDim dim : 8;
82 bool arrayed : 1;
83 bool shadow : 1;
84 bool ms : 1;
85 bool image : 1; // image, combined should be false
86 bool combined : 1; // true means texture is combined with a sampler, false means texture with no sampler
87 bool sampler : 1; // true means a pure sampler, other fields should be clear()
88
89 unsigned int vectorSize : 3; // vector return type size.
90 // Some languages support structures as sample results. Storing the whole structure in the
91 // TSampler is too large, so there is an index to a separate table.
92 static const unsigned structReturnIndexBits = 4; // number of index bits to use.
93 static const unsigned structReturnSlots = (1<<structReturnIndexBits)-1; // number of valid values
94 static const unsigned noReturnStruct = structReturnSlots; // value if no return struct type.
95 // Index into a language specific table of texture return structures.
96 unsigned int structReturnIndex : structReturnIndexBits;
97
98 bool external : 1; // GL_OES_EGL_image_external
99 bool yuv : 1; // GL_EXT_YUV_target
100
101 #ifdef ENABLE_HLSL
getVectorSizeTSampler102 unsigned int getVectorSize() const { return vectorSize; }
clearReturnStructTSampler103 void clearReturnStruct() { structReturnIndex = noReturnStruct; }
hasReturnStructTSampler104 bool hasReturnStruct() const { return structReturnIndex != noReturnStruct; }
getStructReturnIndexTSampler105 unsigned getStructReturnIndex() const { return structReturnIndex; }
106 #endif
107
is1DTSampler108 bool is1D() const { return dim == Esd1D; }
is2DTSampler109 bool is2D() const { return dim == Esd2D; }
isBufferTSampler110 bool isBuffer() const { return dim == EsdBuffer; }
isRectTSampler111 bool isRect() const { return dim == EsdRect; }
isSubpassTSampler112 bool isSubpass() const { return dim == EsdSubpass; }
isAttachmentEXTTSampler113 bool isAttachmentEXT() const { return dim == EsdAttachmentEXT; }
isCombinedTSampler114 bool isCombined() const { return combined; }
isImageTSampler115 bool isImage() const { return image && !isSubpass() && !isAttachmentEXT();}
isImageClassTSampler116 bool isImageClass() const { return image; }
isMultiSampleTSampler117 bool isMultiSample() const { return ms; }
isExternalTSampler118 bool isExternal() const { return external; }
setExternalTSampler119 void setExternal(bool e) { external = e; }
isYuvTSampler120 bool isYuv() const { return yuv; }
isTextureTSampler121 bool isTexture() const { return !sampler && !image; }
isPureSamplerTSampler122 bool isPureSampler() const { return sampler; }
123
setCombinedTSampler124 void setCombined(bool c) { combined = c; }
setBasicTypeTSampler125 void setBasicType(TBasicType t) { type = t; }
getBasicTypeTSampler126 TBasicType getBasicType() const { return type; }
isShadowTSampler127 bool isShadow() const { return shadow; }
isArrayedTSampler128 bool isArrayed() const { return arrayed; }
129
clearTSampler130 void clear()
131 {
132 type = EbtVoid;
133 dim = EsdNone;
134 arrayed = false;
135 shadow = false;
136 ms = false;
137 image = false;
138 combined = false;
139 sampler = false;
140 external = false;
141 yuv = false;
142
143 #ifdef ENABLE_HLSL
144 clearReturnStruct();
145 // by default, returns a single vec4;
146 vectorSize = 4;
147 #endif
148 }
149
150 // make a combined sampler and texture
151 void set(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
152 {
153 clear();
154 type = t;
155 dim = d;
156 arrayed = a;
157 shadow = s;
158 ms = m;
159 combined = true;
160 }
161
162 // make an image
163 void setImage(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
164 {
165 clear();
166 type = t;
167 dim = d;
168 arrayed = a;
169 shadow = s;
170 ms = m;
171 image = true;
172 }
173
174 // make a texture with no sampler
175 void setTexture(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
176 {
177 clear();
178 type = t;
179 dim = d;
180 arrayed = a;
181 shadow = s;
182 ms = m;
183 }
184
185 // make a pure sampler, no texture, no image, nothing combined, the 'sampler' keyword
setPureSamplerTSampler186 void setPureSampler(bool s)
187 {
188 clear();
189 sampler = true;
190 shadow = s;
191 }
192
193 // make a subpass input attachment
194 void setSubpass(TBasicType t, bool m = false)
195 {
196 clear();
197 type = t;
198 image = true;
199 dim = EsdSubpass;
200 ms = m;
201 }
202
203 // make an AttachmentEXT
setAttachmentEXTTSampler204 void setAttachmentEXT(TBasicType t)
205 {
206 clear();
207 type = t;
208 image = true;
209 dim = EsdAttachmentEXT;
210 }
211
212 bool operator==(const TSampler& right) const
213 {
214 return type == right.type &&
215 dim == right.dim &&
216 arrayed == right.arrayed &&
217 shadow == right.shadow &&
218 isMultiSample() == right.isMultiSample() &&
219 isImageClass() == right.isImageClass() &&
220 isCombined() == right.isCombined() &&
221 isPureSampler() == right.isPureSampler() &&
222 isExternal() == right.isExternal() &&
223 isYuv() == right.isYuv()
224 #ifdef ENABLE_HLSL
225 && getVectorSize() == right.getVectorSize() &&
226 getStructReturnIndex() == right.getStructReturnIndex()
227 #endif
228 ;
229 }
230
231 bool operator!=(const TSampler& right) const
232 {
233 return ! operator==(right);
234 }
235
getStringTSampler236 TString getString() const
237 {
238 TString s;
239
240 if (isPureSampler()) {
241 s.append("sampler");
242 return s;
243 }
244
245 switch (type) {
246 case EbtInt: s.append("i"); break;
247 case EbtUint: s.append("u"); break;
248 case EbtFloat16: s.append("f16"); break;
249 case EbtInt8: s.append("i8"); break;
250 case EbtUint16: s.append("u8"); break;
251 case EbtInt16: s.append("i16"); break;
252 case EbtUint8: s.append("u16"); break;
253 case EbtInt64: s.append("i64"); break;
254 case EbtUint64: s.append("u64"); break;
255 default: break;
256 }
257 if (isImageClass()) {
258 if (isAttachmentEXT())
259 s.append("attachmentEXT");
260 else if (isSubpass())
261 s.append("subpass");
262 else
263 s.append("image");
264 } else if (isCombined()) {
265 s.append("sampler");
266 } else {
267 s.append("texture");
268 }
269 if (isExternal()) {
270 s.append("ExternalOES");
271 return s;
272 }
273 if (isYuv()) {
274 return "__" + s + "External2DY2YEXT";
275 }
276 switch (dim) {
277 case Esd2D: s.append("2D"); break;
278 case Esd3D: s.append("3D"); break;
279 case EsdCube: s.append("Cube"); break;
280 case Esd1D: s.append("1D"); break;
281 case EsdRect: s.append("2DRect"); break;
282 case EsdBuffer: s.append("Buffer"); break;
283 case EsdSubpass: s.append("Input"); break;
284 case EsdAttachmentEXT: s.append(""); break;
285 default: break; // some compilers want this
286 }
287 if (isMultiSample())
288 s.append("MS");
289 if (arrayed)
290 s.append("Array");
291 if (shadow)
292 s.append("Shadow");
293
294 return s;
295 }
296 };
297
298 //
299 // Need to have association of line numbers to types in a list for building structs.
300 //
301 class TType;
302 struct TTypeLoc {
303 TType* type;
304 TSourceLoc loc;
305 };
306 typedef TVector<TTypeLoc> TTypeList;
307
308 typedef TVector<TString*> TIdentifierList;
309
310 //
311 // Following are a series of helper enums for managing layouts and qualifiers,
312 // used for TPublicType, TType, others.
313 //
314
315 enum TLayoutPacking {
316 ElpNone,
317 ElpShared, // default, but different than saying nothing
318 ElpStd140,
319 ElpStd430,
320 ElpPacked,
321 ElpScalar,
322 ElpCount // If expanding, see bitfield width below
323 };
324
325 enum TLayoutMatrix {
326 ElmNone,
327 ElmRowMajor,
328 ElmColumnMajor, // default, but different than saying nothing
329 ElmCount // If expanding, see bitfield width below
330 };
331
332 // Union of geometry shader and tessellation shader geometry types.
333 // They don't go into TType, but rather have current state per shader or
334 // active parser type (TPublicType).
335 enum TLayoutGeometry {
336 ElgNone,
337 ElgPoints,
338 ElgLines,
339 ElgLinesAdjacency,
340 ElgLineStrip,
341 ElgTriangles,
342 ElgTrianglesAdjacency,
343 ElgTriangleStrip,
344 ElgQuads,
345 ElgIsolines,
346 };
347
348 enum TVertexSpacing {
349 EvsNone,
350 EvsEqual,
351 EvsFractionalEven,
352 EvsFractionalOdd
353 };
354
355 enum TVertexOrder {
356 EvoNone,
357 EvoCw,
358 EvoCcw
359 };
360
361 // Note: order matters, as type of format is done by comparison.
362 enum TLayoutFormat {
363 ElfNone,
364
365 // Float image
366 ElfRgba32f,
367 ElfRgba16f,
368 ElfR32f,
369 ElfRgba8,
370 ElfRgba8Snorm,
371
372 ElfEsFloatGuard, // to help with comparisons
373
374 ElfRg32f,
375 ElfRg16f,
376 ElfR11fG11fB10f,
377 ElfR16f,
378 ElfRgba16,
379 ElfRgb10A2,
380 ElfRg16,
381 ElfRg8,
382 ElfR16,
383 ElfR8,
384 ElfRgba16Snorm,
385 ElfRg16Snorm,
386 ElfRg8Snorm,
387 ElfR16Snorm,
388 ElfR8Snorm,
389
390 ElfFloatGuard, // to help with comparisons
391
392 // Int image
393 ElfRgba32i,
394 ElfRgba16i,
395 ElfRgba8i,
396 ElfR32i,
397
398 ElfEsIntGuard, // to help with comparisons
399
400 ElfRg32i,
401 ElfRg16i,
402 ElfRg8i,
403 ElfR16i,
404 ElfR8i,
405 ElfR64i,
406
407 ElfIntGuard, // to help with comparisons
408
409 // Uint image
410 ElfRgba32ui,
411 ElfRgba16ui,
412 ElfRgba8ui,
413 ElfR32ui,
414
415 ElfEsUintGuard, // to help with comparisons
416
417 ElfRg32ui,
418 ElfRg16ui,
419 ElfRgb10a2ui,
420 ElfRg8ui,
421 ElfR16ui,
422 ElfR8ui,
423 ElfR64ui,
424 ElfExtSizeGuard, // to help with comparisons
425 ElfSize1x8,
426 ElfSize1x16,
427 ElfSize1x32,
428 ElfSize2x32,
429 ElfSize4x32,
430
431 ElfCount
432 };
433
434 enum TLayoutDepth {
435 EldNone,
436 EldAny,
437 EldGreater,
438 EldLess,
439 EldUnchanged,
440
441 EldCount
442 };
443
444 enum TLayoutStencil {
445 ElsNone,
446 ElsRefUnchangedFrontAMD,
447 ElsRefGreaterFrontAMD,
448 ElsRefLessFrontAMD,
449 ElsRefUnchangedBackAMD,
450 ElsRefGreaterBackAMD,
451 ElsRefLessBackAMD,
452
453 ElsCount
454 };
455
456 enum TBlendEquationShift {
457 // No 'EBlendNone':
458 // These are used as bit-shift amounts. A mask of such shifts will have type 'int',
459 // and in that space, 0 means no bits set, or none. In this enum, 0 means (1 << 0), a bit is set.
460 EBlendMultiply,
461 EBlendScreen,
462 EBlendOverlay,
463 EBlendDarken,
464 EBlendLighten,
465 EBlendColordodge,
466 EBlendColorburn,
467 EBlendHardlight,
468 EBlendSoftlight,
469 EBlendDifference,
470 EBlendExclusion,
471 EBlendHslHue,
472 EBlendHslSaturation,
473 EBlendHslColor,
474 EBlendHslLuminosity,
475 EBlendAllEquations,
476
477 EBlendCount
478 };
479
480 enum TInterlockOrdering {
481 EioNone,
482 EioPixelInterlockOrdered,
483 EioPixelInterlockUnordered,
484 EioSampleInterlockOrdered,
485 EioSampleInterlockUnordered,
486 EioShadingRateInterlockOrdered,
487 EioShadingRateInterlockUnordered,
488
489 EioCount,
490 };
491
492 enum TShaderInterface
493 {
494 // Includes both uniform blocks and buffer blocks
495 EsiUniform = 0,
496 EsiInput,
497 EsiOutput,
498 EsiNone,
499
500 EsiCount
501 };
502
503 class TQualifier {
504 public:
505 static const int layoutNotSet = -1;
506
clear()507 void clear()
508 {
509 precision = EpqNone;
510 invariant = false;
511 makeTemporary();
512 declaredBuiltIn = EbvNone;
513 noContraction = false;
514 nullInit = false;
515 spirvByReference = false;
516 spirvLiteral = false;
517 defaultBlock = false;
518 }
519
520 // drop qualifiers that don't belong in a temporary variable
makeTemporary()521 void makeTemporary()
522 {
523 semanticName = nullptr;
524 storage = EvqTemporary;
525 builtIn = EbvNone;
526 clearInterstage();
527 clearMemory();
528 specConstant = false;
529 nonUniform = false;
530 nullInit = false;
531 defaultBlock = false;
532 clearLayout();
533 spirvStorageClass = -1;
534 spirvDecorate = nullptr;
535 spirvByReference = false;
536 spirvLiteral = false;
537 }
538
clearInterstage()539 void clearInterstage()
540 {
541 clearInterpolation();
542 patch = false;
543 sample = false;
544 }
545
clearInterpolation()546 void clearInterpolation()
547 {
548 centroid = false;
549 smooth = false;
550 flat = false;
551 nopersp = false;
552 explicitInterp = false;
553 pervertexNV = false;
554 perPrimitiveNV = false;
555 perViewNV = false;
556 perTaskNV = false;
557 pervertexEXT = false;
558 }
559
clearMemory()560 void clearMemory()
561 {
562 coherent = false;
563 devicecoherent = false;
564 queuefamilycoherent = false;
565 workgroupcoherent = false;
566 subgroupcoherent = false;
567 shadercallcoherent = false;
568 nonprivate = false;
569 volatil = false;
570 restrict = false;
571 readonly = false;
572 writeonly = false;
573 }
574
575 const char* semanticName;
576 TStorageQualifier storage : 6;
577 TBuiltInVariable builtIn : 9;
578 TBuiltInVariable declaredBuiltIn : 9;
579 static_assert(EbvLast < 256, "need to increase size of TBuiltInVariable bitfields!");
580 TPrecisionQualifier precision : 3;
581 bool invariant : 1; // require canonical treatment for cross-shader invariance
582 bool centroid : 1;
583 bool smooth : 1;
584 bool flat : 1;
585 // having a constant_id is not sufficient: expressions have no id, but are still specConstant
586 bool specConstant : 1;
587 bool nonUniform : 1;
588 bool explicitOffset : 1;
589 bool defaultBlock : 1; // default blocks with matching names have structures merged when linking
590
591 bool noContraction: 1; // prevent contraction and reassociation, e.g., for 'precise' keyword, and expressions it affects
592 bool nopersp : 1;
593 bool explicitInterp : 1;
594 bool pervertexNV : 1;
595 bool pervertexEXT : 1;
596 bool perPrimitiveNV : 1;
597 bool perViewNV : 1;
598 bool perTaskNV : 1;
599 bool patch : 1;
600 bool sample : 1;
601 bool restrict : 1;
602 bool readonly : 1;
603 bool writeonly : 1;
604 bool coherent : 1;
605 bool volatil : 1;
606 bool devicecoherent : 1;
607 bool queuefamilycoherent : 1;
608 bool workgroupcoherent : 1;
609 bool subgroupcoherent : 1;
610 bool shadercallcoherent : 1;
611 bool nonprivate : 1;
612 bool nullInit : 1;
613 bool spirvByReference : 1;
614 bool spirvLiteral : 1;
isWriteOnly()615 bool isWriteOnly() const { return writeonly; }
isReadOnly()616 bool isReadOnly() const { return readonly; }
isRestrict()617 bool isRestrict() const { return restrict; }
isCoherent()618 bool isCoherent() const { return coherent; }
isVolatile()619 bool isVolatile() const { return volatil; }
isSample()620 bool isSample() const { return sample; }
isMemory()621 bool isMemory() const
622 {
623 return shadercallcoherent || subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || restrict || readonly || writeonly || nonprivate;
624 }
isMemoryQualifierImageAndSSBOOnly()625 bool isMemoryQualifierImageAndSSBOOnly() const
626 {
627 return shadercallcoherent || subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || restrict || readonly || writeonly;
628 }
bufferReferenceNeedsVulkanMemoryModel()629 bool bufferReferenceNeedsVulkanMemoryModel() const
630 {
631 // include qualifiers that map to load/store availability/visibility/nonprivate memory access operands
632 return subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || nonprivate;
633 }
isInterpolation()634 bool isInterpolation() const
635 {
636 return flat || smooth || nopersp || explicitInterp;
637 }
isExplicitInterpolation()638 bool isExplicitInterpolation() const
639 {
640 return explicitInterp;
641 }
isAuxiliary()642 bool isAuxiliary() const
643 {
644 return centroid || patch || sample || pervertexNV || pervertexEXT;
645 }
isPatch()646 bool isPatch() const { return patch; }
isNoContraction()647 bool isNoContraction() const { return noContraction; }
setNoContraction()648 void setNoContraction() { noContraction = true; }
isPervertexNV()649 bool isPervertexNV() const { return pervertexNV; }
isPervertexEXT()650 bool isPervertexEXT() const { return pervertexEXT; }
setNullInit()651 void setNullInit() { nullInit = true; }
isNullInit()652 bool isNullInit() const { return nullInit; }
setSpirvByReference()653 void setSpirvByReference() { spirvByReference = true; }
isSpirvByReference()654 bool isSpirvByReference() const { return spirvByReference; }
setSpirvLiteral()655 void setSpirvLiteral() { spirvLiteral = true; }
isSpirvLiteral()656 bool isSpirvLiteral() const { return spirvLiteral; }
657
isPipeInput()658 bool isPipeInput() const
659 {
660 switch (storage) {
661 case EvqVaryingIn:
662 case EvqFragCoord:
663 case EvqPointCoord:
664 case EvqFace:
665 case EvqVertexId:
666 case EvqInstanceId:
667 return true;
668 default:
669 return false;
670 }
671 }
672
isPipeOutput()673 bool isPipeOutput() const
674 {
675 switch (storage) {
676 case EvqPosition:
677 case EvqPointSize:
678 case EvqClipVertex:
679 case EvqVaryingOut:
680 case EvqFragColor:
681 case EvqFragDepth:
682 case EvqFragStencil:
683 return true;
684 default:
685 return false;
686 }
687 }
688
isParamInput()689 bool isParamInput() const
690 {
691 switch (storage) {
692 case EvqIn:
693 case EvqInOut:
694 case EvqConstReadOnly:
695 return true;
696 default:
697 return false;
698 }
699 }
700
isParamOutput()701 bool isParamOutput() const
702 {
703 switch (storage) {
704 case EvqOut:
705 case EvqInOut:
706 return true;
707 default:
708 return false;
709 }
710 }
711
isUniformOrBuffer()712 bool isUniformOrBuffer() const
713 {
714 switch (storage) {
715 case EvqUniform:
716 case EvqBuffer:
717 return true;
718 default:
719 return false;
720 }
721 }
722
isUniform()723 bool isUniform() const
724 {
725 switch (storage) {
726 case EvqUniform:
727 return true;
728 default:
729 return false;
730 }
731 }
732
isIo()733 bool isIo() const
734 {
735 switch (storage) {
736 case EvqUniform:
737 case EvqBuffer:
738 case EvqVaryingIn:
739 case EvqFragCoord:
740 case EvqPointCoord:
741 case EvqFace:
742 case EvqVertexId:
743 case EvqInstanceId:
744 case EvqPosition:
745 case EvqPointSize:
746 case EvqClipVertex:
747 case EvqVaryingOut:
748 case EvqFragColor:
749 case EvqFragDepth:
750 case EvqFragStencil:
751 return true;
752 default:
753 return false;
754 }
755 }
756
757 // non-built-in symbols that might link between compilation units
isLinkable()758 bool isLinkable() const
759 {
760 switch (storage) {
761 case EvqGlobal:
762 case EvqVaryingIn:
763 case EvqVaryingOut:
764 case EvqUniform:
765 case EvqBuffer:
766 case EvqShared:
767 return true;
768 default:
769 return false;
770 }
771 }
772
getBlockStorage()773 TBlockStorageClass getBlockStorage() const {
774 if (storage == EvqUniform && !isPushConstant()) {
775 return EbsUniform;
776 }
777 else if (storage == EvqUniform) {
778 return EbsPushConstant;
779 }
780 else if (storage == EvqBuffer) {
781 return EbsStorageBuffer;
782 }
783 return EbsNone;
784 }
785
setBlockStorage(TBlockStorageClass newBacking)786 void setBlockStorage(TBlockStorageClass newBacking) {
787 layoutPushConstant = (newBacking == EbsPushConstant);
788 switch (newBacking) {
789 case EbsUniform :
790 if (layoutPacking == ElpStd430) {
791 // std430 would not be valid
792 layoutPacking = ElpStd140;
793 }
794 storage = EvqUniform;
795 break;
796 case EbsStorageBuffer :
797 storage = EvqBuffer;
798 break;
799 case EbsPushConstant :
800 storage = EvqUniform;
801 layoutSet = TQualifier::layoutSetEnd;
802 layoutBinding = TQualifier::layoutBindingEnd;
803 break;
804 default:
805 break;
806 }
807 }
808
isPerPrimitive()809 bool isPerPrimitive() const { return perPrimitiveNV; }
isPerView()810 bool isPerView() const { return perViewNV; }
isTaskMemory()811 bool isTaskMemory() const { return perTaskNV; }
isTaskPayload()812 bool isTaskPayload() const { return storage == EvqtaskPayloadSharedEXT; }
isAnyPayload()813 bool isAnyPayload() const {
814 return storage == EvqPayload || storage == EvqPayloadIn;
815 }
isAnyCallable()816 bool isAnyCallable() const {
817 return storage == EvqCallableData || storage == EvqCallableDataIn;
818 }
isHitObjectAttrNV()819 bool isHitObjectAttrNV() const {
820 return storage == EvqHitObjectAttrNV;
821 }
822
823 // True if this type of IO is supposed to be arrayed with extra level for per-vertex data
isArrayedIo(EShLanguage language)824 bool isArrayedIo(EShLanguage language) const
825 {
826 switch (language) {
827 case EShLangGeometry:
828 return isPipeInput();
829 case EShLangTessControl:
830 return ! patch && (isPipeInput() || isPipeOutput());
831 case EShLangTessEvaluation:
832 return ! patch && isPipeInput();
833 case EShLangFragment:
834 return (pervertexNV || pervertexEXT) && isPipeInput();
835 case EShLangMesh:
836 return ! perTaskNV && isPipeOutput();
837
838 default:
839 return false;
840 }
841 }
842
843 // Implementing an embedded layout-qualifier class here, since C++ can't have a real class bitfield
clearLayout()844 void clearLayout() // all layout
845 {
846 clearUniformLayout();
847
848 layoutPushConstant = false;
849 layoutBufferReference = false;
850 layoutPassthrough = false;
851 layoutViewportRelative = false;
852 // -2048 as the default value indicating layoutSecondaryViewportRelative is not set
853 layoutSecondaryViewportRelativeOffset = -2048;
854 layoutShaderRecord = false;
855 layoutHitObjectShaderRecordNV = false;
856 layoutBindlessSampler = false;
857 layoutBindlessImage = false;
858 layoutBufferReferenceAlign = layoutBufferReferenceAlignEnd;
859 layoutFormat = ElfNone;
860
861 clearInterstageLayout();
862
863 layoutSpecConstantId = layoutSpecConstantIdEnd;
864 }
clearInterstageLayout()865 void clearInterstageLayout()
866 {
867 layoutLocation = layoutLocationEnd;
868 layoutComponent = layoutComponentEnd;
869 layoutIndex = layoutIndexEnd;
870 clearStreamLayout();
871 clearXfbLayout();
872 }
873
clearStreamLayout()874 void clearStreamLayout()
875 {
876 layoutStream = layoutStreamEnd;
877 }
clearXfbLayout()878 void clearXfbLayout()
879 {
880 layoutXfbBuffer = layoutXfbBufferEnd;
881 layoutXfbStride = layoutXfbStrideEnd;
882 layoutXfbOffset = layoutXfbOffsetEnd;
883 }
884
hasNonXfbLayout()885 bool hasNonXfbLayout() const
886 {
887 return hasUniformLayout() ||
888 hasAnyLocation() ||
889 hasStream() ||
890 hasFormat() ||
891 isShaderRecord() ||
892 isPushConstant() ||
893 hasBufferReference();
894 }
hasLayout()895 bool hasLayout() const
896 {
897 return hasNonXfbLayout() ||
898 hasXfb();
899 }
900
901 TLayoutMatrix layoutMatrix : 3;
902 TLayoutPacking layoutPacking : 4;
903 int layoutOffset;
904 int layoutAlign;
905
906 unsigned int layoutLocation : 12;
907 static const unsigned int layoutLocationEnd = 0xFFF;
908
909 unsigned int layoutComponent : 3;
910 static const unsigned int layoutComponentEnd = 4;
911
912 unsigned int layoutSet : 7;
913 static const unsigned int layoutSetEnd = 0x3F;
914
915 unsigned int layoutBinding : 16;
916 static const unsigned int layoutBindingEnd = 0xFFFF;
917
918 unsigned int layoutIndex : 8;
919 static const unsigned int layoutIndexEnd = 0xFF;
920
921 unsigned int layoutStream : 8;
922 static const unsigned int layoutStreamEnd = 0xFF;
923
924 unsigned int layoutXfbBuffer : 4;
925 static const unsigned int layoutXfbBufferEnd = 0xF;
926
927 unsigned int layoutXfbStride : 14;
928 static const unsigned int layoutXfbStrideEnd = 0x3FFF;
929
930 unsigned int layoutXfbOffset : 13;
931 static const unsigned int layoutXfbOffsetEnd = 0x1FFF;
932
933 unsigned int layoutAttachment : 8; // for input_attachment_index
934 static const unsigned int layoutAttachmentEnd = 0XFF;
935
936 unsigned int layoutSpecConstantId : 11;
937 static const unsigned int layoutSpecConstantIdEnd = 0x7FF;
938
939 // stored as log2 of the actual alignment value
940 unsigned int layoutBufferReferenceAlign : 6;
941 static const unsigned int layoutBufferReferenceAlignEnd = 0x3F;
942
943 TLayoutFormat layoutFormat : 8;
944
945 bool layoutPushConstant;
946 bool layoutBufferReference;
947 bool layoutPassthrough;
948 bool layoutViewportRelative;
949 int layoutSecondaryViewportRelativeOffset;
950 bool layoutShaderRecord;
951 bool layoutHitObjectShaderRecordNV;
952
953 // GL_EXT_spirv_intrinsics
954 int spirvStorageClass;
955 TSpirvDecorate* spirvDecorate;
956
957 bool layoutBindlessSampler;
958 bool layoutBindlessImage;
959
hasUniformLayout()960 bool hasUniformLayout() const
961 {
962 return hasMatrix() ||
963 hasPacking() ||
964 hasOffset() ||
965 hasBinding() ||
966 hasSet() ||
967 hasAlign();
968 }
clearUniformLayout()969 void clearUniformLayout() // only uniform specific
970 {
971 layoutMatrix = ElmNone;
972 layoutPacking = ElpNone;
973 layoutOffset = layoutNotSet;
974 layoutAlign = layoutNotSet;
975
976 layoutSet = layoutSetEnd;
977 layoutBinding = layoutBindingEnd;
978 layoutAttachment = layoutAttachmentEnd;
979 }
980
hasMatrix()981 bool hasMatrix() const
982 {
983 return layoutMatrix != ElmNone;
984 }
hasPacking()985 bool hasPacking() const
986 {
987 return layoutPacking != ElpNone;
988 }
hasAlign()989 bool hasAlign() const
990 {
991 return layoutAlign != layoutNotSet;
992 }
hasAnyLocation()993 bool hasAnyLocation() const
994 {
995 return hasLocation() ||
996 hasComponent() ||
997 hasIndex();
998 }
hasLocation()999 bool hasLocation() const
1000 {
1001 return layoutLocation != layoutLocationEnd;
1002 }
hasSet()1003 bool hasSet() const
1004 {
1005 return layoutSet != layoutSetEnd;
1006 }
hasBinding()1007 bool hasBinding() const
1008 {
1009 return layoutBinding != layoutBindingEnd;
1010 }
hasOffset()1011 bool hasOffset() const
1012 {
1013 return layoutOffset != layoutNotSet;
1014 }
isNonPerspective()1015 bool isNonPerspective() const { return nopersp; }
hasIndex()1016 bool hasIndex() const
1017 {
1018 return layoutIndex != layoutIndexEnd;
1019 }
getIndex()1020 unsigned getIndex() const { return layoutIndex; }
hasComponent()1021 bool hasComponent() const
1022 {
1023 return layoutComponent != layoutComponentEnd;
1024 }
hasStream()1025 bool hasStream() const
1026 {
1027 return layoutStream != layoutStreamEnd;
1028 }
hasFormat()1029 bool hasFormat() const
1030 {
1031 return layoutFormat != ElfNone;
1032 }
hasXfb()1033 bool hasXfb() const
1034 {
1035 return hasXfbBuffer() ||
1036 hasXfbStride() ||
1037 hasXfbOffset();
1038 }
hasXfbBuffer()1039 bool hasXfbBuffer() const
1040 {
1041 return layoutXfbBuffer != layoutXfbBufferEnd;
1042 }
hasXfbStride()1043 bool hasXfbStride() const
1044 {
1045 return layoutXfbStride != layoutXfbStrideEnd;
1046 }
hasXfbOffset()1047 bool hasXfbOffset() const
1048 {
1049 return layoutXfbOffset != layoutXfbOffsetEnd;
1050 }
hasAttachment()1051 bool hasAttachment() const
1052 {
1053 return layoutAttachment != layoutAttachmentEnd;
1054 }
getFormat()1055 TLayoutFormat getFormat() const { return layoutFormat; }
isPushConstant()1056 bool isPushConstant() const { return layoutPushConstant; }
isShaderRecord()1057 bool isShaderRecord() const { return layoutShaderRecord; }
hasHitObjectShaderRecordNV()1058 bool hasHitObjectShaderRecordNV() const { return layoutHitObjectShaderRecordNV; }
hasBufferReference()1059 bool hasBufferReference() const { return layoutBufferReference; }
hasBufferReferenceAlign()1060 bool hasBufferReferenceAlign() const
1061 {
1062 return layoutBufferReferenceAlign != layoutBufferReferenceAlignEnd;
1063 }
isNonUniform()1064 bool isNonUniform() const
1065 {
1066 return nonUniform;
1067 }
isBindlessSampler()1068 bool isBindlessSampler() const
1069 {
1070 return layoutBindlessSampler;
1071 }
isBindlessImage()1072 bool isBindlessImage() const
1073 {
1074 return layoutBindlessImage;
1075 }
1076
1077 // GL_EXT_spirv_intrinsics
hasSpirvDecorate()1078 bool hasSpirvDecorate() const { return spirvDecorate != nullptr; }
1079 void setSpirvDecorate(int decoration, const TIntermAggregate* args = nullptr);
1080 void setSpirvDecorateId(int decoration, const TIntermAggregate* args);
1081 void setSpirvDecorateString(int decoration, const TIntermAggregate* args);
getSpirvDecorate()1082 const TSpirvDecorate& getSpirvDecorate() const { assert(spirvDecorate); return *spirvDecorate; }
getSpirvDecorate()1083 TSpirvDecorate& getSpirvDecorate() { assert(spirvDecorate); return *spirvDecorate; }
1084 TString getSpirvDecorateQualifierString() const;
1085
hasSpecConstantId()1086 bool hasSpecConstantId() const
1087 {
1088 // Not the same thing as being a specialization constant, this
1089 // is just whether or not it was declared with an ID.
1090 return layoutSpecConstantId != layoutSpecConstantIdEnd;
1091 }
isSpecConstant()1092 bool isSpecConstant() const
1093 {
1094 // True if type is a specialization constant, whether or not it
1095 // had a specialization-constant ID, and false if it is not a
1096 // true front-end constant.
1097 return specConstant;
1098 }
isFrontEndConstant()1099 bool isFrontEndConstant() const
1100 {
1101 // True if the front-end knows the final constant value.
1102 // This allows front-end constant folding.
1103 return storage == EvqConst && ! specConstant;
1104 }
isConstant()1105 bool isConstant() const
1106 {
1107 // True if is either kind of constant; specialization or regular.
1108 return isFrontEndConstant() || isSpecConstant();
1109 }
makeSpecConstant()1110 void makeSpecConstant()
1111 {
1112 storage = EvqConst;
1113 specConstant = true;
1114 }
getLayoutPackingString(TLayoutPacking packing)1115 static const char* getLayoutPackingString(TLayoutPacking packing)
1116 {
1117 switch (packing) {
1118 case ElpStd140: return "std140";
1119 case ElpPacked: return "packed";
1120 case ElpShared: return "shared";
1121 case ElpStd430: return "std430";
1122 case ElpScalar: return "scalar";
1123 default: return "none";
1124 }
1125 }
getLayoutMatrixString(TLayoutMatrix m)1126 static const char* getLayoutMatrixString(TLayoutMatrix m)
1127 {
1128 switch (m) {
1129 case ElmColumnMajor: return "column_major";
1130 case ElmRowMajor: return "row_major";
1131 default: return "none";
1132 }
1133 }
getLayoutFormatString(TLayoutFormat f)1134 static const char* getLayoutFormatString(TLayoutFormat f)
1135 {
1136 switch (f) {
1137 case ElfRgba32f: return "rgba32f";
1138 case ElfRgba16f: return "rgba16f";
1139 case ElfRg32f: return "rg32f";
1140 case ElfRg16f: return "rg16f";
1141 case ElfR11fG11fB10f: return "r11f_g11f_b10f";
1142 case ElfR32f: return "r32f";
1143 case ElfR16f: return "r16f";
1144 case ElfRgba16: return "rgba16";
1145 case ElfRgb10A2: return "rgb10_a2";
1146 case ElfRgba8: return "rgba8";
1147 case ElfRg16: return "rg16";
1148 case ElfRg8: return "rg8";
1149 case ElfR16: return "r16";
1150 case ElfR8: return "r8";
1151 case ElfRgba16Snorm: return "rgba16_snorm";
1152 case ElfRgba8Snorm: return "rgba8_snorm";
1153 case ElfRg16Snorm: return "rg16_snorm";
1154 case ElfRg8Snorm: return "rg8_snorm";
1155 case ElfR16Snorm: return "r16_snorm";
1156 case ElfR8Snorm: return "r8_snorm";
1157
1158 case ElfRgba32i: return "rgba32i";
1159 case ElfRgba16i: return "rgba16i";
1160 case ElfRgba8i: return "rgba8i";
1161 case ElfRg32i: return "rg32i";
1162 case ElfRg16i: return "rg16i";
1163 case ElfRg8i: return "rg8i";
1164 case ElfR32i: return "r32i";
1165 case ElfR16i: return "r16i";
1166 case ElfR8i: return "r8i";
1167
1168 case ElfRgba32ui: return "rgba32ui";
1169 case ElfRgba16ui: return "rgba16ui";
1170 case ElfRgba8ui: return "rgba8ui";
1171 case ElfRg32ui: return "rg32ui";
1172 case ElfRg16ui: return "rg16ui";
1173 case ElfRgb10a2ui: return "rgb10_a2ui";
1174 case ElfRg8ui: return "rg8ui";
1175 case ElfR32ui: return "r32ui";
1176 case ElfR16ui: return "r16ui";
1177 case ElfR8ui: return "r8ui";
1178 case ElfR64ui: return "r64ui";
1179 case ElfR64i: return "r64i";
1180 case ElfSize1x8: return "size1x8";
1181 case ElfSize1x16: return "size1x16";
1182 case ElfSize1x32: return "size1x32";
1183 case ElfSize2x32: return "size2x32";
1184 case ElfSize4x32: return "size4x32";
1185 default: return "none";
1186 }
1187 }
getLayoutDepthString(TLayoutDepth d)1188 static const char* getLayoutDepthString(TLayoutDepth d)
1189 {
1190 switch (d) {
1191 case EldAny: return "depth_any";
1192 case EldGreater: return "depth_greater";
1193 case EldLess: return "depth_less";
1194 case EldUnchanged: return "depth_unchanged";
1195 default: return "none";
1196 }
1197 }
getLayoutStencilString(TLayoutStencil s)1198 static const char* getLayoutStencilString(TLayoutStencil s)
1199 {
1200 switch (s) {
1201 case ElsRefUnchangedFrontAMD: return "stencil_ref_unchanged_front_amd";
1202 case ElsRefGreaterFrontAMD: return "stencil_ref_greater_front_amd";
1203 case ElsRefLessFrontAMD: return "stencil_ref_less_front_amd";
1204 case ElsRefUnchangedBackAMD: return "stencil_ref_unchanged_back_amd";
1205 case ElsRefGreaterBackAMD: return "stencil_ref_greater_back_amd";
1206 case ElsRefLessBackAMD: return "stencil_ref_less_back_amd";
1207 default: return "none";
1208 }
1209 }
getBlendEquationString(TBlendEquationShift e)1210 static const char* getBlendEquationString(TBlendEquationShift e)
1211 {
1212 switch (e) {
1213 case EBlendMultiply: return "blend_support_multiply";
1214 case EBlendScreen: return "blend_support_screen";
1215 case EBlendOverlay: return "blend_support_overlay";
1216 case EBlendDarken: return "blend_support_darken";
1217 case EBlendLighten: return "blend_support_lighten";
1218 case EBlendColordodge: return "blend_support_colordodge";
1219 case EBlendColorburn: return "blend_support_colorburn";
1220 case EBlendHardlight: return "blend_support_hardlight";
1221 case EBlendSoftlight: return "blend_support_softlight";
1222 case EBlendDifference: return "blend_support_difference";
1223 case EBlendExclusion: return "blend_support_exclusion";
1224 case EBlendHslHue: return "blend_support_hsl_hue";
1225 case EBlendHslSaturation: return "blend_support_hsl_saturation";
1226 case EBlendHslColor: return "blend_support_hsl_color";
1227 case EBlendHslLuminosity: return "blend_support_hsl_luminosity";
1228 case EBlendAllEquations: return "blend_support_all_equations";
1229 default: return "unknown";
1230 }
1231 }
getGeometryString(TLayoutGeometry geometry)1232 static const char* getGeometryString(TLayoutGeometry geometry)
1233 {
1234 switch (geometry) {
1235 case ElgPoints: return "points";
1236 case ElgLines: return "lines";
1237 case ElgLinesAdjacency: return "lines_adjacency";
1238 case ElgLineStrip: return "line_strip";
1239 case ElgTriangles: return "triangles";
1240 case ElgTrianglesAdjacency: return "triangles_adjacency";
1241 case ElgTriangleStrip: return "triangle_strip";
1242 case ElgQuads: return "quads";
1243 case ElgIsolines: return "isolines";
1244 default: return "none";
1245 }
1246 }
getVertexSpacingString(TVertexSpacing spacing)1247 static const char* getVertexSpacingString(TVertexSpacing spacing)
1248 {
1249 switch (spacing) {
1250 case EvsEqual: return "equal_spacing";
1251 case EvsFractionalEven: return "fractional_even_spacing";
1252 case EvsFractionalOdd: return "fractional_odd_spacing";
1253 default: return "none";
1254 }
1255 }
getVertexOrderString(TVertexOrder order)1256 static const char* getVertexOrderString(TVertexOrder order)
1257 {
1258 switch (order) {
1259 case EvoCw: return "cw";
1260 case EvoCcw: return "ccw";
1261 default: return "none";
1262 }
1263 }
mapGeometryToSize(TLayoutGeometry geometry)1264 static int mapGeometryToSize(TLayoutGeometry geometry)
1265 {
1266 switch (geometry) {
1267 case ElgPoints: return 1;
1268 case ElgLines: return 2;
1269 case ElgLinesAdjacency: return 4;
1270 case ElgTriangles: return 3;
1271 case ElgTrianglesAdjacency: return 6;
1272 default: return 0;
1273 }
1274 }
getInterlockOrderingString(TInterlockOrdering order)1275 static const char* getInterlockOrderingString(TInterlockOrdering order)
1276 {
1277 switch (order) {
1278 case EioPixelInterlockOrdered: return "pixel_interlock_ordered";
1279 case EioPixelInterlockUnordered: return "pixel_interlock_unordered";
1280 case EioSampleInterlockOrdered: return "sample_interlock_ordered";
1281 case EioSampleInterlockUnordered: return "sample_interlock_unordered";
1282 case EioShadingRateInterlockOrdered: return "shading_rate_interlock_ordered";
1283 case EioShadingRateInterlockUnordered: return "shading_rate_interlock_unordered";
1284 default: return "none";
1285 }
1286 }
1287 };
1288
1289 // Qualifiers that don't need to be keep per object. They have shader scope, not object scope.
1290 // So, they will not be part of TType, TQualifier, etc.
1291 struct TShaderQualifiers {
1292 TLayoutGeometry geometry; // geometry/tessellation shader in/out primitives
1293 bool pixelCenterInteger; // fragment shader
1294 bool originUpperLeft; // fragment shader
1295 int invocations;
1296 int vertices; // for tessellation "vertices", geometry & mesh "max_vertices"
1297 TVertexSpacing spacing;
1298 TVertexOrder order;
1299 bool pointMode;
1300 int localSize[3]; // compute shader
1301 bool localSizeNotDefault[3]; // compute shader
1302 int localSizeSpecId[3]; // compute shader specialization id for gl_WorkGroupSize
1303 bool earlyFragmentTests; // fragment input
1304 bool postDepthCoverage; // fragment input
1305 bool earlyAndLateFragmentTestsAMD; //fragment input
1306 bool nonCoherentColorAttachmentReadEXT; // fragment input
1307 bool nonCoherentDepthAttachmentReadEXT; // fragment input
1308 bool nonCoherentStencilAttachmentReadEXT; // fragment input
1309 TLayoutDepth layoutDepth;
1310 TLayoutStencil layoutStencil;
1311 bool blendEquation; // true if any blend equation was specified
1312 int numViews; // multiview extenstions
1313 TInterlockOrdering interlockOrdering;
1314 bool layoutOverrideCoverage; // true if layout override_coverage set
1315 bool layoutDerivativeGroupQuads; // true if layout derivative_group_quadsNV set
1316 bool layoutDerivativeGroupLinear; // true if layout derivative_group_linearNV set
1317 int primitives; // mesh shader "max_primitives"DerivativeGroupLinear; // true if layout derivative_group_linearNV set
1318 bool layoutPrimitiveCulling; // true if layout primitive_culling set
getDepthTShaderQualifiers1319 TLayoutDepth getDepth() const { return layoutDepth; }
getStencilTShaderQualifiers1320 TLayoutStencil getStencil() const { return layoutStencil; }
1321
initTShaderQualifiers1322 void init()
1323 {
1324 geometry = ElgNone;
1325 originUpperLeft = false;
1326 pixelCenterInteger = false;
1327 invocations = TQualifier::layoutNotSet;
1328 vertices = TQualifier::layoutNotSet;
1329 spacing = EvsNone;
1330 order = EvoNone;
1331 pointMode = false;
1332 localSize[0] = 1;
1333 localSize[1] = 1;
1334 localSize[2] = 1;
1335 localSizeNotDefault[0] = false;
1336 localSizeNotDefault[1] = false;
1337 localSizeNotDefault[2] = false;
1338 localSizeSpecId[0] = TQualifier::layoutNotSet;
1339 localSizeSpecId[1] = TQualifier::layoutNotSet;
1340 localSizeSpecId[2] = TQualifier::layoutNotSet;
1341 earlyFragmentTests = false;
1342 earlyAndLateFragmentTestsAMD = false;
1343 postDepthCoverage = false;
1344 nonCoherentColorAttachmentReadEXT = false;
1345 nonCoherentDepthAttachmentReadEXT = false;
1346 nonCoherentStencilAttachmentReadEXT = false;
1347 layoutDepth = EldNone;
1348 layoutStencil = ElsNone;
1349 blendEquation = false;
1350 numViews = TQualifier::layoutNotSet;
1351 layoutOverrideCoverage = false;
1352 layoutDerivativeGroupQuads = false;
1353 layoutDerivativeGroupLinear = false;
1354 layoutPrimitiveCulling = false;
1355 primitives = TQualifier::layoutNotSet;
1356 interlockOrdering = EioNone;
1357 }
1358
hasBlendEquationTShaderQualifiers1359 bool hasBlendEquation() const { return blendEquation; }
1360
1361 // Merge in characteristics from the 'src' qualifier. They can override when
1362 // set, but never erase when not set.
mergeTShaderQualifiers1363 void merge(const TShaderQualifiers& src)
1364 {
1365 if (src.geometry != ElgNone)
1366 geometry = src.geometry;
1367 if (src.pixelCenterInteger)
1368 pixelCenterInteger = src.pixelCenterInteger;
1369 if (src.originUpperLeft)
1370 originUpperLeft = src.originUpperLeft;
1371 if (src.invocations != TQualifier::layoutNotSet)
1372 invocations = src.invocations;
1373 if (src.vertices != TQualifier::layoutNotSet)
1374 vertices = src.vertices;
1375 if (src.spacing != EvsNone)
1376 spacing = src.spacing;
1377 if (src.order != EvoNone)
1378 order = src.order;
1379 if (src.pointMode)
1380 pointMode = true;
1381 for (int i = 0; i < 3; ++i) {
1382 if (src.localSize[i] > 1)
1383 localSize[i] = src.localSize[i];
1384 }
1385 for (int i = 0; i < 3; ++i) {
1386 localSizeNotDefault[i] = src.localSizeNotDefault[i] || localSizeNotDefault[i];
1387 }
1388 for (int i = 0; i < 3; ++i) {
1389 if (src.localSizeSpecId[i] != TQualifier::layoutNotSet)
1390 localSizeSpecId[i] = src.localSizeSpecId[i];
1391 }
1392 if (src.earlyFragmentTests)
1393 earlyFragmentTests = true;
1394 if (src.earlyAndLateFragmentTestsAMD)
1395 earlyAndLateFragmentTestsAMD = true;
1396 if (src.postDepthCoverage)
1397 postDepthCoverage = true;
1398 if (src.nonCoherentColorAttachmentReadEXT)
1399 nonCoherentColorAttachmentReadEXT = true;
1400 if (src.nonCoherentDepthAttachmentReadEXT)
1401 nonCoherentDepthAttachmentReadEXT = true;
1402 if (src.nonCoherentStencilAttachmentReadEXT)
1403 nonCoherentStencilAttachmentReadEXT = true;
1404 if (src.layoutDepth)
1405 layoutDepth = src.layoutDepth;
1406 if (src.layoutStencil)
1407 layoutStencil = src.layoutStencil;
1408 if (src.blendEquation)
1409 blendEquation = src.blendEquation;
1410 if (src.numViews != TQualifier::layoutNotSet)
1411 numViews = src.numViews;
1412 if (src.layoutOverrideCoverage)
1413 layoutOverrideCoverage = src.layoutOverrideCoverage;
1414 if (src.layoutDerivativeGroupQuads)
1415 layoutDerivativeGroupQuads = src.layoutDerivativeGroupQuads;
1416 if (src.layoutDerivativeGroupLinear)
1417 layoutDerivativeGroupLinear = src.layoutDerivativeGroupLinear;
1418 if (src.primitives != TQualifier::layoutNotSet)
1419 primitives = src.primitives;
1420 if (src.interlockOrdering != EioNone)
1421 interlockOrdering = src.interlockOrdering;
1422 if (src.layoutPrimitiveCulling)
1423 layoutPrimitiveCulling = src.layoutPrimitiveCulling;
1424 }
1425 };
1426
1427 class TTypeParameters {
1428 public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator ())1429 POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
1430
1431 TTypeParameters() : basicType(EbtVoid), arraySizes(nullptr) {}
1432
1433 TBasicType basicType;
1434 TArraySizes *arraySizes;
1435
1436 bool operator==(const TTypeParameters& rhs) const { return basicType == rhs.basicType && *arraySizes == *rhs.arraySizes; }
1437 bool operator!=(const TTypeParameters& rhs) const { return basicType != rhs.basicType || *arraySizes != *rhs.arraySizes; }
1438 };
1439
1440 //
1441 // TPublicType is just temporarily used while parsing and not quite the same
1442 // information kept per node in TType. Due to the bison stack, it can't have
1443 // types that it thinks have non-trivial constructors. It should
1444 // just be used while recognizing the grammar, not anything else.
1445 // Once enough is known about the situation, the proper information
1446 // moved into a TType, or the parse context, etc.
1447 //
1448 class TPublicType {
1449 public:
1450 TBasicType basicType;
1451 TSampler sampler;
1452 TQualifier qualifier;
1453 TShaderQualifiers shaderQualifiers;
1454 uint32_t vectorSize : 4;
1455 uint32_t matrixCols : 4;
1456 uint32_t matrixRows : 4;
1457 bool coopmatNV : 1;
1458 bool coopmatKHR : 1;
1459 TArraySizes* arraySizes;
1460 const TType* userDef;
1461 TSourceLoc loc;
1462 TTypeParameters* typeParameters;
1463 // SPIR-V type defined by spirv_type directive
1464 TSpirvType* spirvType;
1465
isCoopmat()1466 bool isCoopmat() const { return coopmatNV || coopmatKHR; }
isCoopmatNV()1467 bool isCoopmatNV() const { return coopmatNV; }
isCoopmatKHR()1468 bool isCoopmatKHR() const { return coopmatKHR; }
1469
initType(const TSourceLoc & l)1470 void initType(const TSourceLoc& l)
1471 {
1472 basicType = EbtVoid;
1473 vectorSize = 1u;
1474 matrixRows = 0;
1475 matrixCols = 0;
1476 arraySizes = nullptr;
1477 userDef = nullptr;
1478 loc = l;
1479 typeParameters = nullptr;
1480 coopmatNV = false;
1481 coopmatKHR = false;
1482 spirvType = nullptr;
1483 }
1484
1485 void initQualifiers(bool global = false)
1486 {
1487 qualifier.clear();
1488 if (global)
1489 qualifier.storage = EvqGlobal;
1490 }
1491
1492 void init(const TSourceLoc& l, bool global = false)
1493 {
1494 initType(l);
1495 sampler.clear();
1496 initQualifiers(global);
1497 shaderQualifiers.init();
1498 }
1499
setVector(int s)1500 void setVector(int s)
1501 {
1502 matrixRows = 0;
1503 matrixCols = 0;
1504 assert(s >= 0);
1505 vectorSize = static_cast<uint32_t>(s) & 0b1111;
1506 }
1507
setMatrix(int c,int r)1508 void setMatrix(int c, int r)
1509 {
1510 assert(r >= 0);
1511 matrixRows = static_cast<uint32_t>(r) & 0b1111;
1512 assert(c >= 0);
1513 matrixCols = static_cast<uint32_t>(c) & 0b1111;
1514 vectorSize = 0;
1515 }
1516
isScalar()1517 bool isScalar() const
1518 {
1519 return matrixCols == 0u && vectorSize == 1u && arraySizes == nullptr && userDef == nullptr;
1520 }
1521
1522 // GL_EXT_spirv_intrinsics
1523 void setSpirvType(const TSpirvInstruction& spirvInst, const TSpirvTypeParameters* typeParams = nullptr);
1524
1525 // "Image" is a superset of "Subpass"
isImage()1526 bool isImage() const { return basicType == EbtSampler && sampler.isImage(); }
isSubpass()1527 bool isSubpass() const { return basicType == EbtSampler && sampler.isSubpass(); }
isAttachmentEXT()1528 bool isAttachmentEXT() const { return basicType == EbtSampler && sampler.isAttachmentEXT(); }
1529 };
1530
1531 //
1532 // Base class for things that have a type.
1533 //
1534 class TType {
1535 public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator ())1536 POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
1537
1538 // for "empty" type (no args) or simple scalar/vector/matrix
1539 explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0,
1540 bool isVector = false) :
1541 basicType(t), vectorSize(static_cast<uint32_t>(vs) & 0b1111), matrixCols(static_cast<uint32_t>(mc) & 0b1111), matrixRows(static_cast<uint32_t>(mr) & 0b1111), vector1(isVector && vs == 1), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
1542 arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr),
1543 spirvType(nullptr)
1544 {
1545 assert(vs >= 0);
1546 assert(mc >= 0);
1547 assert(mr >= 0);
1548
1549 sampler.clear();
1550 qualifier.clear();
1551 qualifier.storage = q;
1552 assert(!(isMatrix() && vectorSize != 0)); // prevent vectorSize != 0 on matrices
1553 }
1554 // for explicit precision qualifier
1555 TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0,
1556 bool isVector = false) :
basicType(t)1557 basicType(t), vectorSize(static_cast<uint32_t>(vs) & 0b1111), matrixCols(static_cast<uint32_t>(mc) & 0b1111), matrixRows(static_cast<uint32_t>(mr) & 0b1111), vector1(isVector && vs == 1), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
1558 arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr),
1559 spirvType(nullptr)
1560 {
1561 assert(vs >= 0);
1562 assert(mc >= 0);
1563 assert(mr >= 0);
1564
1565 sampler.clear();
1566 qualifier.clear();
1567 qualifier.storage = q;
1568 qualifier.precision = p;
1569 assert(p >= EpqNone && p <= EpqHigh);
1570 assert(!(isMatrix() && vectorSize != 0)); // prevent vectorSize != 0 on matrices
1571 }
1572 // for turning a TPublicType into a TType, using a shallow copy
TType(const TPublicType & p)1573 explicit TType(const TPublicType& p) :
1574 basicType(p.basicType),
1575 vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false), coopmatNV(p.coopmatNV), coopmatKHR(p.coopmatKHR), coopmatKHRuse(0), coopmatKHRUseValid(false),
1576 arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(p.typeParameters),
1577 spirvType(p.spirvType)
1578 {
1579 if (basicType == EbtSampler)
1580 sampler = p.sampler;
1581 else
1582 sampler.clear();
1583 qualifier = p.qualifier;
1584 if (p.userDef) {
1585 if (p.userDef->basicType == EbtReference) {
1586 basicType = EbtReference;
1587 referentType = p.userDef->referentType;
1588 } else {
1589 structure = p.userDef->getWritableStruct(); // public type is short-lived; there are no sharing issues
1590 }
1591 typeName = NewPoolTString(p.userDef->getTypeName().c_str());
1592 }
1593 if (p.isCoopmatNV() && p.typeParameters && p.typeParameters->arraySizes->getNumDims() > 0) {
1594 int numBits = p.typeParameters->arraySizes->getDimSize(0);
1595 if (p.basicType == EbtFloat && numBits == 16) {
1596 basicType = EbtFloat16;
1597 qualifier.precision = EpqNone;
1598 } else if (p.basicType == EbtUint && numBits == 8) {
1599 basicType = EbtUint8;
1600 qualifier.precision = EpqNone;
1601 } else if (p.basicType == EbtUint && numBits == 16) {
1602 basicType = EbtUint16;
1603 qualifier.precision = EpqNone;
1604 } else if (p.basicType == EbtInt && numBits == 8) {
1605 basicType = EbtInt8;
1606 qualifier.precision = EpqNone;
1607 } else if (p.basicType == EbtInt && numBits == 16) {
1608 basicType = EbtInt16;
1609 qualifier.precision = EpqNone;
1610 }
1611 }
1612 if (p.isCoopmatKHR() && p.typeParameters && p.typeParameters->arraySizes->getNumDims() > 0) {
1613 basicType = p.typeParameters->basicType;
1614
1615 if (p.typeParameters->arraySizes->getNumDims() == 4) {
1616 const int dimSize = p.typeParameters->arraySizes->getDimSize(3);
1617 assert(dimSize >= 0);
1618 coopmatKHRuse = static_cast<uint32_t>(dimSize) & 0b111;
1619 coopmatKHRUseValid = true;
1620 p.typeParameters->arraySizes->removeLastSize();
1621 }
1622 }
1623 }
1624 // for construction of sampler types
1625 TType(const TSampler& sampler, TStorageQualifier q = EvqUniform, TArraySizes* as = nullptr) :
basicType(EbtSampler)1626 basicType(EbtSampler), vectorSize(1u), matrixCols(0u), matrixRows(0u), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
1627 arraySizes(as), structure(nullptr), fieldName(nullptr), typeName(nullptr),
1628 sampler(sampler), typeParameters(nullptr), spirvType(nullptr)
1629 {
1630 qualifier.clear();
1631 qualifier.storage = q;
1632 }
1633 // to efficiently make a dereferenced type
1634 // without ever duplicating the outer structure that will be thrown away
1635 // and using only shallow copy
1636 TType(const TType& type, int derefIndex, bool rowMajor = false)
1637 {
1638 if (type.isArray()) {
1639 shallowCopy(type);
1640 if (type.getArraySizes()->getNumDims() == 1) {
1641 arraySizes = nullptr;
1642 } else {
1643 // want our own copy of the array, so we can edit it
1644 arraySizes = new TArraySizes;
1645 arraySizes->copyDereferenced(*type.arraySizes);
1646 }
1647 } else if (type.basicType == EbtStruct || type.basicType == EbtBlock) {
1648 // do a structure dereference
1649 const TTypeList& memberList = *type.getStruct();
1650 shallowCopy(*memberList[derefIndex].type);
1651 return;
1652 } else {
1653 // do a vector/matrix dereference
1654 shallowCopy(type);
1655 if (matrixCols > 0) {
1656 // dereference from matrix to vector
1657 if (rowMajor)
1658 vectorSize = matrixCols;
1659 else
1660 vectorSize = matrixRows;
1661 matrixCols = 0;
1662 matrixRows = 0;
1663 if (vectorSize == 1)
1664 vector1 = true;
1665 } else if (isVector()) {
1666 // dereference from vector to scalar
1667 vectorSize = 1;
1668 vector1 = false;
1669 } else if (isCoopMat()) {
1670 coopmatNV = false;
1671 coopmatKHR = false;
1672 coopmatKHRuse = 0;
1673 coopmatKHRUseValid = false;
1674 typeParameters = nullptr;
1675 }
1676 }
1677 }
1678 // for making structures, ...
TType(TTypeList * userDef,const TString & n)1679 TType(TTypeList* userDef, const TString& n) :
1680 basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
1681 arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr),
1682 spirvType(nullptr)
1683 {
1684 sampler.clear();
1685 qualifier.clear();
1686 typeName = NewPoolTString(n.c_str());
1687 }
1688 // For interface blocks
TType(TTypeList * userDef,const TString & n,const TQualifier & q)1689 TType(TTypeList* userDef, const TString& n, const TQualifier& q) :
1690 basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
1691 qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr),
1692 spirvType(nullptr)
1693 {
1694 sampler.clear();
1695 typeName = NewPoolTString(n.c_str());
1696 }
1697 // for block reference (first parameter must be EbtReference)
TType(TBasicType t,const TType & p,const TString & n)1698 explicit TType(TBasicType t, const TType &p, const TString& n) :
1699 basicType(t), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false),
1700 arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr),
1701 spirvType(nullptr)
1702 {
1703 assert(t == EbtReference);
1704 typeName = NewPoolTString(n.c_str());
1705 sampler.clear();
1706 qualifier.clear();
1707 qualifier.storage = p.qualifier.storage;
1708 referentType = p.clone();
1709 }
~TType()1710 virtual ~TType() {}
1711
1712 // Not for use across pool pops; it will cause multiple instances of TType to point to the same information.
1713 // This only works if that information (like a structure's list of types) does not change and
1714 // the instances are sharing the same pool.
shallowCopy(const TType & copyOf)1715 void shallowCopy(const TType& copyOf)
1716 {
1717 basicType = copyOf.basicType;
1718 sampler = copyOf.sampler;
1719 qualifier = copyOf.qualifier;
1720 vectorSize = copyOf.vectorSize;
1721 matrixCols = copyOf.matrixCols;
1722 matrixRows = copyOf.matrixRows;
1723 vector1 = copyOf.vector1;
1724 arraySizes = copyOf.arraySizes; // copying the pointer only, not the contents
1725 fieldName = copyOf.fieldName;
1726 typeName = copyOf.typeName;
1727 if (isStruct()) {
1728 structure = copyOf.structure;
1729 } else {
1730 referentType = copyOf.referentType;
1731 }
1732 typeParameters = copyOf.typeParameters;
1733 spirvType = copyOf.spirvType;
1734 coopmatNV = copyOf.isCoopMatNV();
1735 coopmatKHR = copyOf.isCoopMatKHR();
1736 coopmatKHRuse = copyOf.coopmatKHRuse;
1737 coopmatKHRUseValid = copyOf.coopmatKHRUseValid;
1738 }
1739
1740 // Make complete copy of the whole type graph rooted at 'copyOf'.
deepCopy(const TType & copyOf)1741 void deepCopy(const TType& copyOf)
1742 {
1743 TMap<TTypeList*,TTypeList*> copied; // to enable copying a type graph as a graph, not a tree
1744 deepCopy(copyOf, copied);
1745 }
1746
1747 // Recursively make temporary
makeTemporary()1748 void makeTemporary()
1749 {
1750 getQualifier().makeTemporary();
1751
1752 if (isStruct())
1753 for (unsigned int i = 0; i < structure->size(); ++i)
1754 (*structure)[i].type->makeTemporary();
1755 }
1756
clone()1757 TType* clone() const
1758 {
1759 TType *newType = new TType();
1760 newType->deepCopy(*this);
1761
1762 return newType;
1763 }
1764
makeVector()1765 void makeVector() { vector1 = true; }
1766
hideMember()1767 virtual void hideMember() { basicType = EbtVoid; vectorSize = 1u; }
hiddenMember()1768 virtual bool hiddenMember() const { return basicType == EbtVoid; }
1769
setFieldName(const TString & n)1770 virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); }
getTypeName()1771 virtual const TString& getTypeName() const
1772 {
1773 assert(typeName);
1774 return *typeName;
1775 }
1776
getFieldName()1777 virtual const TString& getFieldName() const
1778 {
1779 assert(fieldName);
1780 return *fieldName;
1781 }
getShaderInterface()1782 TShaderInterface getShaderInterface() const
1783 {
1784 if (basicType != EbtBlock)
1785 return EsiNone;
1786
1787 switch (qualifier.storage) {
1788 default:
1789 return EsiNone;
1790 case EvqVaryingIn:
1791 return EsiInput;
1792 case EvqVaryingOut:
1793 return EsiOutput;
1794 case EvqUniform:
1795 case EvqBuffer:
1796 return EsiUniform;
1797 }
1798 }
1799
getBasicType()1800 virtual TBasicType getBasicType() const { return basicType; }
getSampler()1801 virtual const TSampler& getSampler() const { return sampler; }
getSampler()1802 virtual TSampler& getSampler() { return sampler; }
1803
getQualifier()1804 virtual TQualifier& getQualifier() { return qualifier; }
getQualifier()1805 virtual const TQualifier& getQualifier() const { return qualifier; }
1806
getVectorSize()1807 virtual int getVectorSize() const { return static_cast<int>(vectorSize); } // returns 1 for either scalar or vector of size 1, valid for both
getMatrixCols()1808 virtual int getMatrixCols() const { return static_cast<int>(matrixCols); }
getMatrixRows()1809 virtual int getMatrixRows() const { return static_cast<int>(matrixRows); }
getOuterArraySize()1810 virtual int getOuterArraySize() const { return arraySizes->getOuterSize(); }
getOuterArrayNode()1811 virtual TIntermTyped* getOuterArrayNode() const { return arraySizes->getOuterNode(); }
getCumulativeArraySize()1812 virtual int getCumulativeArraySize() const { return arraySizes->getCumulativeSize(); }
isArrayOfArrays()1813 bool isArrayOfArrays() const { return arraySizes != nullptr && arraySizes->getNumDims() > 1; }
getImplicitArraySize()1814 virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); }
getArraySizes()1815 virtual const TArraySizes* getArraySizes() const { return arraySizes; }
getArraySizes()1816 virtual TArraySizes* getArraySizes() { return arraySizes; }
getReferentType()1817 virtual TType* getReferentType() const { return referentType; }
getTypeParameters()1818 virtual const TTypeParameters* getTypeParameters() const { return typeParameters; }
getTypeParameters()1819 virtual TTypeParameters* getTypeParameters() { return typeParameters; }
1820
isScalar()1821 virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); }
isScalarOrVec1()1822 virtual bool isScalarOrVec1() const { return isScalar() || vector1; }
isScalarOrVector()1823 virtual bool isScalarOrVector() const { return !isMatrix() && !isStruct() && !isArray(); }
isVector()1824 virtual bool isVector() const { return vectorSize > 1u || vector1; }
isMatrix()1825 virtual bool isMatrix() const { return matrixCols ? true : false; }
isArray()1826 virtual bool isArray() const { return arraySizes != nullptr; }
isSizedArray()1827 virtual bool isSizedArray() const { return isArray() && arraySizes->isSized(); }
isUnsizedArray()1828 virtual bool isUnsizedArray() const { return isArray() && !arraySizes->isSized(); }
isImplicitlySizedArray()1829 virtual bool isImplicitlySizedArray() const { return isArray() && arraySizes->isImplicitlySized(); }
isArrayVariablyIndexed()1830 virtual bool isArrayVariablyIndexed() const { assert(isArray()); return arraySizes->isVariablyIndexed(); }
setArrayVariablyIndexed()1831 virtual void setArrayVariablyIndexed() { assert(isArray()); arraySizes->setVariablyIndexed(); }
updateImplicitArraySize(int size)1832 virtual void updateImplicitArraySize(int size) { assert(isArray()); arraySizes->updateImplicitSize(size); }
setImplicitlySized(bool isImplicitSized)1833 virtual void setImplicitlySized(bool isImplicitSized) { arraySizes->setImplicitlySized(isImplicitSized); }
isStruct()1834 virtual bool isStruct() const { return basicType == EbtStruct || basicType == EbtBlock; }
isFloatingDomain()1835 virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16; }
isIntegerDomain()1836 virtual bool isIntegerDomain() const
1837 {
1838 switch (basicType) {
1839 case EbtInt8:
1840 case EbtUint8:
1841 case EbtInt16:
1842 case EbtUint16:
1843 case EbtInt:
1844 case EbtUint:
1845 case EbtInt64:
1846 case EbtUint64:
1847 case EbtAtomicUint:
1848 return true;
1849 default:
1850 break;
1851 }
1852 return false;
1853 }
isOpaque()1854 virtual bool isOpaque() const { return basicType == EbtSampler
1855 || basicType == EbtAtomicUint || basicType == EbtAccStruct || basicType == EbtRayQuery
1856 || basicType == EbtHitObjectNV; }
isBuiltIn()1857 virtual bool isBuiltIn() const { return getQualifier().builtIn != EbvNone; }
1858
isAttachmentEXT()1859 virtual bool isAttachmentEXT() const { return basicType == EbtSampler && getSampler().isAttachmentEXT(); }
isImage()1860 virtual bool isImage() const { return basicType == EbtSampler && getSampler().isImage(); }
isSubpass()1861 virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); }
isTexture()1862 virtual bool isTexture() const { return basicType == EbtSampler && getSampler().isTexture(); }
isBindlessImage()1863 virtual bool isBindlessImage() const { return isImage() && qualifier.layoutBindlessImage; }
isBindlessTexture()1864 virtual bool isBindlessTexture() const { return isTexture() && qualifier.layoutBindlessSampler; }
1865 // Check the block-name convention of creating a block without populating it's members:
isUnusableName()1866 virtual bool isUnusableName() const { return isStruct() && structure == nullptr; }
isParameterized()1867 virtual bool isParameterized() const { return typeParameters != nullptr; }
isAtomic()1868 bool isAtomic() const { return basicType == EbtAtomicUint; }
isCoopMat()1869 bool isCoopMat() const { return coopmatNV || coopmatKHR; }
isCoopMatNV()1870 bool isCoopMatNV() const { return coopmatNV; }
isCoopMatKHR()1871 bool isCoopMatKHR() const { return coopmatKHR; }
isReference()1872 bool isReference() const { return getBasicType() == EbtReference; }
isSpirvType()1873 bool isSpirvType() const { return getBasicType() == EbtSpirvType; }
getCoopMatKHRuse()1874 int getCoopMatKHRuse() const { return static_cast<int>(coopmatKHRuse); }
1875
1876 // return true if this type contains any subtype which satisfies the given predicate.
1877 template <typename P>
contains(P predicate)1878 bool contains(P predicate) const
1879 {
1880 if (predicate(this))
1881 return true;
1882
1883 const auto hasa = [predicate](const TTypeLoc& tl) { return tl.type->contains(predicate); };
1884
1885 return isStruct() && std::any_of(structure->begin(), structure->end(), hasa);
1886 }
1887
1888 // Recursively checks if the type contains the given basic type
containsBasicType(TBasicType checkType)1889 virtual bool containsBasicType(TBasicType checkType) const
1890 {
1891 return contains([checkType](const TType* t) { return t->basicType == checkType; } );
1892 }
1893
1894 // Recursively check the structure for any arrays, needed for some error checks
containsArray()1895 virtual bool containsArray() const
1896 {
1897 return contains([](const TType* t) { return t->isArray(); } );
1898 }
1899
1900 // Check the structure for any structures, needed for some error checks
containsStructure()1901 virtual bool containsStructure() const
1902 {
1903 return contains([this](const TType* t) { return t != this && t->isStruct(); } );
1904 }
1905
1906 // Recursively check the structure for any unsized arrays, needed for triggering a copyUp().
containsUnsizedArray()1907 virtual bool containsUnsizedArray() const
1908 {
1909 return contains([](const TType* t) { return t->isUnsizedArray(); } );
1910 }
1911
containsOpaque()1912 virtual bool containsOpaque() const
1913 {
1914 return contains([](const TType* t) { return t->isOpaque(); } );
1915 }
1916
containsSampler()1917 virtual bool containsSampler() const
1918 {
1919 return contains([](const TType* t) { return t->isTexture() || t->isImage(); });
1920 }
1921
1922 // Recursively checks if the type contains a built-in variable
containsBuiltIn()1923 virtual bool containsBuiltIn() const
1924 {
1925 return contains([](const TType* t) { return t->isBuiltIn(); } );
1926 }
1927
containsNonOpaque()1928 virtual bool containsNonOpaque() const
1929 {
1930 const auto nonOpaque = [](const TType* t) {
1931 switch (t->basicType) {
1932 case EbtVoid:
1933 case EbtFloat:
1934 case EbtDouble:
1935 case EbtFloat16:
1936 case EbtInt8:
1937 case EbtUint8:
1938 case EbtInt16:
1939 case EbtUint16:
1940 case EbtInt:
1941 case EbtUint:
1942 case EbtInt64:
1943 case EbtUint64:
1944 case EbtBool:
1945 case EbtReference:
1946 return true;
1947 default:
1948 return false;
1949 }
1950 };
1951
1952 return contains(nonOpaque);
1953 }
1954
containsSpecializationSize()1955 virtual bool containsSpecializationSize() const
1956 {
1957 return contains([](const TType* t) { return t->isArray() && t->arraySizes->isOuterSpecialization(); } );
1958 }
1959
containsDouble()1960 bool containsDouble() const
1961 {
1962 return containsBasicType(EbtDouble);
1963 }
contains16BitFloat()1964 bool contains16BitFloat() const
1965 {
1966 return containsBasicType(EbtFloat16);
1967 }
contains64BitInt()1968 bool contains64BitInt() const
1969 {
1970 return containsBasicType(EbtInt64) || containsBasicType(EbtUint64);
1971 }
contains16BitInt()1972 bool contains16BitInt() const
1973 {
1974 return containsBasicType(EbtInt16) || containsBasicType(EbtUint16);
1975 }
contains8BitInt()1976 bool contains8BitInt() const
1977 {
1978 return containsBasicType(EbtInt8) || containsBasicType(EbtUint8);
1979 }
containsCoopMat()1980 bool containsCoopMat() const
1981 {
1982 return contains([](const TType* t) { return t->coopmatNV || t->coopmatKHR; } );
1983 }
containsReference()1984 bool containsReference() const
1985 {
1986 return containsBasicType(EbtReference);
1987 }
1988
1989 // Array editing methods. Array descriptors can be shared across
1990 // type instances. This allows all uses of the same array
1991 // to be updated at once. E.g., all nodes can be explicitly sized
1992 // by tracking and correcting one implicit size. Or, all nodes
1993 // can get the explicit size on a redeclaration that gives size.
1994 //
1995 // N.B.: Don't share with the shared symbol tables (symbols are
1996 // marked as isReadOnly(). Such symbols with arrays that will be
1997 // edited need to copyUp() on first use, so that
1998 // A) the edits don't effect the shared symbol table, and
1999 // B) the edits are shared across all users.
updateArraySizes(const TType & type)2000 void updateArraySizes(const TType& type)
2001 {
2002 // For when we may already be sharing existing array descriptors,
2003 // keeping the pointers the same, just updating the contents.
2004 assert(arraySizes != nullptr);
2005 assert(type.arraySizes != nullptr);
2006 *arraySizes = *type.arraySizes;
2007 }
copyArraySizes(const TArraySizes & s)2008 void copyArraySizes(const TArraySizes& s)
2009 {
2010 // For setting a fresh new set of array sizes, not yet worrying about sharing.
2011 arraySizes = new TArraySizes;
2012 *arraySizes = s;
2013 }
transferArraySizes(TArraySizes * s)2014 void transferArraySizes(TArraySizes* s)
2015 {
2016 // For setting an already allocated set of sizes that this type can use
2017 // (no copy made).
2018 arraySizes = s;
2019 }
clearArraySizes()2020 void clearArraySizes()
2021 {
2022 arraySizes = nullptr;
2023 }
2024
2025 // Add inner array sizes, to any existing sizes, via copy; the
2026 // sizes passed in can still be reused for other purposes.
copyArrayInnerSizes(const TArraySizes * s)2027 void copyArrayInnerSizes(const TArraySizes* s)
2028 {
2029 if (s != nullptr) {
2030 if (arraySizes == nullptr)
2031 copyArraySizes(*s);
2032 else
2033 arraySizes->addInnerSizes(*s);
2034 }
2035 }
changeOuterArraySize(int s)2036 void changeOuterArraySize(int s) { arraySizes->changeOuterSize(s); }
2037
2038 // Recursively make the implicit array size the explicit array size.
2039 // Expicit arrays are compile-time or link-time sized, never run-time sized.
2040 // Sometimes, policy calls for an array to be run-time sized even if it was
2041 // never variably indexed: Don't turn a 'skipNonvariablyIndexed' array into
2042 // an explicit array.
adoptImplicitArraySizes(bool skipNonvariablyIndexed)2043 void adoptImplicitArraySizes(bool skipNonvariablyIndexed)
2044 {
2045 if (isUnsizedArray() &&
2046 (qualifier.builtIn == EbvSampleMask ||
2047 !(skipNonvariablyIndexed || isArrayVariablyIndexed()))) {
2048 changeOuterArraySize(getImplicitArraySize());
2049 setImplicitlySized(true);
2050 }
2051 // For multi-dim per-view arrays, set unsized inner dimension size to 1
2052 if (qualifier.isPerView() && arraySizes && arraySizes->isInnerUnsized())
2053 arraySizes->clearInnerUnsized();
2054 if (isStruct() && structure->size() > 0) {
2055 int lastMember = (int)structure->size() - 1;
2056 for (int i = 0; i < lastMember; ++i)
2057 (*structure)[i].type->adoptImplicitArraySizes(false);
2058 // implement the "last member of an SSBO" policy
2059 (*structure)[lastMember].type->adoptImplicitArraySizes(getQualifier().storage == EvqBuffer);
2060 }
2061 }
2062
copyTypeParameters(const TTypeParameters & s)2063 void copyTypeParameters(const TTypeParameters& s)
2064 {
2065 // For setting a fresh new set of type parameters, not yet worrying about sharing.
2066 typeParameters = new TTypeParameters;
2067 *typeParameters = s;
2068 }
2069
getBasicString()2070 const char* getBasicString() const
2071 {
2072 return TType::getBasicString(basicType);
2073 }
2074
getBasicString(TBasicType t)2075 static const char* getBasicString(TBasicType t)
2076 {
2077 switch (t) {
2078 case EbtFloat: return "float";
2079 case EbtInt: return "int";
2080 case EbtUint: return "uint";
2081 case EbtSampler: return "sampler/image";
2082 case EbtVoid: return "void";
2083 case EbtDouble: return "double";
2084 case EbtFloat16: return "float16_t";
2085 case EbtInt8: return "int8_t";
2086 case EbtUint8: return "uint8_t";
2087 case EbtInt16: return "int16_t";
2088 case EbtUint16: return "uint16_t";
2089 case EbtInt64: return "int64_t";
2090 case EbtUint64: return "uint64_t";
2091 case EbtBool: return "bool";
2092 case EbtAtomicUint: return "atomic_uint";
2093 case EbtStruct: return "structure";
2094 case EbtBlock: return "block";
2095 case EbtAccStruct: return "accelerationStructureNV";
2096 case EbtRayQuery: return "rayQueryEXT";
2097 case EbtReference: return "reference";
2098 case EbtString: return "string";
2099 case EbtSpirvType: return "spirv_type";
2100 case EbtCoopmat: return "coopmat";
2101 default: return "unknown type";
2102 }
2103 }
2104
2105 TString getCompleteString(bool syntactic = false, bool getQualifiers = true, bool getPrecision = true,
2106 bool getType = true, TString name = "", TString structName = "") const
2107 {
2108 TString typeString;
2109
2110 const auto appendStr = [&](const char* s) { typeString.append(s); };
2111 const auto appendUint = [&](unsigned int u) { typeString.append(std::to_string(u).c_str()); };
2112 const auto appendInt = [&](int i) { typeString.append(std::to_string(i).c_str()); };
2113
2114 if (getQualifiers) {
2115 if (qualifier.hasSpirvDecorate())
2116 appendStr(qualifier.getSpirvDecorateQualifierString().c_str());
2117
2118 if (qualifier.hasLayout()) {
2119 // To reduce noise, skip this if the only layout is an xfb_buffer
2120 // with no triggering xfb_offset.
2121 TQualifier noXfbBuffer = qualifier;
2122 noXfbBuffer.layoutXfbBuffer = TQualifier::layoutXfbBufferEnd;
2123 if (noXfbBuffer.hasLayout()) {
2124 appendStr("layout(");
2125 if (qualifier.hasAnyLocation()) {
2126 appendStr(" location=");
2127 appendUint(qualifier.layoutLocation);
2128 if (qualifier.hasComponent()) {
2129 appendStr(" component=");
2130 appendUint(qualifier.layoutComponent);
2131 }
2132 if (qualifier.hasIndex()) {
2133 appendStr(" index=");
2134 appendUint(qualifier.layoutIndex);
2135 }
2136 }
2137 if (qualifier.hasSet()) {
2138 appendStr(" set=");
2139 appendUint(qualifier.layoutSet);
2140 }
2141 if (qualifier.hasBinding()) {
2142 appendStr(" binding=");
2143 appendUint(qualifier.layoutBinding);
2144 }
2145 if (qualifier.hasStream()) {
2146 appendStr(" stream=");
2147 appendUint(qualifier.layoutStream);
2148 }
2149 if (qualifier.hasMatrix()) {
2150 appendStr(" ");
2151 appendStr(TQualifier::getLayoutMatrixString(qualifier.layoutMatrix));
2152 }
2153 if (qualifier.hasPacking()) {
2154 appendStr(" ");
2155 appendStr(TQualifier::getLayoutPackingString(qualifier.layoutPacking));
2156 }
2157 if (qualifier.hasOffset()) {
2158 appendStr(" offset=");
2159 appendInt(qualifier.layoutOffset);
2160 }
2161 if (qualifier.hasAlign()) {
2162 appendStr(" align=");
2163 appendInt(qualifier.layoutAlign);
2164 }
2165 if (qualifier.hasFormat()) {
2166 appendStr(" ");
2167 appendStr(TQualifier::getLayoutFormatString(qualifier.layoutFormat));
2168 }
2169 if (qualifier.hasXfbBuffer() && qualifier.hasXfbOffset()) {
2170 appendStr(" xfb_buffer=");
2171 appendUint(qualifier.layoutXfbBuffer);
2172 }
2173 if (qualifier.hasXfbOffset()) {
2174 appendStr(" xfb_offset=");
2175 appendUint(qualifier.layoutXfbOffset);
2176 }
2177 if (qualifier.hasXfbStride()) {
2178 appendStr(" xfb_stride=");
2179 appendUint(qualifier.layoutXfbStride);
2180 }
2181 if (qualifier.hasAttachment()) {
2182 appendStr(" input_attachment_index=");
2183 appendUint(qualifier.layoutAttachment);
2184 }
2185 if (qualifier.hasSpecConstantId()) {
2186 appendStr(" constant_id=");
2187 appendUint(qualifier.layoutSpecConstantId);
2188 }
2189 if (qualifier.layoutPushConstant)
2190 appendStr(" push_constant");
2191 if (qualifier.layoutBufferReference)
2192 appendStr(" buffer_reference");
2193 if (qualifier.hasBufferReferenceAlign()) {
2194 appendStr(" buffer_reference_align=");
2195 appendUint(1u << qualifier.layoutBufferReferenceAlign);
2196 }
2197
2198 if (qualifier.layoutPassthrough)
2199 appendStr(" passthrough");
2200 if (qualifier.layoutViewportRelative)
2201 appendStr(" layoutViewportRelative");
2202 if (qualifier.layoutSecondaryViewportRelativeOffset != -2048) {
2203 appendStr(" layoutSecondaryViewportRelativeOffset=");
2204 appendInt(qualifier.layoutSecondaryViewportRelativeOffset);
2205 }
2206
2207 if (qualifier.layoutShaderRecord)
2208 appendStr(" shaderRecordNV");
2209 if (qualifier.layoutHitObjectShaderRecordNV)
2210 appendStr(" hitobjectshaderrecordnv");
2211
2212 if (qualifier.layoutBindlessSampler)
2213 appendStr(" layoutBindlessSampler");
2214 if (qualifier.layoutBindlessImage)
2215 appendStr(" layoutBindlessImage");
2216
2217 appendStr(")");
2218 }
2219 }
2220
2221 if (qualifier.invariant)
2222 appendStr(" invariant");
2223 if (qualifier.noContraction)
2224 appendStr(" noContraction");
2225 if (qualifier.centroid)
2226 appendStr(" centroid");
2227 if (qualifier.smooth)
2228 appendStr(" smooth");
2229 if (qualifier.flat)
2230 appendStr(" flat");
2231 if (qualifier.nopersp)
2232 appendStr(" noperspective");
2233 if (qualifier.explicitInterp)
2234 appendStr(" __explicitInterpAMD");
2235 if (qualifier.pervertexNV)
2236 appendStr(" pervertexNV");
2237 if (qualifier.pervertexEXT)
2238 appendStr(" pervertexEXT");
2239 if (qualifier.perPrimitiveNV)
2240 appendStr(" perprimitiveNV");
2241 if (qualifier.perViewNV)
2242 appendStr(" perviewNV");
2243 if (qualifier.perTaskNV)
2244 appendStr(" taskNV");
2245 if (qualifier.patch)
2246 appendStr(" patch");
2247 if (qualifier.sample)
2248 appendStr(" sample");
2249 if (qualifier.coherent)
2250 appendStr(" coherent");
2251 if (qualifier.devicecoherent)
2252 appendStr(" devicecoherent");
2253 if (qualifier.queuefamilycoherent)
2254 appendStr(" queuefamilycoherent");
2255 if (qualifier.workgroupcoherent)
2256 appendStr(" workgroupcoherent");
2257 if (qualifier.subgroupcoherent)
2258 appendStr(" subgroupcoherent");
2259 if (qualifier.shadercallcoherent)
2260 appendStr(" shadercallcoherent");
2261 if (qualifier.nonprivate)
2262 appendStr(" nonprivate");
2263 if (qualifier.volatil)
2264 appendStr(" volatile");
2265 if (qualifier.restrict)
2266 appendStr(" restrict");
2267 if (qualifier.readonly)
2268 appendStr(" readonly");
2269 if (qualifier.writeonly)
2270 appendStr(" writeonly");
2271 if (qualifier.specConstant)
2272 appendStr(" specialization-constant");
2273 if (qualifier.nonUniform)
2274 appendStr(" nonuniform");
2275 if (qualifier.isNullInit())
2276 appendStr(" null-init");
2277 if (qualifier.isSpirvByReference())
2278 appendStr(" spirv_by_reference");
2279 if (qualifier.isSpirvLiteral())
2280 appendStr(" spirv_literal");
2281 appendStr(" ");
2282 appendStr(getStorageQualifierString());
2283 }
2284 if (getType) {
2285 if (syntactic) {
2286 if (getPrecision && qualifier.precision != EpqNone) {
2287 appendStr(" ");
2288 appendStr(getPrecisionQualifierString());
2289 }
2290 if (isVector() || isMatrix()) {
2291 appendStr(" ");
2292 switch (basicType) {
2293 case EbtDouble:
2294 appendStr("d");
2295 break;
2296 case EbtInt:
2297 appendStr("i");
2298 break;
2299 case EbtUint:
2300 appendStr("u");
2301 break;
2302 case EbtBool:
2303 appendStr("b");
2304 break;
2305 case EbtFloat:
2306 default:
2307 break;
2308 }
2309 if (isVector()) {
2310 appendStr("vec");
2311 appendInt(vectorSize);
2312 } else {
2313 appendStr("mat");
2314 appendInt(matrixCols);
2315 appendStr("x");
2316 appendInt(matrixRows);
2317 }
2318 } else if (isStruct() && structure) {
2319 appendStr(" ");
2320 appendStr(structName.c_str());
2321 appendStr("{");
2322 bool hasHiddenMember = true;
2323 for (size_t i = 0; i < structure->size(); ++i) {
2324 if (!(*structure)[i].type->hiddenMember()) {
2325 if (!hasHiddenMember)
2326 appendStr(", ");
2327 typeString.append((*structure)[i].type->getCompleteString(syntactic, getQualifiers, getPrecision, getType, (*structure)[i].type->getFieldName()));
2328 hasHiddenMember = false;
2329 }
2330 }
2331 appendStr("}");
2332 } else {
2333 appendStr(" ");
2334 switch (basicType) {
2335 case EbtDouble:
2336 appendStr("double");
2337 break;
2338 case EbtInt:
2339 appendStr("int");
2340 break;
2341 case EbtUint:
2342 appendStr("uint");
2343 break;
2344 case EbtBool:
2345 appendStr("bool");
2346 break;
2347 case EbtFloat:
2348 appendStr("float");
2349 break;
2350 default:
2351 appendStr("unexpected");
2352 break;
2353 }
2354 }
2355 if (name.length() > 0) {
2356 appendStr(" ");
2357 appendStr(name.c_str());
2358 }
2359 if (isArray()) {
2360 for (int i = 0; i < (int)arraySizes->getNumDims(); ++i) {
2361 int size = arraySizes->getDimSize(i);
2362 if (size == UnsizedArraySize && i == 0 && arraySizes->isVariablyIndexed())
2363 appendStr("[]");
2364 else {
2365 if (size == UnsizedArraySize) {
2366 appendStr("[");
2367 if (i == 0)
2368 appendInt(arraySizes->getImplicitSize());
2369 appendStr("]");
2370 }
2371 else {
2372 appendStr("[");
2373 appendInt(arraySizes->getDimSize(i));
2374 appendStr("]");
2375 }
2376 }
2377 }
2378 }
2379 }
2380 else {
2381 if (isArray()) {
2382 for (int i = 0; i < (int)arraySizes->getNumDims(); ++i) {
2383 int size = arraySizes->getDimSize(i);
2384 if (size == UnsizedArraySize && i == 0 && arraySizes->isVariablyIndexed())
2385 appendStr(" runtime-sized array of");
2386 else {
2387 if (size == UnsizedArraySize) {
2388 appendStr(" unsized");
2389 if (i == 0) {
2390 appendStr(" ");
2391 appendInt(arraySizes->getImplicitSize());
2392 }
2393 }
2394 else {
2395 appendStr(" ");
2396 appendInt(arraySizes->getDimSize(i));
2397 }
2398 appendStr("-element array of");
2399 }
2400 }
2401 }
2402 if (isParameterized()) {
2403 if (isCoopMatKHR()) {
2404 appendStr(" ");
2405 appendStr("coopmat");
2406 }
2407
2408 appendStr("<");
2409 for (int i = 0; i < (int)typeParameters->arraySizes->getNumDims(); ++i) {
2410 appendInt(typeParameters->arraySizes->getDimSize(i));
2411 if (i != (int)typeParameters->arraySizes->getNumDims() - 1)
2412 appendStr(", ");
2413 }
2414 if (coopmatKHRUseValid) {
2415 appendStr(", ");
2416 appendInt(coopmatKHRuse);
2417 }
2418 appendStr(">");
2419 }
2420 if (getPrecision && qualifier.precision != EpqNone) {
2421 appendStr(" ");
2422 appendStr(getPrecisionQualifierString());
2423 }
2424 if (isMatrix()) {
2425 appendStr(" ");
2426 appendInt(matrixCols);
2427 appendStr("X");
2428 appendInt(matrixRows);
2429 appendStr(" matrix of");
2430 }
2431 else if (isVector()) {
2432 appendStr(" ");
2433 appendInt(vectorSize);
2434 appendStr("-component vector of");
2435 }
2436
2437 appendStr(" ");
2438 typeString.append(getBasicTypeString());
2439
2440 if (qualifier.builtIn != EbvNone) {
2441 appendStr(" ");
2442 appendStr(getBuiltInVariableString());
2443 }
2444
2445 // Add struct/block members
2446 if (isStruct() && structure) {
2447 appendStr("{");
2448 bool hasHiddenMember = true;
2449 for (size_t i = 0; i < structure->size(); ++i) {
2450 if (!(*structure)[i].type->hiddenMember()) {
2451 if (!hasHiddenMember)
2452 appendStr(", ");
2453 typeString.append((*structure)[i].type->getCompleteString());
2454 typeString.append(" ");
2455 typeString.append((*structure)[i].type->getFieldName());
2456 hasHiddenMember = false;
2457 }
2458 }
2459 appendStr("}");
2460 }
2461 }
2462 }
2463
2464 return typeString;
2465 }
2466
getBasicTypeString()2467 TString getBasicTypeString() const
2468 {
2469 if (basicType == EbtSampler)
2470 return sampler.getString();
2471 else
2472 return getBasicString();
2473 }
2474
getStorageQualifierString()2475 const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); }
getBuiltInVariableString()2476 const char* getBuiltInVariableString() const { return GetBuiltInVariableString(qualifier.builtIn); }
getPrecisionQualifierString()2477 const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
2478
getStruct()2479 const TTypeList* getStruct() const { assert(isStruct()); return structure; }
setStruct(TTypeList * s)2480 void setStruct(TTypeList* s) { assert(isStruct()); structure = s; }
getWritableStruct()2481 TTypeList* getWritableStruct() const { assert(isStruct()); return structure; } // This should only be used when known to not be sharing with other threads
setBasicType(const TBasicType & t)2482 void setBasicType(const TBasicType& t) { basicType = t; }
setVectorSize(int s)2483 void setVectorSize(int s) {
2484 assert(s >= 0);
2485 vectorSize = static_cast<uint32_t>(s) & 0b1111;
2486 }
2487
computeNumComponents()2488 int computeNumComponents() const
2489 {
2490 uint32_t components = 0;
2491
2492 if (getBasicType() == EbtStruct || getBasicType() == EbtBlock) {
2493 for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
2494 components += ((*tl).type)->computeNumComponents();
2495 } else if (matrixCols)
2496 components = matrixCols * matrixRows;
2497 else
2498 components = vectorSize;
2499
2500 if (arraySizes != nullptr) {
2501 components *= arraySizes->getCumulativeSize();
2502 }
2503
2504 return static_cast<int>(components);
2505 }
2506
2507 // append this type's mangled name to the passed in 'name'
appendMangledName(TString & name)2508 void appendMangledName(TString& name) const
2509 {
2510 buildMangledName(name);
2511 name += ';' ;
2512 }
2513
2514 // These variables are inconsistently declared inside and outside of gl_PerVertex in glslang right now.
2515 // They are declared inside of 'in gl_PerVertex', but sitting as standalone when they are 'out'puts.
isInconsistentGLPerVertexMember(const TString & name)2516 bool isInconsistentGLPerVertexMember(const TString& name) const
2517 {
2518 if (name == "gl_SecondaryPositionNV" ||
2519 name == "gl_PositionPerViewNV")
2520 return true;
2521 return false;
2522 }
2523
2524
2525 // Do two structure types match? They could be declared independently,
2526 // in different places, but still might satisfy the definition of matching.
2527 // From the spec:
2528 //
2529 // "Structures must have the same name, sequence of type names, and
2530 // type definitions, and member names to be considered the same type.
2531 // This rule applies recursively for nested or embedded types."
2532 //
2533 // If type mismatch in structure, return member indices through lpidx and rpidx.
2534 // If matching members for either block are exhausted, return -1 for exhausted
2535 // block and the index of the unmatched member. Otherwise return {-1,-1}.
2536 //
2537 bool sameStructType(const TType& right, int* lpidx = nullptr, int* rpidx = nullptr) const
2538 {
2539 // Initialize error to general type mismatch.
2540 if (lpidx != nullptr) {
2541 *lpidx = -1;
2542 *rpidx = -1;
2543 }
2544
2545 // Most commonly, they are both nullptr, or the same pointer to the same actual structure
2546 // TODO: Why return true when neither types are structures?
2547 if ((!isStruct() && !right.isStruct()) ||
2548 (isStruct() && right.isStruct() && structure == right.structure))
2549 return true;
2550
2551 if (!isStruct() || !right.isStruct())
2552 return false;
2553
2554 // Structure names have to match
2555 if (*typeName != *right.typeName)
2556 return false;
2557
2558 // There are inconsistencies with how gl_PerVertex is setup. For now ignore those as errors if they
2559 // are known inconsistencies.
2560 bool isGLPerVertex = *typeName == "gl_PerVertex";
2561
2562 // Both being nullptr was caught above, now they both have to be structures of the same number of elements
2563 if (lpidx == nullptr &&
2564 (structure->size() != right.structure->size() && !isGLPerVertex)) {
2565 return false;
2566 }
2567
2568 // Compare the names and types of all the members, which have to match
2569 for (size_t li = 0, ri = 0; li < structure->size() || ri < right.structure->size(); ++li, ++ri) {
2570 if (lpidx != nullptr) {
2571 *lpidx = static_cast<int>(li);
2572 *rpidx = static_cast<int>(ri);
2573 }
2574 if (li < structure->size() && ri < right.structure->size()) {
2575 if ((*structure)[li].type->getFieldName() == (*right.structure)[ri].type->getFieldName()) {
2576 if (*(*structure)[li].type != *(*right.structure)[ri].type)
2577 return false;
2578 } else {
2579 // Skip hidden members
2580 if ((*structure)[li].type->hiddenMember()) {
2581 ri--;
2582 continue;
2583 } else if ((*right.structure)[ri].type->hiddenMember()) {
2584 li--;
2585 continue;
2586 }
2587 // If one of the members is something that's inconsistently declared, skip over it
2588 // for now.
2589 if (isGLPerVertex) {
2590 if (isInconsistentGLPerVertexMember((*structure)[li].type->getFieldName())) {
2591 ri--;
2592 continue;
2593 } else if (isInconsistentGLPerVertexMember((*right.structure)[ri].type->getFieldName())) {
2594 li--;
2595 continue;
2596 }
2597 } else {
2598 return false;
2599 }
2600 }
2601 // If we get here, then there should only be inconsistently declared members left
2602 } else if (li < structure->size()) {
2603 if (!(*structure)[li].type->hiddenMember() && !isInconsistentGLPerVertexMember((*structure)[li].type->getFieldName())) {
2604 if (lpidx != nullptr) {
2605 *rpidx = -1;
2606 }
2607 return false;
2608 }
2609 } else {
2610 if (!(*right.structure)[ri].type->hiddenMember() && !isInconsistentGLPerVertexMember((*right.structure)[ri].type->getFieldName())) {
2611 if (lpidx != nullptr) {
2612 *lpidx = -1;
2613 }
2614 return false;
2615 }
2616 }
2617 }
2618
2619 return true;
2620 }
2621
sameReferenceType(const TType & right)2622 bool sameReferenceType(const TType& right) const
2623 {
2624 if (isReference() != right.isReference())
2625 return false;
2626
2627 if (!isReference() && !right.isReference())
2628 return true;
2629
2630 assert(referentType != nullptr);
2631 assert(right.referentType != nullptr);
2632
2633 if (referentType == right.referentType)
2634 return true;
2635
2636 return *referentType == *right.referentType;
2637 }
2638
2639 // See if two types match, in all aspects except arrayness
2640 // If mismatch in structure members, return member indices in lpidx and rpidx.
2641 bool sameElementType(const TType& right, int* lpidx = nullptr, int* rpidx = nullptr) const
2642 {
2643 if (lpidx != nullptr) {
2644 *lpidx = -1;
2645 *rpidx = -1;
2646 }
2647 return basicType == right.basicType && sameElementShape(right, lpidx, rpidx);
2648 }
2649
2650 // See if two type's arrayness match
sameArrayness(const TType & right)2651 bool sameArrayness(const TType& right) const
2652 {
2653 return ((arraySizes == nullptr && right.arraySizes == nullptr) ||
2654 (arraySizes != nullptr && right.arraySizes != nullptr &&
2655 (*arraySizes == *right.arraySizes ||
2656 (arraySizes->isImplicitlySized() && right.arraySizes->isDefaultImplicitlySized()) ||
2657 (right.arraySizes->isImplicitlySized() && arraySizes->isDefaultImplicitlySized()))));
2658 }
2659
2660 // See if two type's arrayness match in everything except their outer dimension
sameInnerArrayness(const TType & right)2661 bool sameInnerArrayness(const TType& right) const
2662 {
2663 assert(arraySizes != nullptr && right.arraySizes != nullptr);
2664 return arraySizes->sameInnerArrayness(*right.arraySizes);
2665 }
2666
2667 // See if two type's parameters match
sameTypeParameters(const TType & right)2668 bool sameTypeParameters(const TType& right) const
2669 {
2670 return ((typeParameters == nullptr && right.typeParameters == nullptr) ||
2671 (typeParameters != nullptr && right.typeParameters != nullptr && *typeParameters == *right.typeParameters));
2672 }
2673
2674 // See if two type's SPIR-V type contents match
sameSpirvType(const TType & right)2675 bool sameSpirvType(const TType& right) const
2676 {
2677 return ((spirvType == nullptr && right.spirvType == nullptr) ||
2678 (spirvType != nullptr && right.spirvType != nullptr && *spirvType == *right.spirvType));
2679 }
2680
2681 // See if two type's elements match in all ways except basic type
2682 // If mismatch in structure members, return member indices in lpidx and rpidx.
2683 bool sameElementShape(const TType& right, int* lpidx = nullptr, int* rpidx = nullptr) const
2684 {
2685 if (lpidx != nullptr) {
2686 *lpidx = -1;
2687 *rpidx = -1;
2688 }
2689 return ((basicType != EbtSampler && right.basicType != EbtSampler) || sampler == right.sampler) &&
2690 vectorSize == right.vectorSize &&
2691 matrixCols == right.matrixCols &&
2692 matrixRows == right.matrixRows &&
2693 vector1 == right.vector1 &&
2694 isCoopMatNV() == right.isCoopMatNV() &&
2695 isCoopMatKHR() == right.isCoopMatKHR() &&
2696 sameStructType(right, lpidx, rpidx) &&
2697 sameReferenceType(right);
2698 }
2699
2700 // See if a cooperative matrix type parameter with unspecified parameters is
2701 // an OK function parameter
coopMatParameterOK(const TType & right)2702 bool coopMatParameterOK(const TType& right) const
2703 {
2704 if (isCoopMatNV()) {
2705 return right.isCoopMatNV() && (getBasicType() == right.getBasicType()) && typeParameters == nullptr &&
2706 right.typeParameters != nullptr;
2707 }
2708 if (isCoopMatKHR() && right.isCoopMatKHR()) {
2709 return ((getBasicType() == right.getBasicType()) || (getBasicType() == EbtCoopmat) ||
2710 (right.getBasicType() == EbtCoopmat)) &&
2711 typeParameters == nullptr && right.typeParameters != nullptr;
2712 }
2713 return false;
2714 }
2715
sameCoopMatBaseType(const TType & right)2716 bool sameCoopMatBaseType(const TType &right) const {
2717 bool rv = false;
2718
2719 if (isCoopMatNV()) {
2720 rv = isCoopMatNV() && right.isCoopMatNV();
2721 if (getBasicType() == EbtFloat || getBasicType() == EbtFloat16)
2722 rv = right.getBasicType() == EbtFloat || right.getBasicType() == EbtFloat16;
2723 else if (getBasicType() == EbtUint || getBasicType() == EbtUint8 || getBasicType() == EbtUint16)
2724 rv = right.getBasicType() == EbtUint || right.getBasicType() == EbtUint8 || right.getBasicType() == EbtUint16;
2725 else if (getBasicType() == EbtInt || getBasicType() == EbtInt8 || getBasicType() == EbtInt16)
2726 rv = right.getBasicType() == EbtInt || right.getBasicType() == EbtInt8 || right.getBasicType() == EbtInt16;
2727 else
2728 rv = false;
2729 } else if (isCoopMatKHR() && right.isCoopMatKHR()) {
2730 if (getBasicType() == EbtFloat || getBasicType() == EbtFloat16)
2731 rv = right.getBasicType() == EbtFloat || right.getBasicType() == EbtFloat16 || right.getBasicType() == EbtCoopmat;
2732 else if (getBasicType() == EbtUint || getBasicType() == EbtUint8 || getBasicType() == EbtUint16)
2733 rv = right.getBasicType() == EbtUint || right.getBasicType() == EbtUint8 || right.getBasicType() == EbtUint16 || right.getBasicType() == EbtCoopmat;
2734 else if (getBasicType() == EbtInt || getBasicType() == EbtInt8 || getBasicType() == EbtInt16)
2735 rv = right.getBasicType() == EbtInt || right.getBasicType() == EbtInt8 || right.getBasicType() == EbtInt16 || right.getBasicType() == EbtCoopmat;
2736 else
2737 rv = false;
2738 }
2739 return rv;
2740 }
2741
sameCoopMatUse(const TType & right)2742 bool sameCoopMatUse(const TType &right) const {
2743 return coopmatKHRuse == right.coopmatKHRuse;
2744 }
2745
sameCoopMatShapeAndUse(const TType & right)2746 bool sameCoopMatShapeAndUse(const TType &right) const
2747 {
2748 if (!isCoopMat() || !right.isCoopMat() || isCoopMatKHR() != right.isCoopMatKHR())
2749 return false;
2750
2751 if (coopmatKHRuse != right.coopmatKHRuse)
2752 return false;
2753
2754 // Skip bit width type parameter (first array size) for coopmatNV
2755 int firstArrayDimToCompare = isCoopMatNV() ? 1 : 0;
2756 for (int i = firstArrayDimToCompare; i < typeParameters->arraySizes->getNumDims(); ++i) {
2757 if (typeParameters->arraySizes->getDimSize(i) != right.typeParameters->arraySizes->getDimSize(i))
2758 return false;
2759 }
2760 return true;
2761 }
2762
2763 // See if two types match in all ways (just the actual type, not qualification)
2764 bool operator==(const TType& right) const
2765 {
2766 return sameElementType(right) && sameArrayness(right) && sameTypeParameters(right) && sameCoopMatUse(right) && sameSpirvType(right);
2767 }
2768
2769 bool operator!=(const TType& right) const
2770 {
2771 return ! operator==(right);
2772 }
2773
getBufferReferenceAlignment()2774 unsigned int getBufferReferenceAlignment() const
2775 {
2776 if (getBasicType() == glslang::EbtReference) {
2777 return getReferentType()->getQualifier().hasBufferReferenceAlign() ?
2778 (1u << getReferentType()->getQualifier().layoutBufferReferenceAlign) : 16u;
2779 }
2780 return 0;
2781 }
2782
getSpirvType()2783 const TSpirvType& getSpirvType() const { assert(spirvType); return *spirvType; }
2784
2785 protected:
2786 // Require consumer to pick between deep copy and shallow copy.
2787 TType(const TType& type);
2788 TType& operator=(const TType& type);
2789
2790 // Recursively copy a type graph, while preserving the graph-like
2791 // quality. That is, don't make more than one copy of a structure that
2792 // gets reused multiple times in the type graph.
deepCopy(const TType & copyOf,TMap<TTypeList *,TTypeList * > & copiedMap)2793 void deepCopy(const TType& copyOf, TMap<TTypeList*,TTypeList*>& copiedMap)
2794 {
2795 shallowCopy(copyOf);
2796
2797 // GL_EXT_spirv_intrinsics
2798 if (copyOf.qualifier.spirvDecorate) {
2799 qualifier.spirvDecorate = new TSpirvDecorate;
2800 *qualifier.spirvDecorate = *copyOf.qualifier.spirvDecorate;
2801 }
2802
2803 if (copyOf.spirvType) {
2804 spirvType = new TSpirvType;
2805 *spirvType = *copyOf.spirvType;
2806 }
2807
2808 if (copyOf.arraySizes) {
2809 arraySizes = new TArraySizes;
2810 *arraySizes = *copyOf.arraySizes;
2811 }
2812
2813 if (copyOf.typeParameters) {
2814 typeParameters = new TTypeParameters;
2815 typeParameters->arraySizes = new TArraySizes;
2816 *typeParameters->arraySizes = *copyOf.typeParameters->arraySizes;
2817 typeParameters->basicType = copyOf.basicType;
2818 }
2819
2820 if (copyOf.isStruct() && copyOf.structure) {
2821 auto prevCopy = copiedMap.find(copyOf.structure);
2822 if (prevCopy != copiedMap.end())
2823 structure = prevCopy->second;
2824 else {
2825 structure = new TTypeList;
2826 copiedMap[copyOf.structure] = structure;
2827 for (unsigned int i = 0; i < copyOf.structure->size(); ++i) {
2828 TTypeLoc typeLoc;
2829 typeLoc.loc = (*copyOf.structure)[i].loc;
2830 typeLoc.type = new TType();
2831 typeLoc.type->deepCopy(*(*copyOf.structure)[i].type, copiedMap);
2832 structure->push_back(typeLoc);
2833 }
2834 }
2835 }
2836
2837 if (copyOf.fieldName)
2838 fieldName = NewPoolTString(copyOf.fieldName->c_str());
2839 if (copyOf.typeName)
2840 typeName = NewPoolTString(copyOf.typeName->c_str());
2841 }
2842
2843
2844 void buildMangledName(TString&) const;
2845
2846 TBasicType basicType : 8;
2847 uint32_t vectorSize : 4; // 1 means either scalar or 1-component vector; see vector1 to disambiguate.
2848 uint32_t matrixCols : 4;
2849 uint32_t matrixRows : 4;
2850 bool vector1 : 1; // Backward-compatible tracking of a 1-component vector distinguished from a scalar.
2851 // GLSL 4.5 never has a 1-component vector; so this will always be false until such
2852 // functionality is added.
2853 // HLSL does have a 1-component vectors, so this will be true to disambiguate
2854 // from a scalar.
2855 bool coopmatNV : 1;
2856 bool coopmatKHR : 1;
2857 uint32_t coopmatKHRuse : 3; // Accepts one of three values: 0, 1, 2 (gl_MatrixUseA, gl_MatrixUseB, gl_MatrixUseAccumulator)
2858 bool coopmatKHRUseValid : 1; // True if coopmatKHRuse has been set
2859 TQualifier qualifier;
2860
2861 TArraySizes* arraySizes; // nullptr unless an array; can be shared across types
2862 // A type can't be both a structure (EbtStruct/EbtBlock) and a reference (EbtReference), so
2863 // conserve space by making these a union
2864 union {
2865 TTypeList* structure; // invalid unless this is a struct; can be shared across types
2866 TType *referentType; // invalid unless this is an EbtReference
2867 };
2868 TString *fieldName; // for structure field names
2869 TString *typeName; // for structure type name
2870 TSampler sampler;
2871 TTypeParameters *typeParameters;// nullptr unless a parameterized type; can be shared across types
2872 TSpirvType* spirvType; // SPIR-V type defined by spirv_type directive
2873 };
2874
2875 } // end namespace glslang
2876
2877 #endif // _TYPES_INCLUDED_
2878