summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/glslang/src/glslang/Include/Types.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/glslang/src/glslang/Include/Types.h')
-rw-r--r--chromium/third_party/glslang/src/glslang/Include/Types.h1714
1 files changed, 1714 insertions, 0 deletions
diff --git a/chromium/third_party/glslang/src/glslang/Include/Types.h b/chromium/third_party/glslang/src/glslang/Include/Types.h
new file mode 100644
index 00000000000..e37c77cdb78
--- /dev/null
+++ b/chromium/third_party/glslang/src/glslang/Include/Types.h
@@ -0,0 +1,1714 @@
+//
+//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
+//Copyright (C) 2012-2016 LunarG, Inc.
+//Copyright (C) 2015-2016 Google, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _TYPES_INCLUDED
+#define _TYPES_INCLUDED
+
+#include "../Include/Common.h"
+#include "../Include/BaseTypes.h"
+#include "../Public/ShaderLang.h"
+#include "arrays.h"
+
+namespace glslang {
+
+const int GlslangMaxTypeLength = 200; // TODO: need to print block/struct one member per line, so this can stay bounded
+
+const char* const AnonymousPrefix = "anon@"; // for something like a block whose members can be directly accessed
+inline bool IsAnonymous(const TString& name)
+{
+ return name.compare(0, 5, AnonymousPrefix) == 0;
+}
+
+//
+// Details within a sampler type
+//
+enum TSamplerDim {
+ EsdNone,
+ Esd1D,
+ Esd2D,
+ Esd3D,
+ EsdCube,
+ EsdRect,
+ EsdBuffer,
+ EsdSubpass, // goes only with non-sampled image (image is true)
+ EsdNumDims
+};
+
+struct TSampler { // misnomer now; includes images, textures without sampler, and textures with sampler
+ TBasicType type : 8; // type returned by sampler
+ TSamplerDim dim : 8;
+ bool arrayed : 1;
+ bool shadow : 1;
+ bool ms : 1;
+ bool image : 1; // image, combined should be false
+ bool combined : 1; // true means texture is combined with a sampler, false means texture with no sampler
+ bool sampler : 1; // true means a pure sampler, other fields should be clear()
+ bool external : 1; // GL_OES_EGL_image_external
+
+ bool isImage() const { return image && dim != EsdSubpass; }
+ bool isSubpass() const { return dim == EsdSubpass; }
+ bool isCombined() const { return combined; }
+ bool isPureSampler() const { return sampler; }
+ bool isTexture() const { return !sampler && !image; }
+
+ void clear()
+ {
+ type = EbtVoid;
+ dim = EsdNone;
+ arrayed = false;
+ shadow = false;
+ ms = false;
+ image = false;
+ combined = false;
+ sampler = false;
+ external = false;
+ }
+
+ // make a combined sampler and texture
+ void set(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
+ {
+ clear();
+ type = t;
+ dim = d;
+ arrayed = a;
+ shadow = s;
+ ms = m;
+ combined = true;
+ }
+
+ // make an image
+ void setImage(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
+ {
+ clear();
+ type = t;
+ dim = d;
+ arrayed = a;
+ shadow = s;
+ ms = m;
+ image = true;
+ }
+
+ // make a texture with no sampler
+ void setTexture(TBasicType t, TSamplerDim d, bool a = false, bool s = false, bool m = false)
+ {
+ clear();
+ type = t;
+ dim = d;
+ arrayed = a;
+ shadow = s;
+ ms = m;
+ }
+
+ // make a subpass input attachment
+ void setSubpass(TBasicType t, bool m = false)
+ {
+ clear();
+ type = t;
+ image = true;
+ dim = EsdSubpass;
+ ms = m;
+ }
+
+ // make a pure sampler, no texture, no image, nothing combined, the 'sampler' keyword
+ void setPureSampler(bool s)
+ {
+ clear();
+ sampler = true;
+ shadow = s;
+ }
+
+ bool operator==(const TSampler& right) const
+ {
+ return type == right.type &&
+ dim == right.dim &&
+ arrayed == right.arrayed &&
+ shadow == right.shadow &&
+ ms == right.ms &&
+ image == right.image &&
+ combined == right.combined &&
+ sampler == right.sampler &&
+ external == right.external;
+ }
+
+ bool operator!=(const TSampler& right) const
+ {
+ return ! operator==(right);
+ }
+
+ TString getString() const
+ {
+ TString s;
+
+ if (sampler) {
+ s.append("sampler");
+ return s;
+ }
+
+ switch (type) {
+ case EbtFloat: break;
+ case EbtInt: s.append("i"); break;
+ case EbtUint: s.append("u"); break;
+ case EbtInt64: s.append("i64"); break;
+ case EbtUint64: s.append("u64"); break;
+ default: break; // some compilers want this
+ }
+ if (image) {
+ if (dim == EsdSubpass)
+ s.append("subpass");
+ else
+ s.append("image");
+ } else if (combined) {
+ s.append("sampler");
+ } else {
+ s.append("texture");
+ }
+ if (external) {
+ s.append("ExternalOES");
+ return s;
+ }
+ switch (dim) {
+ case Esd1D: s.append("1D"); break;
+ case Esd2D: s.append("2D"); break;
+ case Esd3D: s.append("3D"); break;
+ case EsdCube: s.append("Cube"); break;
+ case EsdRect: s.append("2DRect"); break;
+ case EsdBuffer: s.append("Buffer"); break;
+ case EsdSubpass: s.append("Input"); break;
+ default: break; // some compilers want this
+ }
+ if (ms)
+ s.append("MS");
+ if (arrayed)
+ s.append("Array");
+ if (shadow)
+ s.append("Shadow");
+
+ return s;
+ }
+};
+
+//
+// Need to have association of line numbers to types in a list for building structs.
+//
+class TType;
+struct TTypeLoc {
+ TType* type;
+ TSourceLoc loc;
+};
+typedef TVector<TTypeLoc> TTypeList;
+
+typedef TVector<TString*> TIdentifierList;
+
+//
+// Following are a series of helper enums for managing layouts and qualifiers,
+// used for TPublicType, TType, others.
+//
+
+enum TLayoutPacking {
+ ElpNone,
+ ElpShared, // default, but different than saying nothing
+ ElpStd140,
+ ElpStd430,
+ ElpPacked,
+ ElpCount // If expanding, see bitfield width below
+};
+
+enum TLayoutMatrix {
+ ElmNone,
+ ElmRowMajor,
+ ElmColumnMajor, // default, but different than saying nothing
+ ElmCount // If expanding, see bitfield width below
+};
+
+// Union of geometry shader and tessellation shader geometry types.
+// They don't go into TType, but rather have current state per shader or
+// active parser type (TPublicType).
+enum TLayoutGeometry {
+ ElgNone,
+ ElgPoints,
+ ElgLines,
+ ElgLinesAdjacency,
+ ElgLineStrip,
+ ElgTriangles,
+ ElgTrianglesAdjacency,
+ ElgTriangleStrip,
+ ElgQuads,
+ ElgIsolines,
+};
+
+enum TVertexSpacing {
+ EvsNone,
+ EvsEqual,
+ EvsFractionalEven,
+ EvsFractionalOdd
+};
+
+enum TVertexOrder {
+ EvoNone,
+ EvoCw,
+ EvoCcw
+};
+
+// Note: order matters, as type of format is done by comparison.
+enum TLayoutFormat {
+ ElfNone,
+
+ // Float image
+ ElfRgba32f,
+ ElfRgba16f,
+ ElfR32f,
+ ElfRgba8,
+ ElfRgba8Snorm,
+
+ ElfEsFloatGuard, // to help with comparisons
+
+ ElfRg32f,
+ ElfRg16f,
+ ElfR11fG11fB10f,
+ ElfR16f,
+ ElfRgba16,
+ ElfRgb10A2,
+ ElfRg16,
+ ElfRg8,
+ ElfR16,
+ ElfR8,
+ ElfRgba16Snorm,
+ ElfRg16Snorm,
+ ElfRg8Snorm,
+ ElfR16Snorm,
+ ElfR8Snorm,
+
+ ElfFloatGuard, // to help with comparisons
+
+ // Int image
+ ElfRgba32i,
+ ElfRgba16i,
+ ElfRgba8i,
+ ElfR32i,
+
+ ElfEsIntGuard, // to help with comparisons
+
+ ElfRg32i,
+ ElfRg16i,
+ ElfRg8i,
+ ElfR16i,
+ ElfR8i,
+
+ ElfIntGuard, // to help with comparisons
+
+ // Uint image
+ ElfRgba32ui,
+ ElfRgba16ui,
+ ElfRgba8ui,
+ ElfR32ui,
+
+ ElfEsUintGuard, // to help with comparisons
+
+ ElfRg32ui,
+ ElfRg16ui,
+ ElfRgb10a2ui,
+ ElfRg8ui,
+ ElfR16ui,
+ ElfR8ui,
+
+ ElfCount
+};
+
+enum TLayoutDepth {
+ EldNone,
+ EldAny,
+ EldGreater,
+ EldLess,
+ EldUnchanged,
+
+ EldCount
+};
+
+enum TBlendEquationShift {
+ // No 'EBlendNone':
+ // These are used as bit-shift amounts. A mask of such shifts will have type 'int',
+ // and in that space, 0 means no bits set, or none. In this enum, 0 means (1 << 0), a bit is set.
+ EBlendMultiply,
+ EBlendScreen,
+ EBlendOverlay,
+ EBlendDarken,
+ EBlendLighten,
+ EBlendColordodge,
+ EBlendColorburn,
+ EBlendHardlight,
+ EBlendSoftlight,
+ EBlendDifference,
+ EBlendExclusion,
+ EBlendHslHue,
+ EBlendHslSaturation,
+ EBlendHslColor,
+ EBlendHslLuminosity,
+ EBlendAllEquations,
+
+ EBlendCount
+};
+
+class TQualifier {
+public:
+ static const int layoutNotSet = -1;
+
+ void clear()
+ {
+ precision = EpqNone;
+ invariant = false;
+ noContraction = false;
+ makeTemporary();
+ }
+
+ // drop qualifiers that don't belong in a temporary variable
+ void makeTemporary()
+ {
+ storage = EvqTemporary;
+ builtIn = EbvNone;
+ centroid = false;
+ smooth = false;
+ flat = false;
+ nopersp = false;
+ patch = false;
+ sample = false;
+ coherent = false;
+ volatil = false;
+ restrict = false;
+ readonly = false;
+ writeonly = false;
+ specConstant = false;
+ clearLayout();
+ }
+
+ // Drop just the storage qualification, which perhaps should
+ // never be done, as it is fundamentally inconsistent, but need to
+ // explore what downstream consumers need.
+ // E.g., in a deference, it is an inconsistency between:
+ // A) partially dereferenced resource is still in the storage class it started in
+ // B) partially dereferenced resource is a new temporary object
+ // If A, then nothing should change, if B, then everything should change, but this is half way.
+ void makePartialTemporary()
+ {
+ storage = EvqTemporary;
+ specConstant = false;
+ }
+
+ TStorageQualifier storage : 6;
+ TBuiltInVariable builtIn : 8;
+ TPrecisionQualifier precision : 3;
+ bool invariant : 1; // require canonical treatment for cross-shader invariance
+ bool noContraction: 1; // prevent contraction and reassociation, e.g., for 'precise' keyword, and expressions it affects
+ bool centroid : 1;
+ bool smooth : 1;
+ bool flat : 1;
+ bool nopersp : 1;
+ bool patch : 1;
+ bool sample : 1;
+ bool coherent : 1;
+ bool volatil : 1;
+ bool restrict : 1;
+ bool readonly : 1;
+ bool writeonly : 1;
+ bool specConstant : 1; // having a constant_id is not sufficient: expressions have no id, but are still specConstant
+
+ bool isMemory() const
+ {
+ return coherent || volatil || restrict || readonly || writeonly;
+ }
+ bool isInterpolation() const
+ {
+ return flat || smooth || nopersp;
+ }
+ bool isAuxiliary() const
+ {
+ return centroid || patch || sample;
+ }
+
+ bool isPipeInput() const
+ {
+ switch (storage) {
+ case EvqVaryingIn:
+ case EvqFragCoord:
+ case EvqPointCoord:
+ case EvqFace:
+ case EvqVertexId:
+ case EvqInstanceId:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isPipeOutput() const
+ {
+ switch (storage) {
+ case EvqPosition:
+ case EvqPointSize:
+ case EvqClipVertex:
+ case EvqVaryingOut:
+ case EvqFragColor:
+ case EvqFragDepth:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isParamInput() const
+ {
+ switch (storage) {
+ case EvqIn:
+ case EvqInOut:
+ case EvqConstReadOnly:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isParamOutput() const
+ {
+ switch (storage) {
+ case EvqOut:
+ case EvqInOut:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isUniformOrBuffer() const
+ {
+ switch (storage) {
+ case EvqUniform:
+ case EvqBuffer:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isIo() const
+ {
+ switch (storage) {
+ case EvqUniform:
+ case EvqBuffer:
+ case EvqVaryingIn:
+ case EvqFragCoord:
+ case EvqPointCoord:
+ case EvqFace:
+ case EvqVertexId:
+ case EvqInstanceId:
+ case EvqPosition:
+ case EvqPointSize:
+ case EvqClipVertex:
+ case EvqVaryingOut:
+ case EvqFragColor:
+ case EvqFragDepth:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ // True if this type of IO is supposed to be arrayed with extra level for per-vertex data
+ bool isArrayedIo(EShLanguage language) const
+ {
+ switch (language) {
+ case EShLangGeometry:
+ return isPipeInput();
+ case EShLangTessControl:
+ return ! patch && (isPipeInput() || isPipeOutput());
+ case EShLangTessEvaluation:
+ return ! patch && isPipeInput();
+ default:
+ return false;
+ }
+ }
+
+ // Implementing an embedded layout-qualifier class here, since C++ can't have a real class bitfield
+ void clearLayout()
+ {
+ layoutMatrix = ElmNone;
+ layoutPacking = ElpNone;
+ layoutOffset = layoutNotSet;
+ layoutAlign = layoutNotSet;
+
+ layoutLocation = layoutLocationEnd;
+ layoutComponent = layoutComponentEnd;
+ layoutSet = layoutSetEnd;
+ layoutBinding = layoutBindingEnd;
+ layoutIndex = layoutIndexEnd;
+
+ layoutStream = layoutStreamEnd;
+
+ layoutXfbBuffer = layoutXfbBufferEnd;
+ layoutXfbStride = layoutXfbStrideEnd;
+ layoutXfbOffset = layoutXfbOffsetEnd;
+ layoutAttachment = layoutAttachmentEnd;
+ layoutSpecConstantId = layoutSpecConstantIdEnd;
+
+ layoutFormat = ElfNone;
+
+ layoutPushConstant = false;
+ }
+ bool hasLayout() const
+ {
+ return hasUniformLayout() ||
+ hasAnyLocation() ||
+ hasBinding() ||
+ hasStream() ||
+ hasXfb() ||
+ hasFormat() ||
+ layoutPushConstant;
+ }
+ TLayoutMatrix layoutMatrix : 3;
+ TLayoutPacking layoutPacking : 4;
+ int layoutOffset;
+ int layoutAlign;
+
+ unsigned int layoutLocation :12;
+ static const unsigned int layoutLocationEnd = 0xFFF;
+
+ unsigned int layoutComponent : 3;
+ static const unsigned int layoutComponentEnd = 4;
+
+ unsigned int layoutSet : 7;
+ static const unsigned int layoutSetEnd = 0x3F;
+
+ unsigned int layoutBinding : 8;
+ static const unsigned int layoutBindingEnd = 0xFF;
+
+ unsigned int layoutIndex : 8;
+ static const unsigned int layoutIndexEnd = 0xFF;
+
+ unsigned int layoutStream : 8;
+ static const unsigned int layoutStreamEnd = 0xFF;
+
+ unsigned int layoutXfbBuffer : 4;
+ static const unsigned int layoutXfbBufferEnd = 0xF;
+
+ unsigned int layoutXfbStride : 10;
+ static const unsigned int layoutXfbStrideEnd = 0x3FF;
+
+ unsigned int layoutXfbOffset : 10;
+ static const unsigned int layoutXfbOffsetEnd = 0x3FF;
+
+ unsigned int layoutAttachment : 8; // for input_attachment_index
+ static const unsigned int layoutAttachmentEnd = 0XFF;
+
+ unsigned int layoutSpecConstantId : 11;
+ static const unsigned int layoutSpecConstantIdEnd = 0x7FF;
+
+ TLayoutFormat layoutFormat : 8;
+
+ bool layoutPushConstant;
+
+ bool hasUniformLayout() const
+ {
+ return hasMatrix() ||
+ hasPacking() ||
+ hasOffset() ||
+ hasBinding() ||
+ hasAlign();
+ }
+ bool hasMatrix() const
+ {
+ return layoutMatrix != ElmNone;
+ }
+ bool hasPacking() const
+ {
+ return layoutPacking != ElpNone;
+ }
+ bool hasOffset() const
+ {
+ return layoutOffset != layoutNotSet;
+ }
+ bool hasAlign() const
+ {
+ return layoutAlign != layoutNotSet;
+ }
+ bool hasAnyLocation() const
+ {
+ return hasLocation() ||
+ hasComponent() ||
+ hasIndex();
+ }
+ bool hasLocation() const
+ {
+ return layoutLocation != layoutLocationEnd;
+ }
+ bool hasComponent() const
+ {
+ return layoutComponent != layoutComponentEnd;
+ }
+ bool hasIndex() const
+ {
+ return layoutIndex != layoutIndexEnd;
+ }
+ bool hasSet() const
+ {
+ return layoutSet != layoutSetEnd;
+ }
+ bool hasBinding() const
+ {
+ return layoutBinding != layoutBindingEnd;
+ }
+ bool hasStream() const
+ {
+ return layoutStream != layoutStreamEnd;
+ }
+ bool hasFormat() const
+ {
+ return layoutFormat != ElfNone;
+ }
+ bool hasXfb() const
+ {
+ return hasXfbBuffer() ||
+ hasXfbStride() ||
+ hasXfbOffset();
+ }
+ bool hasXfbBuffer() const
+ {
+ return layoutXfbBuffer != layoutXfbBufferEnd;
+ }
+ bool hasXfbStride() const
+ {
+ return layoutXfbStride != layoutXfbStrideEnd;
+ }
+ bool hasXfbOffset() const
+ {
+ return layoutXfbOffset != layoutXfbOffsetEnd;
+ }
+ bool hasAttachment() const
+ {
+ return layoutAttachment != layoutAttachmentEnd;
+ }
+ bool hasSpecConstantId() const
+ {
+ // Not the same thing as being a specialization constant, this
+ // is just whether or not it was declared with an ID.
+ return layoutSpecConstantId != layoutSpecConstantIdEnd;
+ }
+ bool isSpecConstant() const
+ {
+ // True if type is a specialization constant, whether or not it
+ // had a specialization-constant ID, and false if it is not a
+ // true front-end constant.
+ return specConstant;
+ }
+ bool isFrontEndConstant() const
+ {
+ // True if the front-end knows the final constant value.
+ // This allows front-end constant folding.
+ return storage == EvqConst && ! specConstant;
+ }
+ bool isConstant() const
+ {
+ // True if is either kind of constant; specialization or regular.
+ return isFrontEndConstant() || isSpecConstant();
+ }
+ void makeSpecConstant()
+ {
+ storage = EvqConst;
+ specConstant = true;
+ }
+ static const char* getLayoutPackingString(TLayoutPacking packing)
+ {
+ switch (packing) {
+ case ElpPacked: return "packed";
+ case ElpShared: return "shared";
+ case ElpStd140: return "std140";
+ case ElpStd430: return "std430";
+ default: return "none";
+ }
+ }
+ static const char* getLayoutMatrixString(TLayoutMatrix m)
+ {
+ switch (m) {
+ case ElmColumnMajor: return "column_major";
+ case ElmRowMajor: return "row_major";
+ default: return "none";
+ }
+ }
+ static const char* getLayoutFormatString(TLayoutFormat f)
+ {
+ switch (f) {
+ case ElfRgba32f: return "rgba32f";
+ case ElfRgba16f: return "rgba16f";
+ case ElfRg32f: return "rg32f";
+ case ElfRg16f: return "rg16f";
+ case ElfR11fG11fB10f: return "r11f_g11f_b10f";
+ case ElfR32f: return "r32f";
+ case ElfR16f: return "r16f";
+ case ElfRgba16: return "rgba16";
+ case ElfRgb10A2: return "rgb10_a2";
+ case ElfRgba8: return "rgba8";
+ case ElfRg16: return "rg16";
+ case ElfRg8: return "rg8";
+ case ElfR16: return "r16";
+ case ElfR8: return "r8";
+ case ElfRgba16Snorm: return "rgba16_snorm";
+ case ElfRgba8Snorm: return "rgba8_snorm";
+ case ElfRg16Snorm: return "rg16_snorm";
+ case ElfRg8Snorm: return "rg8_snorm";
+ case ElfR16Snorm: return "r16_snorm";
+ case ElfR8Snorm: return "r8_snorm";
+
+ case ElfRgba32i: return "rgba32i";
+ case ElfRgba16i: return "rgba16i";
+ case ElfRgba8i: return "rgba8i";
+ case ElfRg32i: return "rg32i";
+ case ElfRg16i: return "rg16i";
+ case ElfRg8i: return "rg8i";
+ case ElfR32i: return "r32i";
+ case ElfR16i: return "r16i";
+ case ElfR8i: return "r8i";
+
+ case ElfRgba32ui: return "rgba32ui";
+ case ElfRgba16ui: return "rgba16ui";
+ case ElfRgba8ui: return "rgba8ui";
+ case ElfRg32ui: return "rg32ui";
+ case ElfRg16ui: return "rg16ui";
+ case ElfRgb10a2ui: return "rgb10_a2ui";
+ case ElfRg8ui: return "rg8ui";
+ case ElfR32ui: return "r32ui";
+ case ElfR16ui: return "r16ui";
+ case ElfR8ui: return "r8ui";
+ default: return "none";
+ }
+ }
+ static const char* getLayoutDepthString(TLayoutDepth d)
+ {
+ switch (d) {
+ case EldAny: return "depth_any";
+ case EldGreater: return "depth_greater";
+ case EldLess: return "depth_less";
+ case EldUnchanged: return "depth_unchanged";
+ default: return "none";
+ }
+ }
+ static const char* getBlendEquationString(TBlendEquationShift e)
+ {
+ switch (e) {
+ case EBlendMultiply: return "blend_support_multiply";
+ case EBlendScreen: return "blend_support_screen";
+ case EBlendOverlay: return "blend_support_overlay";
+ case EBlendDarken: return "blend_support_darken";
+ case EBlendLighten: return "blend_support_lighten";
+ case EBlendColordodge: return "blend_support_colordodge";
+ case EBlendColorburn: return "blend_support_colorburn";
+ case EBlendHardlight: return "blend_support_hardlight";
+ case EBlendSoftlight: return "blend_support_softlight";
+ case EBlendDifference: return "blend_support_difference";
+ case EBlendExclusion: return "blend_support_exclusion";
+ case EBlendHslHue: return "blend_support_hsl_hue";
+ case EBlendHslSaturation: return "blend_support_hsl_saturation";
+ case EBlendHslColor: return "blend_support_hsl_color";
+ case EBlendHslLuminosity: return "blend_support_hsl_luminosity";
+ case EBlendAllEquations: return "blend_support_all_equations";
+ default: return "unknown";
+ }
+ }
+ static const char* getGeometryString(TLayoutGeometry geometry)
+ {
+ switch (geometry) {
+ case ElgPoints: return "points";
+ case ElgLines: return "lines";
+ case ElgLinesAdjacency: return "lines_adjacency";
+ case ElgLineStrip: return "line_strip";
+ case ElgTriangles: return "triangles";
+ case ElgTrianglesAdjacency: return "triangles_adjacency";
+ case ElgTriangleStrip: return "triangle_strip";
+ case ElgQuads: return "quads";
+ case ElgIsolines: return "isolines";
+ default: return "none";
+ }
+ }
+ static const char* getVertexSpacingString(TVertexSpacing spacing)
+ {
+ switch (spacing) {
+ case EvsEqual: return "equal_spacing";
+ case EvsFractionalEven: return "fractional_even_spacing";
+ case EvsFractionalOdd: return "fractional_odd_spacing";
+ default: return "none";
+ }
+ }
+ static const char* getVertexOrderString(TVertexOrder order)
+ {
+ switch (order) {
+ case EvoCw: return "cw";
+ case EvoCcw: return "ccw";
+ default: return "none";
+ }
+ }
+ static int mapGeometryToSize(TLayoutGeometry geometry)
+ {
+ switch (geometry) {
+ case ElgPoints: return 1;
+ case ElgLines: return 2;
+ case ElgLinesAdjacency: return 4;
+ case ElgTriangles: return 3;
+ case ElgTrianglesAdjacency: return 6;
+ default: return 0;
+ }
+ }
+};
+
+// Qualifiers that don't need to be keep per object. They have shader scope, not object scope.
+// So, they will not be part of TType, TQualifier, etc.
+struct TShaderQualifiers {
+ TLayoutGeometry geometry; // geometry/tessellation shader in/out primitives
+ bool pixelCenterInteger; // fragment shader
+ bool originUpperLeft; // fragment shader
+ int invocations;
+ int vertices; // both for tessellation "vertices" and geometry "max_vertices"
+ TVertexSpacing spacing;
+ TVertexOrder order;
+ bool pointMode;
+ int localSize[3]; // compute shader
+ int localSizeSpecId[3]; // compute shader specialization id for gl_WorkGroupSize
+ bool earlyFragmentTests; // fragment input
+ TLayoutDepth layoutDepth;
+ bool blendEquation; // true if any blend equation was specified
+
+ void init()
+ {
+ geometry = ElgNone;
+ originUpperLeft = false;
+ pixelCenterInteger = false;
+ invocations = TQualifier::layoutNotSet;
+ vertices = TQualifier::layoutNotSet;
+ spacing = EvsNone;
+ order = EvoNone;
+ pointMode = false;
+ localSize[0] = 1;
+ localSize[1] = 1;
+ localSize[2] = 1;
+ localSizeSpecId[0] = TQualifier::layoutNotSet;
+ localSizeSpecId[1] = TQualifier::layoutNotSet;
+ localSizeSpecId[2] = TQualifier::layoutNotSet;
+ earlyFragmentTests = false;
+ layoutDepth = EldNone;
+ blendEquation = false;
+ }
+
+ // Merge in characteristics from the 'src' qualifier. They can override when
+ // set, but never erase when not set.
+ void merge(const TShaderQualifiers& src)
+ {
+ if (src.geometry != ElgNone)
+ geometry = src.geometry;
+ if (src.pixelCenterInteger)
+ pixelCenterInteger = src.pixelCenterInteger;
+ if (src.originUpperLeft)
+ originUpperLeft = src.originUpperLeft;
+ if (src.invocations != TQualifier::layoutNotSet)
+ invocations = src.invocations;
+ if (src.vertices != TQualifier::layoutNotSet)
+ vertices = src.vertices;
+ if (src.spacing != EvsNone)
+ spacing = src.spacing;
+ if (src.order != EvoNone)
+ order = src.order;
+ if (src.pointMode)
+ pointMode = true;
+ for (int i = 0; i < 3; ++i) {
+ if (src.localSize[i] > 1)
+ localSize[i] = src.localSize[i];
+ }
+ for (int i = 0; i < 3; ++i) {
+ if (src.localSizeSpecId[i] != TQualifier::layoutNotSet)
+ localSizeSpecId[i] = src.localSizeSpecId[i];
+ }
+ if (src.earlyFragmentTests)
+ earlyFragmentTests = true;
+ if (src.layoutDepth)
+ layoutDepth = src.layoutDepth;
+ if (src.blendEquation)
+ blendEquation = src.blendEquation;
+ }
+};
+
+//
+// TPublicType is just temporarily used while parsing and not quite the same
+// information kept per node in TType. Due to the bison stack, it can't have
+// types that it thinks have non-trivial constructors. It should
+// just be used while recognizing the grammar, not anything else.
+// Once enough is known about the situation, the proper information
+// moved into a TType, or the parse context, etc.
+//
+class TPublicType {
+public:
+ TBasicType basicType;
+ TSampler sampler;
+ TQualifier qualifier;
+ TShaderQualifiers shaderQualifiers;
+ int vectorSize : 4;
+ int matrixCols : 4;
+ int matrixRows : 4;
+ TArraySizes* arraySizes;
+ const TType* userDef;
+ TSourceLoc loc;
+
+ void initType(const TSourceLoc& l)
+ {
+ basicType = EbtVoid;
+ vectorSize = 1;
+ matrixRows = 0;
+ matrixCols = 0;
+ arraySizes = nullptr;
+ userDef = nullptr;
+ loc = l;
+ }
+
+ void initQualifiers(bool global = false)
+ {
+ qualifier.clear();
+ if (global)
+ qualifier.storage = EvqGlobal;
+ }
+
+ void init(const TSourceLoc& l, bool global = false)
+ {
+ initType(l);
+ sampler.clear();
+ initQualifiers(global);
+ shaderQualifiers.init();
+ }
+
+ void setVector(int s)
+ {
+ matrixRows = 0;
+ matrixCols = 0;
+ vectorSize = s;
+ }
+
+ void setMatrix(int c, int r)
+ {
+ matrixRows = r;
+ matrixCols = c;
+ vectorSize = 0;
+ }
+
+ bool isScalar() const
+ {
+ return matrixCols == 0 && vectorSize == 1 && arraySizes == nullptr && userDef == nullptr;
+ }
+
+ // "Image" is a superset of "Subpass"
+ bool isImage() const { return basicType == EbtSampler && sampler.isImage(); }
+ bool isSubpass() const { return basicType == EbtSampler && sampler.isSubpass(); }
+};
+
+//
+// Base class for things that have a type.
+//
+class TType {
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
+
+ // for "empty" type (no args) or simple scalar/vector/matrix
+ explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0,
+ bool isVector = false) :
+ basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1),
+ arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+ {
+ sampler.clear();
+ qualifier.clear();
+ qualifier.storage = q;
+ }
+ // for explicit precision qualifier
+ TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0,
+ bool isVector = false) :
+ basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1),
+ arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+ {
+ sampler.clear();
+ qualifier.clear();
+ qualifier.storage = q;
+ qualifier.precision = p;
+ assert(p >= 0 && p <= EpqHigh);
+ }
+ // for turning a TPublicType into a TType, using a shallow copy
+ explicit TType(const TPublicType& p) :
+ basicType(p.basicType),
+ vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false),
+ arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+ {
+ if (basicType == EbtSampler)
+ sampler = p.sampler;
+ else
+ sampler.clear();
+ qualifier = p.qualifier;
+ if (p.userDef) {
+ structure = p.userDef->getWritableStruct(); // public type is short-lived; there are no sharing issues
+ typeName = NewPoolTString(p.userDef->getTypeName().c_str());
+ }
+ }
+ // to efficiently make a dereferenced type
+ // without ever duplicating the outer structure that will be thrown away
+ // and using only shallow copy
+ TType(const TType& type, int derefIndex, bool rowMajor = false)
+ {
+ if (type.isArray()) {
+ shallowCopy(type);
+ if (type.getArraySizes()->getNumDims() == 1) {
+ arraySizes = nullptr;
+ } else {
+ // want our own copy of the array, so we can edit it
+ arraySizes = new TArraySizes;
+ arraySizes->copyDereferenced(*type.arraySizes);
+ }
+ } else if (type.basicType == EbtStruct || type.basicType == EbtBlock) {
+ // do a structure dereference
+ const TTypeList& memberList = *type.getStruct();
+ shallowCopy(*memberList[derefIndex].type);
+ return;
+ } else {
+ // do a vector/matrix dereference
+ shallowCopy(type);
+ if (matrixCols > 0) {
+ // dereference from matrix to vector
+ if (rowMajor)
+ vectorSize = matrixCols;
+ else
+ vectorSize = matrixRows;
+ matrixCols = 0;
+ matrixRows = 0;
+ if (vectorSize == 1)
+ vector1 = true;
+ } else if (isVector()) {
+ // dereference from vector to scalar
+ vectorSize = 1;
+ vector1 = false;
+ }
+ }
+ }
+ // for making structures, ...
+ TType(TTypeList* userDef, const TString& n) :
+ basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
+ arraySizes(nullptr), structure(userDef), fieldName(nullptr)
+ {
+ sampler.clear();
+ qualifier.clear();
+ typeName = NewPoolTString(n.c_str());
+ }
+ // For interface blocks
+ TType(TTypeList* userDef, const TString& n, const TQualifier& q) :
+ basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
+ qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr)
+ {
+ sampler.clear();
+ typeName = NewPoolTString(n.c_str());
+ }
+ virtual ~TType() {}
+
+ // Not for use across pool pops; it will cause multiple instances of TType to point to the same information.
+ // This only works if that information (like a structure's list of types) does not change and
+ // the instances are sharing the same pool.
+ void shallowCopy(const TType& copyOf)
+ {
+ basicType = copyOf.basicType;
+ sampler = copyOf.sampler;
+ qualifier = copyOf.qualifier;
+ vectorSize = copyOf.vectorSize;
+ matrixCols = copyOf.matrixCols;
+ matrixRows = copyOf.matrixRows;
+ vector1 = copyOf.vector1;
+ arraySizes = copyOf.arraySizes; // copying the pointer only, not the contents
+ structure = copyOf.structure;
+ fieldName = copyOf.fieldName;
+ typeName = copyOf.typeName;
+ }
+
+ void deepCopy(const TType& copyOf)
+ {
+ shallowCopy(copyOf);
+
+ if (copyOf.arraySizes) {
+ arraySizes = new TArraySizes;
+ *arraySizes = *copyOf.arraySizes;
+ }
+
+ if (copyOf.structure) {
+ structure = new TTypeList;
+ for (unsigned int i = 0; i < copyOf.structure->size(); ++i) {
+ TTypeLoc typeLoc;
+ typeLoc.loc = (*copyOf.structure)[i].loc;
+ typeLoc.type = new TType();
+ typeLoc.type->deepCopy(*(*copyOf.structure)[i].type);
+ structure->push_back(typeLoc);
+ }
+ }
+
+ if (copyOf.fieldName)
+ fieldName = NewPoolTString(copyOf.fieldName->c_str());
+ if (copyOf.typeName)
+ typeName = NewPoolTString(copyOf.typeName->c_str());
+ }
+
+ TType* clone()
+ {
+ TType *newType = new TType();
+ newType->deepCopy(*this);
+
+ return newType;
+ }
+
+ void makeVector() { vector1 = true; }
+
+ // Merge type from parent, where a parentType is at the beginning of a declaration,
+ // establishing some characteristics for all subsequent names, while this type
+ // is on the individual names.
+ void mergeType(const TPublicType& parentType)
+ {
+ // arrayness is currently the only child aspect that has to be preserved
+ basicType = parentType.basicType;
+ vectorSize = parentType.vectorSize;
+ matrixCols = parentType.matrixCols;
+ matrixRows = parentType.matrixRows;
+ vector1 = false; // TPublicType is only GLSL which so far has no vec1
+ qualifier = parentType.qualifier;
+ sampler = parentType.sampler;
+ if (parentType.arraySizes)
+ newArraySizes(*parentType.arraySizes);
+ if (parentType.userDef) {
+ structure = parentType.userDef->getWritableStruct();
+ setTypeName(parentType.userDef->getTypeName());
+ }
+ }
+
+ virtual void hideMember() { basicType = EbtVoid; vectorSize = 1; }
+ virtual bool hiddenMember() const { return basicType == EbtVoid; }
+
+ virtual void setTypeName(const TString& n) { typeName = NewPoolTString(n.c_str()); }
+ virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); }
+ virtual const TString& getTypeName() const
+ {
+ assert(typeName);
+ return *typeName;
+ }
+
+ virtual const TString& getFieldName() const
+ {
+ assert(fieldName);
+ return *fieldName;
+ }
+
+ virtual TBasicType getBasicType() const { return basicType; }
+ virtual const TSampler& getSampler() const { return sampler; }
+
+ virtual TQualifier& getQualifier() { return qualifier; }
+ virtual const TQualifier& getQualifier() const { return qualifier; }
+
+ virtual int getVectorSize() const { return vectorSize; } // returns 1 for either scalar or vector of size 1, valid for both
+ virtual int getMatrixCols() const { return matrixCols; }
+ virtual int getMatrixRows() const { return matrixRows; }
+ virtual int getOuterArraySize() const { return arraySizes->getOuterSize(); }
+ virtual TIntermTyped* getOuterArrayNode() const { return arraySizes->getOuterNode(); }
+ virtual int getCumulativeArraySize() const { return arraySizes->getCumulativeSize(); }
+ virtual bool isArrayOfArrays() const { return arraySizes != nullptr && arraySizes->getNumDims() > 1; }
+ virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); }
+ virtual const TArraySizes* getArraySizes() const { return arraySizes; }
+ virtual TArraySizes& getArraySizes() { assert(arraySizes != nullptr); return *arraySizes; }
+
+ virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); }
+ virtual bool isVector() const { return vectorSize > 1 || vector1; }
+ virtual bool isMatrix() const { return matrixCols ? true : false; }
+ virtual bool isArray() const { return arraySizes != nullptr; }
+ virtual bool isExplicitlySizedArray() const { return isArray() && getOuterArraySize() != UnsizedArraySize; }
+ virtual bool isImplicitlySizedArray() const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage != EvqBuffer; }
+ virtual bool isRuntimeSizedArray() const { return isArray() && getOuterArraySize() == UnsizedArraySize && qualifier.storage == EvqBuffer; }
+ virtual bool isStruct() const { return structure != nullptr; }
+ virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble; }
+
+ virtual bool isOpaque() const { return basicType == EbtSampler || basicType == EbtAtomicUint; }
+
+ // "Image" is a superset of "Subpass"
+ virtual bool isImage() const { return basicType == EbtSampler && getSampler().isImage(); }
+ virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); }
+
+ // Recursively checks if the type contains the given basic type
+ virtual bool containsBasicType(TBasicType checkType) const
+ {
+ if (basicType == checkType)
+ return true;
+ if (! structure)
+ return false;
+ for (unsigned int i = 0; i < structure->size(); ++i) {
+ if ((*structure)[i].type->containsBasicType(checkType))
+ return true;
+ }
+ return false;
+ }
+
+ // Recursively check the structure for any arrays, needed for some error checks
+ virtual bool containsArray() const
+ {
+ if (isArray())
+ return true;
+ if (structure == nullptr)
+ return false;
+ for (unsigned int i = 0; i < structure->size(); ++i) {
+ if ((*structure)[i].type->containsArray())
+ return true;
+ }
+ return false;
+ }
+
+ // Check the structure for any structures, needed for some error checks
+ virtual bool containsStructure() const
+ {
+ if (structure == nullptr)
+ return false;
+ for (unsigned int i = 0; i < structure->size(); ++i) {
+ if ((*structure)[i].type->structure)
+ return true;
+ }
+ return false;
+ }
+
+ // Recursively check the structure for any implicitly-sized arrays, needed for triggering a copyUp().
+ virtual bool containsImplicitlySizedArray() const
+ {
+ if (isImplicitlySizedArray())
+ return true;
+ if (structure == nullptr)
+ return false;
+ for (unsigned int i = 0; i < structure->size(); ++i) {
+ if ((*structure)[i].type->containsImplicitlySizedArray())
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool containsOpaque() const
+ {
+ if (isOpaque())
+ return true;
+ if (! structure)
+ return false;
+ for (unsigned int i = 0; i < structure->size(); ++i) {
+ if ((*structure)[i].type->containsOpaque())
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool containsNonOpaque() const
+ {
+ // list all non-opaque types
+ switch (basicType) {
+ case EbtVoid:
+ case EbtFloat:
+ case EbtDouble:
+ case EbtInt:
+ case EbtUint:
+ case EbtInt64:
+ case EbtUint64:
+ case EbtBool:
+ return true;
+ default:
+ break;
+ }
+ if (! structure)
+ return false;
+ for (unsigned int i = 0; i < structure->size(); ++i) {
+ if ((*structure)[i].type->containsNonOpaque())
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool containsSpecializationSize() const
+ {
+ if (isArray() && arraySizes->containsNode())
+ return true;
+ if (! structure)
+ return false;
+ for (unsigned int i = 0; i < structure->size(); ++i) {
+ if ((*structure)[i].type->containsSpecializationSize())
+ return true;
+ }
+ return false;
+ }
+
+ // Array editing methods. Array descriptors can be shared across
+ // type instances. This allows all uses of the same array
+ // to be updated at once. E.g., all nodes can be explicitly sized
+ // by tracking and correcting one implicit size. Or, all nodes
+ // can get the explicit size on a redeclaration that gives size.
+ //
+ // N.B.: Don't share with the shared symbol tables (symbols are
+ // marked as isReadOnly(). Such symbols with arrays that will be
+ // edited need to copyUp() on first use, so that
+ // A) the edits don't effect the shared symbol table, and
+ // B) the edits are shared across all users.
+ void updateArraySizes(const TType& type)
+ {
+ // For when we may already be sharing existing array descriptors,
+ // keeping the pointers the same, just updating the contents.
+ assert(arraySizes != nullptr);
+ assert(type.arraySizes != nullptr);
+ *arraySizes = *type.arraySizes;
+ }
+ void newArraySizes(const TArraySizes& s)
+ {
+ // For setting a fresh new set of array sizes, not yet worrying about sharing.
+ arraySizes = new TArraySizes;
+ *arraySizes = s;
+ }
+ void clearArraySizes()
+ {
+ arraySizes = 0;
+ }
+ void addArrayOuterSizes(const TArraySizes& s)
+ {
+ if (arraySizes == nullptr)
+ newArraySizes(s);
+ else
+ arraySizes->addOuterSizes(s);
+ }
+ void changeOuterArraySize(int s) { arraySizes->changeOuterSize(s); }
+ void setImplicitArraySize(int s) { arraySizes->setImplicitSize(s); }
+
+ // Recursively make the implicit array size the explicit array size, through the type tree.
+ void adoptImplicitArraySizes()
+ {
+ if (isImplicitlySizedArray())
+ changeOuterArraySize(getImplicitArraySize());
+ if (isStruct()) {
+ for (int i = 0; i < (int)structure->size(); ++i)
+ (*structure)[i].type->adoptImplicitArraySizes();
+ }
+ }
+
+ const char* getBasicString() const
+ {
+ return TType::getBasicString(basicType);
+ }
+
+ static const char* getBasicString(TBasicType t)
+ {
+ switch (t) {
+ case EbtVoid: return "void";
+ case EbtFloat: return "float";
+ case EbtDouble: return "double";
+ case EbtInt: return "int";
+ case EbtUint: return "uint";
+ case EbtInt64: return "int64_t";
+ case EbtUint64: return "uint64_t";
+ case EbtBool: return "bool";
+ case EbtAtomicUint: return "atomic_uint";
+ case EbtSampler: return "sampler/image";
+ case EbtStruct: return "structure";
+ case EbtBlock: return "block";
+ default: return "unknown type";
+ }
+ }
+
+ TString getCompleteString() const
+ {
+ const int maxSize = GlslangMaxTypeLength;
+ char buf[maxSize];
+ char* p = &buf[0];
+ char* end = &buf[maxSize];
+
+ if (qualifier.hasLayout()) {
+ // To reduce noise, skip this if the only layout is an xfb_buffer
+ // with no triggering xfb_offset.
+ TQualifier noXfbBuffer = qualifier;
+ noXfbBuffer.layoutXfbBuffer = TQualifier::layoutXfbBufferEnd;
+ if (noXfbBuffer.hasLayout()) {
+ p += snprintf(p, end - p, "layout(");
+ if (qualifier.hasAnyLocation()) {
+ p += snprintf(p, end - p, "location=%d ", qualifier.layoutLocation);
+ if (qualifier.hasComponent())
+ p += snprintf(p, end - p, "component=%d ", qualifier.layoutComponent);
+ if (qualifier.hasIndex())
+ p += snprintf(p, end - p, "index=%d ", qualifier.layoutIndex);
+ }
+ if (qualifier.hasSet())
+ p += snprintf(p, end - p, "set=%d ", qualifier.layoutSet);
+ if (qualifier.hasBinding())
+ p += snprintf(p, end - p, "binding=%d ", qualifier.layoutBinding);
+ if (qualifier.hasStream())
+ p += snprintf(p, end - p, "stream=%d ", qualifier.layoutStream);
+ if (qualifier.hasMatrix())
+ p += snprintf(p, end - p, "%s ", TQualifier::getLayoutMatrixString(qualifier.layoutMatrix));
+ if (qualifier.hasPacking())
+ p += snprintf(p, end - p, "%s ", TQualifier::getLayoutPackingString(qualifier.layoutPacking));
+ if (qualifier.hasOffset())
+ p += snprintf(p, end - p, "offset=%d ", qualifier.layoutOffset);
+ if (qualifier.hasAlign())
+ p += snprintf(p, end - p, "align=%d ", qualifier.layoutAlign);
+ if (qualifier.hasFormat())
+ p += snprintf(p, end - p, "%s ", TQualifier::getLayoutFormatString(qualifier.layoutFormat));
+ if (qualifier.hasXfbBuffer() && qualifier.hasXfbOffset())
+ p += snprintf(p, end - p, "xfb_buffer=%d ", qualifier.layoutXfbBuffer);
+ if (qualifier.hasXfbOffset())
+ p += snprintf(p, end - p, "xfb_offset=%d ", qualifier.layoutXfbOffset);
+ if (qualifier.hasXfbStride())
+ p += snprintf(p, end - p, "xfb_stride=%d ", qualifier.layoutXfbStride);
+ if (qualifier.hasAttachment())
+ p += snprintf(p, end - p, "input_attachment_index=%d ", qualifier.layoutAttachment);
+ if (qualifier.hasSpecConstantId())
+ p += snprintf(p, end - p, "constant_id=%d ", qualifier.layoutSpecConstantId);
+ if (qualifier.layoutPushConstant)
+ p += snprintf(p, end - p, "push_constant ");
+ p += snprintf(p, end - p, ") ");
+ }
+ }
+
+ if (qualifier.invariant)
+ p += snprintf(p, end - p, "invariant ");
+ if (qualifier.noContraction)
+ p += snprintf(p, end - p, "noContraction ");
+ if (qualifier.centroid)
+ p += snprintf(p, end - p, "centroid ");
+ if (qualifier.smooth)
+ p += snprintf(p, end - p, "smooth ");
+ if (qualifier.flat)
+ p += snprintf(p, end - p, "flat ");
+ if (qualifier.nopersp)
+ p += snprintf(p, end - p, "noperspective ");
+ if (qualifier.patch)
+ p += snprintf(p, end - p, "patch ");
+ if (qualifier.sample)
+ p += snprintf(p, end - p, "sample ");
+ if (qualifier.coherent)
+ p += snprintf(p, end - p, "coherent ");
+ if (qualifier.volatil)
+ p += snprintf(p, end - p, "volatile ");
+ if (qualifier.restrict)
+ p += snprintf(p, end - p, "restrict ");
+ if (qualifier.readonly)
+ p += snprintf(p, end - p, "readonly ");
+ if (qualifier.writeonly)
+ p += snprintf(p, end - p, "writeonly ");
+ if (qualifier.specConstant)
+ p += snprintf(p, end - p, "specialization-constant ");
+ p += snprintf(p, end - p, "%s ", getStorageQualifierString());
+ if (isArray()) {
+ for(int i = 0; i < (int)arraySizes->getNumDims(); ++i) {
+ int size = arraySizes->getDimSize(i);
+ if (size == 0)
+ p += snprintf(p, end - p, "implicitly-sized array of ");
+ else
+ p += snprintf(p, end - p, "%d-element array of ", arraySizes->getDimSize(i));
+ }
+ }
+ if (qualifier.precision != EpqNone)
+ p += snprintf(p, end - p, "%s ", getPrecisionQualifierString());
+ if (isMatrix())
+ p += snprintf(p, end - p, "%dX%d matrix of ", matrixCols, matrixRows);
+ else if (isVector())
+ p += snprintf(p, end - p, "%d-component vector of ", vectorSize);
+
+ *p = 0;
+ TString s(buf);
+ s.append(getBasicTypeString());
+
+ if (qualifier.builtIn != EbvNone) {
+ s.append(" ");
+ s.append(getBuiltInVariableString());
+ }
+
+ // Add struct/block members
+ if (structure) {
+ s.append("{");
+ for (size_t i = 0; i < structure->size(); ++i) {
+ if (! (*structure)[i].type->hiddenMember()) {
+ s.append((*structure)[i].type->getCompleteString());
+ s.append(" ");
+ s.append((*structure)[i].type->getFieldName());
+ if (i < structure->size() - 1)
+ s.append(", ");
+ }
+ }
+ s.append("}");
+ }
+
+ return s;
+ }
+
+ TString getBasicTypeString() const
+ {
+ if (basicType == EbtSampler)
+ return sampler.getString();
+ else
+ return getBasicString();
+ }
+
+ const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); }
+ const char* getBuiltInVariableString() const { return GetBuiltInVariableString(qualifier.builtIn); }
+ const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
+ const TTypeList* getStruct() const { return structure; }
+ TTypeList* getWritableStruct() const { return structure; } // This should only be used when known to not be sharing with other threads
+
+ int computeNumComponents() const
+ {
+ int components = 0;
+
+ if (getBasicType() == EbtStruct || getBasicType() == EbtBlock) {
+ for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
+ components += ((*tl).type)->computeNumComponents();
+ } else if (matrixCols)
+ components = matrixCols * matrixRows;
+ else
+ components = vectorSize;
+
+ if (arraySizes != nullptr) {
+ components *= arraySizes->getCumulativeSize();
+ }
+
+ return components;
+ }
+
+ // append this type's mangled name to the passed in 'name'
+ void appendMangledName(TString& name)
+ {
+ buildMangledName(name);
+ name += ';' ;
+ }
+
+ // Do two structure types match? They could be declared independently,
+ // in different places, but still might satisfy the definition of matching.
+ // From the spec:
+ //
+ // "Structures must have the same name, sequence of type names, and
+ // type definitions, and member names to be considered the same type.
+ // This rule applies recursively for nested or embedded types."
+ //
+ bool sameStructType(const TType& right) const
+ {
+ // Most commonly, they are both nullptr, or the same pointer to the same actual structure
+ if (structure == right.structure)
+ return true;
+
+ // Both being nullptr was caught above, now they both have to be structures of the same number of elements
+ if (structure == nullptr || right.structure == nullptr ||
+ structure->size() != right.structure->size())
+ return false;
+
+ // Structure names have to match
+ if (*typeName != *right.typeName)
+ return false;
+
+ // Compare the names and types of all the members, which have to match
+ for (unsigned int i = 0; i < structure->size(); ++i) {
+ if ((*structure)[i].type->getFieldName() != (*right.structure)[i].type->getFieldName())
+ return false;
+
+ if (*(*structure)[i].type != *(*right.structure)[i].type)
+ return false;
+ }
+
+ return true;
+ }
+
+ // See if two types match, in all aspects except arrayness
+ bool sameElementType(const TType& right) const
+ {
+ return basicType == right.basicType && sameElementShape(right);
+ }
+
+ // See if two type's arrayness match
+ bool sameArrayness(const TType& right) const
+ {
+ return ((arraySizes == nullptr && right.arraySizes == nullptr) ||
+ (arraySizes != nullptr && right.arraySizes != nullptr && *arraySizes == *right.arraySizes));
+ }
+
+ // See if two type's arrayness match in everything except their outer dimension
+ bool sameInnerArrayness(const TType& right) const
+ {
+ assert(arraySizes != nullptr && right.arraySizes != nullptr);
+ return arraySizes->sameInnerArrayness(*right.arraySizes);
+ }
+
+ // See if two type's elements match in all ways except basic type
+ bool sameElementShape(const TType& right) const
+ {
+ return sampler == right.sampler &&
+ vectorSize == right.vectorSize &&
+ matrixCols == right.matrixCols &&
+ matrixRows == right.matrixRows &&
+ vector1 == right.vector1 &&
+ sameStructType(right);
+ }
+
+ // See if two types match in all ways (just the actual type, not qualification)
+ bool operator==(const TType& right) const
+ {
+ return sameElementType(right) && sameArrayness(right);
+ }
+
+ bool operator!=(const TType& right) const
+ {
+ return ! operator==(right);
+ }
+
+protected:
+ // Require consumer to pick between deep copy and shallow copy.
+ TType(const TType& type);
+ TType& operator=(const TType& type);
+
+ void buildMangledName(TString&);
+
+ TBasicType basicType : 8;
+ int vectorSize : 4; // 1 means either scalar or 1-component vector; see vector1 to disambiguate.
+ int matrixCols : 4;
+ int matrixRows : 4;
+ bool vector1 : 1; // Backward-compatible tracking of a 1-component vector distinguished from a scalar.
+ // GLSL 4.5 never has a 1-component vector; so this will always be false until such
+ // functionality is added.
+ // HLSL does have a 1-component vectors, so this will be true to disambiguate
+ // from a scalar.
+ TSampler sampler;
+ TQualifier qualifier;
+
+ TArraySizes* arraySizes; // nullptr unless an array; can be shared across types
+ TTypeList* structure; // nullptr unless this is a struct; can be shared across types
+ TString *fieldName; // for structure field names
+ TString *typeName; // for structure type name
+};
+
+} // end namespace glslang
+
+#endif // _TYPES_INCLUDED_