diff options
Diffstat (limited to 'chromium/third_party/glslang/src/glslang/Include/Types.h')
-rw-r--r-- | chromium/third_party/glslang/src/glslang/Include/Types.h | 1714 |
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_ |