Browse Source

Update glslang

Alex Szpakowski 6 years ago
parent
commit
ee77eef9a9
35 changed files with 3276 additions and 1441 deletions
  1. 2 0
      src/libraries/glslang/glslang/Include/BaseTypes.h
  2. 4 2
      src/libraries/glslang/glslang/Include/Common.h
  3. 210 27
      src/libraries/glslang/glslang/Include/Types.h
  4. 5 3
      src/libraries/glslang/glslang/Include/arrays.h
  5. 46 2
      src/libraries/glslang/glslang/Include/intermediate.h
  6. 1 1
      src/libraries/glslang/glslang/Include/revision.h
  7. 7 1
      src/libraries/glslang/glslang/MachineIndependent/Constant.cpp
  8. 146 33
      src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp
  9. 190 4
      src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp
  10. 4 0
      src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp
  11. 407 89
      src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp
  12. 5 4
      src/libraries/glslang/glslang/MachineIndependent/ParseHelper.h
  13. 24 3
      src/libraries/glslang/glslang/MachineIndependent/Scan.cpp
  14. 2 1
      src/libraries/glslang/glslang/MachineIndependent/ScanContext.h
  15. 55 26
      src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp
  16. 72 25
      src/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp
  17. 79 33
      src/libraries/glslang/glslang/MachineIndependent/SymbolTable.h
  18. 21 1
      src/libraries/glslang/glslang/MachineIndependent/Versions.cpp
  19. 6 1
      src/libraries/glslang/glslang/MachineIndependent/Versions.h
  20. 99 13
      src/libraries/glslang/glslang/MachineIndependent/attribute.cpp
  21. 6 1
      src/libraries/glslang/glslang/MachineIndependent/attribute.h
  22. 518 511
      src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp
  23. 233 230
      src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h
  24. 22 3
      src/libraries/glslang/glslang/MachineIndependent/intermOut.cpp
  25. 172 22
      src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp
  26. 75 8
      src/libraries/glslang/glslang/MachineIndependent/localintermediate.h
  27. 1 0
      src/libraries/glslang/glslang/MachineIndependent/parseVersions.h
  28. 36 19
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp
  29. 81 15
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h
  30. 82 59
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp
  31. 31 152
      src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp
  32. 424 76
      src/libraries/glslang/glslang/MachineIndependent/reflection.cpp
  33. 73 49
      src/libraries/glslang/glslang/MachineIndependent/reflection.h
  34. 4 1
      src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp
  35. 133 26
      src/libraries/glslang/glslang/Public/ShaderLang.h

+ 2 - 0
src/libraries/glslang/glslang/Include/BaseTypes.h

@@ -66,6 +66,8 @@ enum TBasicType {
     EbtAccStructNV,
     EbtAccStructNV,
 #endif
 #endif
 
 
+    EbtReference,
+
     // HLSL types that live only temporarily.
     // HLSL types that live only temporarily.
     EbtString,
     EbtString,
 
 

+ 4 - 2
src/libraries/glslang/glslang/Include/Common.h

@@ -38,7 +38,7 @@
 #define _COMMON_INCLUDED_
 #define _COMMON_INCLUDED_
 
 
 
 
-#if defined(__ANDROID__) || _MSC_VER < 1700
+#if defined(__ANDROID__) || (defined(_MSC_VER) && _MSC_VER < 1700)
 #include <sstream>
 #include <sstream>
 namespace std {
 namespace std {
 template<typename T>
 template<typename T>
@@ -102,6 +102,7 @@ std::string to_string(const T& val) {
 #include <algorithm>
 #include <algorithm>
 #include <string>
 #include <string>
 #include <cstdio>
 #include <cstdio>
+#include <cstdlib>
 #include <cassert>
 #include <cassert>
 
 
 #include "PoolAlloc.h"
 #include "PoolAlloc.h"
@@ -250,7 +251,8 @@ struct TSourceLoc {
             return nullptr;
             return nullptr;
         return name->c_str();
         return name->c_str();
     }
     }
-    TString* name; // descriptive name for this string
+    const char* getFilenameStr() const { return name == nullptr ? "" : name->c_str(); }
+    TString* name; // descriptive name for this string, when a textual name is available, otherwise nullptr
     int string;
     int string;
     int line;
     int line;
     int column;
     int column;

+ 210 - 27
src/libraries/glslang/glslang/Include/Types.h

@@ -81,6 +81,7 @@ struct TSampler {   // misnomer now; includes images, textures without sampler,
     bool   combined : 1;  // true means texture is combined with a sampler, false means texture with no sampler
     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    sampler : 1;  // true means a pure sampler, other fields should be clear()
     bool   external : 1;  // GL_OES_EGL_image_external
     bool   external : 1;  // GL_OES_EGL_image_external
+    bool        yuv : 1;  // GL_EXT_YUV_target
     unsigned int vectorSize : 3;  // vector return type size.
     unsigned int vectorSize : 3;  // vector return type size.
 
 
     // Some languages support structures as sample results.  Storing the whole structure in the
     // Some languages support structures as sample results.  Storing the whole structure in the
@@ -116,6 +117,7 @@ struct TSampler {   // misnomer now; includes images, textures without sampler,
         combined = false;
         combined = false;
         sampler = false;
         sampler = false;
         external = false;
         external = false;
+        yuv = false;
         structReturnIndex = noReturnStruct;
         structReturnIndex = noReturnStruct;
 
 
         // by default, returns a single vec4;
         // by default, returns a single vec4;
@@ -186,6 +188,7 @@ struct TSampler {   // misnomer now; includes images, textures without sampler,
                 combined == right.combined &&
                 combined == right.combined &&
                  sampler == right.sampler &&
                  sampler == right.sampler &&
                 external == right.external &&
                 external == right.external &&
+                     yuv == right.yuv &&
               vectorSize == right.vectorSize &&
               vectorSize == right.vectorSize &&
        structReturnIndex == right.structReturnIndex;            
        structReturnIndex == right.structReturnIndex;            
     }
     }
@@ -233,6 +236,9 @@ struct TSampler {   // misnomer now; includes images, textures without sampler,
             s.append("ExternalOES");
             s.append("ExternalOES");
             return s;
             return s;
         }
         }
+        if (yuv) {
+            return "__" + s + "External2DY2YEXT";
+        }
         switch (dim) {
         switch (dim) {
         case Esd1D:      s.append("1D");      break;
         case Esd1D:      s.append("1D");      break;
         case Esd2D:      s.append("2D");      break;
         case Esd2D:      s.append("2D");      break;
@@ -537,6 +543,11 @@ public:
     {
     {
         return subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || restrict || readonly || writeonly;
         return subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || volatil || restrict || readonly || writeonly;
     }
     }
+    bool bufferReferenceNeedsVulkanMemoryModel() const
+    {
+        // include qualifiers that map to load/store availability/visibility/nonprivate memory access operands
+        return subgroupcoherent || workgroupcoherent || queuefamilycoherent || devicecoherent || coherent || nonprivate;
+    }
 
 
     bool isInterpolation() const
     bool isInterpolation() const
     {
     {
@@ -721,6 +732,7 @@ public:
         clearUniformLayout();
         clearUniformLayout();
 
 
         layoutPushConstant = false;
         layoutPushConstant = false;
+        layoutBufferReference = false;
 #ifdef NV_EXTENSIONS
 #ifdef NV_EXTENSIONS
         layoutPassthrough = false;
         layoutPassthrough = false;
         layoutViewportRelative = false;
         layoutViewportRelative = false;
@@ -729,6 +741,8 @@ public:
         layoutShaderRecordNV = false;
         layoutShaderRecordNV = false;
 #endif
 #endif
 
 
+        layoutBufferReferenceAlign = layoutBufferReferenceAlignEnd;
+
         clearInterstageLayout();
         clearInterstageLayout();
 
 
         layoutSpecConstantId = layoutSpecConstantIdEnd;
         layoutSpecConstantId = layoutSpecConstantIdEnd;
@@ -763,7 +777,8 @@ public:
 #ifdef NV_EXTENSIONS
 #ifdef NV_EXTENSIONS
                layoutShaderRecordNV ||
                layoutShaderRecordNV ||
 #endif
 #endif
-               layoutPushConstant;
+               layoutPushConstant ||
+               layoutBufferReference;
     }
     }
     bool hasLayout() const
     bool hasLayout() const
     {
     {
@@ -808,9 +823,14 @@ public:
                  unsigned int layoutSpecConstantId       : 11;
                  unsigned int layoutSpecConstantId       : 11;
     static const unsigned int layoutSpecConstantIdEnd = 0x7FF;
     static const unsigned int layoutSpecConstantIdEnd = 0x7FF;
 
 
+    // stored as log2 of the actual alignment value
+                 unsigned int layoutBufferReferenceAlign :  6;
+    static const unsigned int layoutBufferReferenceAlignEnd = 0x3F;
+
     TLayoutFormat layoutFormat                           :  8;
     TLayoutFormat layoutFormat                           :  8;
 
 
     bool layoutPushConstant;
     bool layoutPushConstant;
+    bool layoutBufferReference;
 
 
 #ifdef NV_EXTENSIONS
 #ifdef NV_EXTENSIONS
     bool layoutPassthrough;
     bool layoutPassthrough;
@@ -918,6 +938,10 @@ public:
         // is just whether or not it was declared with an ID.
         // is just whether or not it was declared with an ID.
         return layoutSpecConstantId != layoutSpecConstantIdEnd;
         return layoutSpecConstantId != layoutSpecConstantIdEnd;
     }
     }
+    bool hasBufferReferenceAlign() const
+    {
+        return layoutBufferReferenceAlign != layoutBufferReferenceAlignEnd;
+    }
     bool isSpecConstant() const
     bool isSpecConstant() const
     {
     {
         // True if type is a specialization constant, whether or not it
         // True if type is a specialization constant, whether or not it
@@ -1211,9 +1235,11 @@ public:
     int vectorSize : 4;
     int vectorSize : 4;
     int matrixCols : 4;
     int matrixCols : 4;
     int matrixRows : 4;
     int matrixRows : 4;
+    bool coopmat   : 1;
     TArraySizes* arraySizes;
     TArraySizes* arraySizes;
     const TType* userDef;
     const TType* userDef;
     TSourceLoc loc;
     TSourceLoc loc;
+    TArraySizes* typeParameters;
 
 
     void initType(const TSourceLoc& l)
     void initType(const TSourceLoc& l)
     {
     {
@@ -1224,6 +1250,8 @@ public:
         arraySizes = nullptr;
         arraySizes = nullptr;
         userDef = nullptr;
         userDef = nullptr;
         loc = l;
         loc = l;
+        typeParameters = nullptr;
+        coopmat = false;
     }
     }
 
 
     void initQualifiers(bool global = false)
     void initQualifiers(bool global = false)
@@ -1275,8 +1303,8 @@ public:
     // for "empty" type (no args) or simple scalar/vector/matrix
     // 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,
     explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0,
                    bool isVector = false) :
                    bool isVector = false) :
-                            basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1),
-                            arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+                            basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1), coopmat(false),
+                            arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr)
                             {
                             {
                                 sampler.clear();
                                 sampler.clear();
                                 qualifier.clear();
                                 qualifier.clear();
@@ -1286,8 +1314,8 @@ public:
     // for explicit precision qualifier
     // for explicit precision qualifier
     TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0,
     TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0,
           bool isVector = false) :
           bool isVector = false) :
-                            basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1),
-                            arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+                            basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1), coopmat(false),
+                            arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr)
                             {
                             {
                                 sampler.clear();
                                 sampler.clear();
                                 qualifier.clear();
                                 qualifier.clear();
@@ -1299,8 +1327,8 @@ public:
     // for turning a TPublicType into a TType, using a shallow copy
     // for turning a TPublicType into a TType, using a shallow copy
     explicit TType(const TPublicType& p) :
     explicit TType(const TPublicType& p) :
                             basicType(p.basicType),
                             basicType(p.basicType),
-                            vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false),
-                            arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+                            vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false), coopmat(p.coopmat),
+                            arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(p.typeParameters)
                             {
                             {
                                 if (basicType == EbtSampler)
                                 if (basicType == EbtSampler)
                                     sampler = p.sampler;
                                     sampler = p.sampler;
@@ -1308,15 +1336,26 @@ public:
                                     sampler.clear();
                                     sampler.clear();
                                 qualifier = p.qualifier;
                                 qualifier = p.qualifier;
                                 if (p.userDef) {
                                 if (p.userDef) {
-                                    structure = p.userDef->getWritableStruct();  // public type is short-lived; there are no sharing issues
+                                    if (p.userDef->basicType == EbtReference) {
+                                        basicType = EbtReference;
+                                        referentType = p.userDef->referentType;
+                                    } else {
+                                        structure = p.userDef->getWritableStruct();  // public type is short-lived; there are no sharing issues
+                                    }
                                     typeName = NewPoolTString(p.userDef->getTypeName().c_str());
                                     typeName = NewPoolTString(p.userDef->getTypeName().c_str());
                                 }
                                 }
+                                if (p.coopmat && p.basicType == EbtFloat &&
+                                    p.typeParameters && p.typeParameters->getNumDims() > 0 &&
+                                    p.typeParameters->getDimSize(0) == 16) {
+                                    basicType = EbtFloat16;
+                                    qualifier.precision = EpqNone;
+                                }
                             }
                             }
     // for construction of sampler types
     // for construction of sampler types
     TType(const TSampler& sampler, TStorageQualifier q = EvqUniform, TArraySizes* as = nullptr) :
     TType(const TSampler& sampler, TStorageQualifier q = EvqUniform, TArraySizes* as = nullptr) :
-        basicType(EbtSampler), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
+        basicType(EbtSampler), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false),
         arraySizes(as), structure(nullptr), fieldName(nullptr), typeName(nullptr),
         arraySizes(as), structure(nullptr), fieldName(nullptr), typeName(nullptr),
-        sampler(sampler)
+        sampler(sampler), typeParameters(nullptr)
     {
     {
         qualifier.clear();
         qualifier.clear();
         qualifier.storage = q;
         qualifier.storage = q;
@@ -1357,13 +1396,16 @@ public:
                                         // dereference from vector to scalar
                                         // dereference from vector to scalar
                                         vectorSize = 1;
                                         vectorSize = 1;
                                         vector1 = false;
                                         vector1 = false;
+                                    } else if (isCoopMat()) {
+                                        coopmat = false;
+                                        typeParameters = nullptr;
                                     }
                                     }
                                 }
                                 }
                             }
                             }
     // for making structures, ...
     // for making structures, ...
     TType(TTypeList* userDef, const TString& n) :
     TType(TTypeList* userDef, const TString& n) :
-                            basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
-                            arraySizes(nullptr), structure(userDef), fieldName(nullptr)
+                            basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false),
+                            arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr)
                             {
                             {
                                 sampler.clear();
                                 sampler.clear();
                                 qualifier.clear();
                                 qualifier.clear();
@@ -1371,12 +1413,23 @@ public:
                             }
                             }
     // For interface blocks
     // For interface blocks
     TType(TTypeList* userDef, const TString& n, const TQualifier& q) :
     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)
+                            basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false),
+                            qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr)
                             {
                             {
                                 sampler.clear();
                                 sampler.clear();
                                 typeName = NewPoolTString(n.c_str());
                                 typeName = NewPoolTString(n.c_str());
                             }
                             }
+    // for block reference (first parameter must be EbtReference)
+    explicit TType(TBasicType t, const TType &p, const TString& n) :
+                            basicType(t), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
+                            arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+                            {
+                                assert(t == EbtReference);
+                                typeName = NewPoolTString(n.c_str());
+                                qualifier.clear();
+                                qualifier.storage = p.qualifier.storage;
+                                referentType = p.clone();
+                            }
     virtual ~TType() {}
     virtual ~TType() {}
 
 
     // Not for use across pool pops; it will cause multiple instances of TType to point to the same information.
     // Not for use across pool pops; it will cause multiple instances of TType to point to the same information.
@@ -1392,9 +1445,15 @@ public:
         matrixRows = copyOf.matrixRows;
         matrixRows = copyOf.matrixRows;
         vector1 = copyOf.vector1;
         vector1 = copyOf.vector1;
         arraySizes = copyOf.arraySizes;  // copying the pointer only, not the contents
         arraySizes = copyOf.arraySizes;  // copying the pointer only, not the contents
-        structure = copyOf.structure;
         fieldName = copyOf.fieldName;
         fieldName = copyOf.fieldName;
         typeName = copyOf.typeName;
         typeName = copyOf.typeName;
+        if (isStruct()) {
+            structure = copyOf.structure;
+        } else {
+            referentType = copyOf.referentType;
+        }
+        typeParameters = copyOf.typeParameters;
+        coopmat = copyOf.coopmat;
     }
     }
 
 
     // Make complete copy of the whole type graph rooted at 'copyOf'.
     // Make complete copy of the whole type graph rooted at 'copyOf'.
@@ -1457,6 +1516,9 @@ public:
     virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); }
     virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); }
     virtual const TArraySizes* getArraySizes() const { return arraySizes; }
     virtual const TArraySizes* getArraySizes() const { return arraySizes; }
     virtual       TArraySizes* getArraySizes()       { return arraySizes; }
     virtual       TArraySizes* getArraySizes()       { return arraySizes; }
+    virtual TType* getReferentType() const { return referentType; }
+    virtual const TArraySizes* getTypeParameters() const { return typeParameters; }
+    virtual       TArraySizes* getTypeParameters()       { return typeParameters; }
 
 
     virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); }
     virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); }
     virtual bool isScalarOrVec1() const { return isScalar() || vector1; }
     virtual bool isScalarOrVec1() const { return isScalar() || vector1; }
@@ -1468,7 +1530,7 @@ public:
     virtual bool isArrayVariablyIndexed() const { assert(isArray()); return arraySizes->isVariablyIndexed(); }
     virtual bool isArrayVariablyIndexed() const { assert(isArray()); return arraySizes->isVariablyIndexed(); }
     virtual void setArrayVariablyIndexed() { assert(isArray()); arraySizes->setVariablyIndexed(); }
     virtual void setArrayVariablyIndexed() { assert(isArray()); arraySizes->setVariablyIndexed(); }
     virtual void updateImplicitArraySize(int size) { assert(isArray()); arraySizes->updateImplicitSize(size); }
     virtual void updateImplicitArraySize(int size) { assert(isArray()); arraySizes->updateImplicitSize(size); }
-    virtual bool isStruct() const { return structure != nullptr; }
+    virtual bool isStruct() const { return basicType == EbtStruct || basicType == EbtBlock; }
     virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16; }
     virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16; }
     virtual bool isIntegerDomain() const
     virtual bool isIntegerDomain() const
     {
     {
@@ -1499,6 +1561,8 @@ public:
     virtual bool isImage()   const { return basicType == EbtSampler && getSampler().isImage(); }
     virtual bool isImage()   const { return basicType == EbtSampler && getSampler().isImage(); }
     virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); }
     virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); }
     virtual bool isTexture() const { return basicType == EbtSampler && getSampler().isTexture(); }
     virtual bool isTexture() const { return basicType == EbtSampler && getSampler().isTexture(); }
+    virtual bool isParameterized()  const { return typeParameters != nullptr; }
+    virtual bool isCoopMat() const { return coopmat; }
 
 
     // return true if this type contains any subtype which satisfies the given predicate.
     // return true if this type contains any subtype which satisfies the given predicate.
     template <typename P>
     template <typename P>
@@ -1509,7 +1573,7 @@ public:
 
 
         const auto hasa = [predicate](const TTypeLoc& tl) { return tl.type->contains(predicate); };
         const auto hasa = [predicate](const TTypeLoc& tl) { return tl.type->contains(predicate); };
 
 
-        return structure && std::any_of(structure->begin(), structure->end(), hasa);
+        return isStruct() && std::any_of(structure->begin(), structure->end(), hasa);
     }
     }
 
 
     // Recursively checks if the type contains the given basic type
     // Recursively checks if the type contains the given basic type
@@ -1564,6 +1628,7 @@ public:
             case EbtInt64:
             case EbtInt64:
             case EbtUint64:
             case EbtUint64:
             case EbtBool:
             case EbtBool:
+            case EbtReference:
                 return true;
                 return true;
             default:
             default:
                 return false;
                 return false;
@@ -1588,6 +1653,11 @@ public:
         return containsBasicType(EbtInt8) || containsBasicType(EbtUint8);
         return containsBasicType(EbtInt8) || containsBasicType(EbtUint8);
     }
     }
 
 
+    virtual bool containsCoopMat() const
+    {
+        return contains([](const TType* t) { return t->coopmat; } );
+    }
+
     // Array editing methods.  Array descriptors can be shared across
     // Array editing methods.  Array descriptors can be shared across
     // type instances.  This allows all uses of the same array
     // type instances.  This allows all uses of the same array
     // to be updated at once.  E.g., all nodes can be explicitly sized
     // to be updated at once.  E.g., all nodes can be explicitly sized
@@ -1660,6 +1730,46 @@ public:
         }
         }
     }
     }
 
 
+
+    void updateTypeParameters(const TType& type)
+    {
+        // For when we may already be sharing existing array descriptors,
+        // keeping the pointers the same, just updating the contents.
+        assert(typeParameters != nullptr);
+        assert(type.typeParameters != nullptr);
+        *typeParameters = *type.typeParameters;
+    }
+    void copyTypeParameters(const TArraySizes& s)
+    {
+        // For setting a fresh new set of type parameters, not yet worrying about sharing.
+        typeParameters = new TArraySizes;
+        *typeParameters = s;
+    }
+    void transferTypeParameters(TArraySizes* s)
+    {
+        // For setting an already allocated set of sizes that this type can use
+        // (no copy made).
+        typeParameters = s;
+    }
+    void clearTypeParameters()
+    {
+        typeParameters = nullptr;
+    }
+
+    // Add inner array sizes, to any existing sizes, via copy; the
+    // sizes passed in can still be reused for other purposes.
+    void copyTypeParametersInnerSizes(const TArraySizes* s)
+    {
+        if (s != nullptr) {
+            if (typeParameters == nullptr)
+                copyTypeParameters(*s);
+            else
+                typeParameters->addInnerSizes(*s);
+        }
+    }
+
+
+
     const char* getBasicString() const
     const char* getBasicString() const
     {
     {
         return TType::getBasicString(basicType);
         return TType::getBasicString(basicType);
@@ -1688,6 +1798,7 @@ public:
 #ifdef NV_EXTENSIONS
 #ifdef NV_EXTENSIONS
         case EbtAccStructNV:       return "accelerationStructureNV";
         case EbtAccStructNV:       return "accelerationStructureNV";
 #endif
 #endif
+        case EbtReference:         return "reference";
         default:                   return "unknown type";
         default:                   return "unknown type";
         }
         }
     }
     }
@@ -1773,6 +1884,12 @@ public:
                 }
                 }
                 if (qualifier.layoutPushConstant)
                 if (qualifier.layoutPushConstant)
                     appendStr(" push_constant");
                     appendStr(" push_constant");
+                if (qualifier.layoutBufferReference)
+                    appendStr(" buffer_reference");
+                if (qualifier.hasBufferReferenceAlign()) {
+                    appendStr(" buffer_reference_align=");
+                    appendUint(1u << qualifier.layoutBufferReferenceAlign);
+                }
 
 
 #ifdef NV_EXTENSIONS
 #ifdef NV_EXTENSIONS
                 if (qualifier.layoutPassthrough)
                 if (qualifier.layoutPassthrough)
@@ -1867,6 +1984,15 @@ public:
                 }
                 }
             }
             }
         }
         }
+        if (isParameterized()) {
+            appendStr("<");
+            for(int i = 0; i < (int)typeParameters->getNumDims(); ++i) {
+                appendInt(typeParameters->getDimSize(i));
+                if (i != (int)typeParameters->getNumDims() - 1)
+                    appendStr(", ");
+            }
+            appendStr(">");
+        }
         if (qualifier.precision != EpqNone) {
         if (qualifier.precision != EpqNone) {
             appendStr(" ");
             appendStr(" ");
             appendStr(getPrecisionQualifierString());
             appendStr(getPrecisionQualifierString());
@@ -1892,7 +2018,7 @@ public:
         }
         }
 
 
         // Add struct/block members
         // Add struct/block members
-        if (structure) {
+        if (isStruct() && structure) {
             appendStr("{");
             appendStr("{");
             for (size_t i = 0; i < structure->size(); ++i) {
             for (size_t i = 0; i < structure->size(); ++i) {
                 if (! (*structure)[i].type->hiddenMember()) {
                 if (! (*structure)[i].type->hiddenMember()) {
@@ -1920,9 +2046,9 @@ public:
     const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); }
     const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); }
     const char* getBuiltInVariableString() const { return GetBuiltInVariableString(qualifier.builtIn); }
     const char* getBuiltInVariableString() const { return GetBuiltInVariableString(qualifier.builtIn); }
     const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
     const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
-    const TTypeList* getStruct() const { return structure; }
-    void setStruct(TTypeList* s) { structure = s; }
-    TTypeList* getWritableStruct() const { return structure; }  // This should only be used when known to not be sharing with other threads
+    const TTypeList* getStruct() const { assert(isStruct()); return structure; }
+    void setStruct(TTypeList* s) { assert(isStruct()); structure = s; }
+    TTypeList* getWritableStruct() const { assert(isStruct()); return structure; }  // This should only be used when known to not be sharing with other threads
 
 
     int computeNumComponents() const
     int computeNumComponents() const
     {
     {
@@ -1961,11 +2087,12 @@ public:
     bool sameStructType(const TType& right) const
     bool sameStructType(const TType& right) const
     {
     {
         // Most commonly, they are both nullptr, or the same pointer to the same actual structure
         // Most commonly, they are both nullptr, or the same pointer to the same actual structure
-        if (structure == right.structure)
+        if ((!isStruct() && !right.isStruct()) ||
+            (isStruct() && right.isStruct() && structure == right.structure))
             return true;
             return true;
 
 
         // Both being nullptr was caught above, now they both have to be structures of the same number of elements
         // 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 ||
+        if (!isStruct() || !right.isStruct() ||
             structure->size() != right.structure->size())
             structure->size() != right.structure->size())
             return false;
             return false;
 
 
@@ -1985,6 +2112,23 @@ public:
         return true;
         return true;
     }
     }
 
 
+    bool sameReferenceType(const TType& right) const
+    {
+        if ((basicType == EbtReference) != (right.basicType == EbtReference))
+            return false;
+
+        if ((basicType != EbtReference) && (right.basicType != EbtReference))
+            return true;
+
+        assert(referentType != nullptr);
+        assert(right.referentType != nullptr);
+
+        if (referentType == right.referentType)
+            return true;
+
+        return *referentType == *right.referentType;
+    }
+
     // See if two types match, in all aspects except arrayness
     // See if two types match, in all aspects except arrayness
     bool sameElementType(const TType& right) const
     bool sameElementType(const TType& right) const
     {
     {
@@ -2005,6 +2149,13 @@ public:
         return arraySizes->sameInnerArrayness(*right.arraySizes);
         return arraySizes->sameInnerArrayness(*right.arraySizes);
     }
     }
 
 
+    // See if two type's parameters match
+    bool sameTypeParameters(const TType& right) const
+    {
+        return ((typeParameters == nullptr && right.typeParameters == nullptr) ||
+                (typeParameters != nullptr && right.typeParameters != nullptr && *typeParameters == *right.typeParameters));
+    }
+
     // See if two type's elements match in all ways except basic type
     // See if two type's elements match in all ways except basic type
     bool sameElementShape(const TType& right) const
     bool sameElementShape(const TType& right) const
     {
     {
@@ -2013,13 +2164,23 @@ public:
                matrixCols == right.matrixCols &&
                matrixCols == right.matrixCols &&
                matrixRows == right.matrixRows &&
                matrixRows == right.matrixRows &&
                   vector1 == right.vector1    &&
                   vector1 == right.vector1    &&
-               sameStructType(right);
+                  coopmat == right.coopmat    &&
+               sameStructType(right)          &&
+               sameReferenceType(right);
+    }
+
+    // See if a cooperative matrix type parameter with unspecified parameters is
+    // an OK function parameter
+    bool coopMatParameterOK(const TType& right) const
+    {
+        return coopmat && right.coopmat &&
+               typeParameters == nullptr && right.typeParameters != nullptr;
     }
     }
 
 
     // See if two types match in all ways (just the actual type, not qualification)
     // See if two types match in all ways (just the actual type, not qualification)
     bool operator==(const TType& right) const
     bool operator==(const TType& right) const
     {
     {
-        return sameElementType(right) && sameArrayness(right);
+        return sameElementType(right) && sameArrayness(right) && sameTypeParameters(right);
     }
     }
 
 
     bool operator!=(const TType& right) const
     bool operator!=(const TType& right) const
@@ -2027,6 +2188,16 @@ public:
         return ! operator==(right);
         return ! operator==(right);
     }
     }
 
 
+    unsigned int getBufferReferenceAlignment() const
+    {
+        if (getBasicType() == glslang::EbtReference) {
+            return getReferentType()->getQualifier().hasBufferReferenceAlign() ?
+                        (1u << getReferentType()->getQualifier().layoutBufferReferenceAlign) : 16u;
+        } else {
+            return 0;
+        }
+    }
+
 protected:
 protected:
     // Require consumer to pick between deep copy and shallow copy.
     // Require consumer to pick between deep copy and shallow copy.
     TType(const TType& type);
     TType(const TType& type);
@@ -2044,7 +2215,12 @@ protected:
             *arraySizes = *copyOf.arraySizes;
             *arraySizes = *copyOf.arraySizes;
         }
         }
 
 
-        if (copyOf.structure) {
+        if (copyOf.typeParameters) {
+            typeParameters = new TArraySizes;
+            *typeParameters = *copyOf.typeParameters;
+        }
+
+        if (copyOf.isStruct() && copyOf.structure) {
             auto prevCopy = copiedMap.find(copyOf.structure);
             auto prevCopy = copiedMap.find(copyOf.structure);
             if (prevCopy != copiedMap.end())
             if (prevCopy != copiedMap.end())
                 structure = prevCopy->second;
                 structure = prevCopy->second;
@@ -2079,13 +2255,20 @@ protected:
                                // functionality is added.
                                // functionality is added.
                                // HLSL does have a 1-component vectors, so this will be true to disambiguate
                                // HLSL does have a 1-component vectors, so this will be true to disambiguate
                                // from a scalar.
                                // from a scalar.
+    bool coopmat         : 1;
     TQualifier qualifier;
     TQualifier qualifier;
 
 
     TArraySizes* arraySizes;    // nullptr unless an array; can be shared across types
     TArraySizes* arraySizes;    // nullptr unless an array; can be shared across types
-    TTypeList* structure;       // nullptr unless this is a struct; can be shared across types
+    // A type can't be both a structure (EbtStruct/EbtBlock) and a reference (EbtReference), so
+    // conserve space by making these a union
+    union {
+        TTypeList* structure;       // invalid unless this is a struct; can be shared across types
+        TType *referentType;        // invalid unless this is an EbtReference
+    };
     TString *fieldName;         // for structure field names
     TString *fieldName;         // for structure field names
     TString *typeName;          // for structure type name
     TString *typeName;          // for structure type name
     TSampler sampler;
     TSampler sampler;
+    TArraySizes* typeParameters;// nullptr unless a parameterized type; can be shared across types
 };
 };
 
 
 } // end namespace glslang
 } // end namespace glslang

+ 5 - 3
src/libraries/glslang/glslang/Include/arrays.h

@@ -254,7 +254,9 @@ struct TArraySizes {
     void addInnerSize() { addInnerSize((unsigned)UnsizedArraySize); }
     void addInnerSize() { addInnerSize((unsigned)UnsizedArraySize); }
     void addInnerSize(int s) { addInnerSize((unsigned)s, nullptr); }
     void addInnerSize(int s) { addInnerSize((unsigned)s, nullptr); }
     void addInnerSize(int s, TIntermTyped* n) { sizes.push_back((unsigned)s, n); }
     void addInnerSize(int s, TIntermTyped* n) { sizes.push_back((unsigned)s, n); }
-    void addInnerSize(TArraySize pair) { sizes.push_back(pair.size, pair.node); }
+    void addInnerSize(TArraySize pair) {
+        sizes.push_back(pair.size, pair.node);
+    }
     void addInnerSizes(const TArraySizes& s) { sizes.push_back(s.sizes); }
     void addInnerSizes(const TArraySizes& s) { sizes.push_back(s.sizes); }
     void changeOuterSize(int s) { sizes.changeFront((unsigned)s); }
     void changeOuterSize(int s) { sizes.changeFront((unsigned)s); }
     int getImplicitSize() const { return implicitArraySize; }
     int getImplicitSize() const { return implicitArraySize; }
@@ -318,8 +320,8 @@ struct TArraySizes {
     void setVariablyIndexed() { variablyIndexed = true; }
     void setVariablyIndexed() { variablyIndexed = true; }
     bool isVariablyIndexed() const { return variablyIndexed; }
     bool isVariablyIndexed() const { return variablyIndexed; }
 
 
-    bool operator==(const TArraySizes& rhs) { return sizes == rhs.sizes; }
-    bool operator!=(const TArraySizes& rhs) { return sizes != rhs.sizes; }
+    bool operator==(const TArraySizes& rhs) const { return sizes == rhs.sizes; }
+    bool operator!=(const TArraySizes& rhs) const { return sizes != rhs.sizes; }
 
 
 protected:
 protected:
     TSmallArrayVector sizes;
     TSmallArrayVector sizes;

+ 46 - 2
src/libraries/glslang/glslang/Include/intermediate.h

@@ -85,6 +85,8 @@ enum TOperator {
     EOpPreIncrement,
     EOpPreIncrement,
     EOpPreDecrement,
     EOpPreDecrement,
 
 
+    EOpCopyObject,
+
     // (u)int* -> bool
     // (u)int* -> bool
     EOpConvInt8ToBool,
     EOpConvInt8ToBool,
     EOpConvUint8ToBool,
     EOpConvUint8ToBool,
@@ -269,6 +271,10 @@ enum TOperator {
     EOpConvDoubleToFloat16,
     EOpConvDoubleToFloat16,
     EOpConvDoubleToFloat,
     EOpConvDoubleToFloat,
 
 
+    // uint64_t <-> pointer
+    EOpConvUint64ToPtr,
+    EOpConvPtrToUint64,
+
     //
     //
     // binary operations
     // binary operations
     //
     //
@@ -611,6 +617,10 @@ enum TOperator {
     EOpAny,
     EOpAny,
     EOpAll,
     EOpAll,
 
 
+    EOpCooperativeMatrixLoad,
+    EOpCooperativeMatrixStore,
+    EOpCooperativeMatrixMulAdd,
+
     //
     //
     // Branch
     // Branch
     //
     //
@@ -732,6 +742,8 @@ enum TOperator {
     EOpConstructStruct,
     EOpConstructStruct,
     EOpConstructTextureSampler,
     EOpConstructTextureSampler,
     EOpConstructNonuniform,     // expected to be transformed away, not present in final AST
     EOpConstructNonuniform,     // expected to be transformed away, not present in final AST
+    EOpConstructReference,
+    EOpConstructCooperativeMatrix,
     EOpConstructGuardEnd,
     EOpConstructGuardEnd,
 
 
     //
     //
@@ -1104,7 +1116,12 @@ public:
         first(testFirst),
         first(testFirst),
         unroll(false),
         unroll(false),
         dontUnroll(false),
         dontUnroll(false),
-        dependency(0)
+        dependency(0),
+        minIterations(0),
+        maxIterations(iterationsInfinite),
+        iterationMultiple(1),
+        peelCount(0),
+        partialCount(0)
     { }
     { }
 
 
     virtual       TIntermLoop* getAsLoopNode() { return this; }
     virtual       TIntermLoop* getAsLoopNode() { return this; }
@@ -1116,14 +1133,36 @@ public:
     bool testFirst() const { return first; }
     bool testFirst() const { return first; }
 
 
     void setUnroll()     { unroll = true; }
     void setUnroll()     { unroll = true; }
-    void setDontUnroll() { dontUnroll = true; }
+    void setDontUnroll() {
+        dontUnroll = true;
+        peelCount = 0;
+        partialCount = 0;
+    }
     bool getUnroll()     const { return unroll; }
     bool getUnroll()     const { return unroll; }
     bool getDontUnroll() const { return dontUnroll; }
     bool getDontUnroll() const { return dontUnroll; }
 
 
     static const unsigned int dependencyInfinite = 0xFFFFFFFF;
     static const unsigned int dependencyInfinite = 0xFFFFFFFF;
+    static const unsigned int iterationsInfinite = 0xFFFFFFFF;
     void setLoopDependency(int d) { dependency = d; }
     void setLoopDependency(int d) { dependency = d; }
     int getLoopDependency() const { return dependency; }
     int getLoopDependency() const { return dependency; }
 
 
+    void setMinIterations(unsigned int v) { minIterations = v; }
+    unsigned int getMinIterations() const { return minIterations; }
+    void setMaxIterations(unsigned int v) { maxIterations = v; }
+    unsigned int getMaxIterations() const { return maxIterations; }
+    void setIterationMultiple(unsigned int v) { iterationMultiple = v; }
+    unsigned int getIterationMultiple() const { return iterationMultiple; }
+    void setPeelCount(unsigned int v) {
+        peelCount = v;
+        dontUnroll = false;
+    }
+    unsigned int getPeelCount() const { return peelCount; }
+    void setPartialCount(unsigned int v) {
+        partialCount = v;
+        dontUnroll = false;
+    }
+    unsigned int getPartialCount() const { return partialCount; }
+
 protected:
 protected:
     TIntermNode* body;       // code to loop over
     TIntermNode* body;       // code to loop over
     TIntermTyped* test;      // exit condition associated with loop, could be 0 for 'for' loops
     TIntermTyped* test;      // exit condition associated with loop, could be 0 for 'for' loops
@@ -1132,6 +1171,11 @@ protected:
     bool unroll;             // true if unroll requested
     bool unroll;             // true if unroll requested
     bool dontUnroll;         // true if request to not unroll
     bool dontUnroll;         // true if request to not unroll
     unsigned int dependency; // loop dependency hint; 0 means not set or unknown
     unsigned int dependency; // loop dependency hint; 0 means not set or unknown
+    unsigned int minIterations;      // as per the SPIR-V specification
+    unsigned int maxIterations;      // as per the SPIR-V specification
+    unsigned int iterationMultiple;  // as per the SPIR-V specification
+    unsigned int peelCount;          // as per the SPIR-V specification
+    unsigned int partialCount;       // as per the SPIR-V specification
 };
 };
 
 
 //
 //

+ 1 - 1
src/libraries/glslang/glslang/Include/revision.h

@@ -1,3 +1,3 @@
 // This header is generated by the make-revision script.
 // This header is generated by the make-revision script.
 
 
-#define GLSLANG_PATCH_LEVEL 3009
+#define GLSLANG_PATCH_LEVEL 3226

+ 7 - 1
src/libraries/glslang/glslang/MachineIndependent/Constant.cpp

@@ -941,6 +941,10 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
             newConstArray[i].setDConst(unionArray[i].getDConst()); break;
             newConstArray[i].setDConst(unionArray[i].getDConst()); break;
         case EOpConvDoubleToFloat:
         case EOpConvDoubleToFloat:
             newConstArray[i].setDConst(unionArray[i].getDConst()); break;
             newConstArray[i].setDConst(unionArray[i].getDConst()); break;
+        case EOpConvPtrToUint64:
+        case EOpConvUint64ToPtr:
+        case EOpConstructReference:
+            newConstArray[i].setU64Const(unionArray[i].getU64Const()); break;
 
 
 
 
 
 
@@ -1354,7 +1358,9 @@ TIntermTyped* TIntermediate::foldDereference(TIntermTyped* node, int index, cons
     // arrays, vectors, matrices, all use simple multiplicative math
     // arrays, vectors, matrices, all use simple multiplicative math
     // while structures need to add up heterogeneous members
     // while structures need to add up heterogeneous members
     int start;
     int start;
-    if (node->isArray() || ! node->isStruct())
+    if (node->getType().isCoopMat())
+        start = 0;
+    else if (node->isArray() || ! node->isStruct())
         start = size * index;
         start = size * index;
     else {
     else {
         // it is a structure
         // it is a structure

+ 146 - 33
src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp

@@ -1609,6 +1609,16 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
                     "vec4 texelFetch(samplerExternalOES, ivec2, int lod);"    // GL_OES_EGL_image_external_essl3
                     "vec4 texelFetch(samplerExternalOES, ivec2, int lod);"    // GL_OES_EGL_image_external_essl3
                 "\n");
                 "\n");
             }
             }
+            commonBuiltins.append(
+                "highp ivec2 textureSize(__samplerExternal2DY2YEXT, int lod);" // GL_EXT_YUV_target
+                "vec4 texture(__samplerExternal2DY2YEXT, vec2);"               // GL_EXT_YUV_target
+                "vec4 texture(__samplerExternal2DY2YEXT, vec2, float bias);"   // GL_EXT_YUV_target
+                "vec4 textureProj(__samplerExternal2DY2YEXT, vec3);"           // GL_EXT_YUV_target
+                "vec4 textureProj(__samplerExternal2DY2YEXT, vec3, float bias);" // GL_EXT_YUV_target
+                "vec4 textureProj(__samplerExternal2DY2YEXT, vec4);"           // GL_EXT_YUV_target
+                "vec4 textureProj(__samplerExternal2DY2YEXT, vec4, float bias);" // GL_EXT_YUV_target
+                "vec4 texelFetch(__samplerExternal2DY2YEXT sampler, ivec2, int lod);" // GL_EXT_YUV_target
+                "\n");
             commonBuiltins.append(
             commonBuiltins.append(
                 "vec4 texture2DGradEXT(sampler2D, vec2, vec2, vec2);"      // GL_EXT_shader_texture_lod
                 "vec4 texture2DGradEXT(sampler2D, vec2, vec2, vec2);"      // GL_EXT_shader_texture_lod
                 "vec4 texture2DProjGradEXT(sampler2D, vec3, vec2, vec2);"  // GL_EXT_shader_texture_lod
                 "vec4 texture2DProjGradEXT(sampler2D, vec3, vec2, vec2);"  // GL_EXT_shader_texture_lod
@@ -1869,7 +1879,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
     }
     }
 
 
     // GL_KHR_shader_subgroup
     // GL_KHR_shader_subgroup
-    if (spvVersion.vulkan > 0) {
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 140)) {
         commonBuiltins.append(
         commonBuiltins.append(
             "void subgroupBarrier();"
             "void subgroupBarrier();"
             "void subgroupMemoryBarrier();"
             "void subgroupMemoryBarrier();"
@@ -4930,6 +4941,34 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
     commonBuiltins.append("void controlBarrier(int, int, int, int);\n"
     commonBuiltins.append("void controlBarrier(int, int, int, int);\n"
                           "void memoryBarrier(int, int, int);\n");
                           "void memoryBarrier(int, int, int);\n");
 
 
+    if (profile != EEsProfile && version >= 450) {
+        // coopMatStoreNV perhaps ought to have "out" on the buf parameter, but
+        // adding it introduces undesirable tempArgs on the stack. What we want
+        // is more like "buf" thought of as a pointer value being an in parameter.
+        stageBuiltins[EShLangCompute].append(
+            "void coopMatLoadNV(out fcoopmatNV m, volatile coherent float16_t[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatLoadNV(out fcoopmatNV m, volatile coherent float[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatLoadNV(out fcoopmatNV m, volatile coherent uint8_t[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatLoadNV(out fcoopmatNV m, volatile coherent uint16_t[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatLoadNV(out fcoopmatNV m, volatile coherent uint[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatLoadNV(out fcoopmatNV m, volatile coherent uint64_t[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatLoadNV(out fcoopmatNV m, volatile coherent uvec2[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatLoadNV(out fcoopmatNV m, volatile coherent uvec4[] buf, uint element, uint stride, bool colMajor);\n"
+
+            "void coopMatStoreNV(fcoopmatNV m, volatile coherent float16_t[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatStoreNV(fcoopmatNV m, volatile coherent float[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatStoreNV(fcoopmatNV m, volatile coherent float64_t[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatStoreNV(fcoopmatNV m, volatile coherent uint8_t[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatStoreNV(fcoopmatNV m, volatile coherent uint16_t[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatStoreNV(fcoopmatNV m, volatile coherent uint[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatStoreNV(fcoopmatNV m, volatile coherent uint64_t[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatStoreNV(fcoopmatNV m, volatile coherent uvec2[] buf, uint element, uint stride, bool colMajor);\n"
+            "void coopMatStoreNV(fcoopmatNV m, volatile coherent uvec4[] buf, uint element, uint stride, bool colMajor);\n"
+
+            "fcoopmatNV coopMatMulAddNV(fcoopmatNV A, fcoopmatNV B, fcoopmatNV C);\n"
+            );
+    }
+
     //============================================================================
     //============================================================================
     //
     //
     // Prototypes for built-in functions seen by fragment shaders only.
     // Prototypes for built-in functions seen by fragment shaders only.
@@ -5362,6 +5401,9 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
             "in highp uvec3 gl_GlobalInvocationID;"
             "in highp uvec3 gl_GlobalInvocationID;"
             "in highp uint gl_LocalInvocationIndex;"
             "in highp uint gl_LocalInvocationIndex;"
 
 
+            "in uint gl_MeshViewCountNV;"
+            "in uint gl_MeshViewIndicesNV[4];"
+
             "\n");
             "\n");
     }
     }
 
 
@@ -5768,7 +5810,14 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
             "patch out highp float gl_TessLevelOuter[4];"
             "patch out highp float gl_TessLevelOuter[4];"
             "patch out highp float gl_TessLevelInner[2];"
             "patch out highp float gl_TessLevelInner[2];"
             "patch out highp vec4 gl_BoundingBoxOES[2];"
             "patch out highp vec4 gl_BoundingBoxOES[2];"
+            "patch out highp vec4 gl_BoundingBoxEXT[2];"
             "\n");
             "\n");
+        if (profile == EEsProfile && version >= 320) {
+            stageBuiltins[EShLangTessControl].append(
+                "patch out highp vec4 gl_BoundingBox[2];"
+                "\n"
+            );
+        }
     }
     }
 
 
     if ((profile != EEsProfile && version >= 140) ||
     if ((profile != EEsProfile && version >= 140) ||
@@ -6093,7 +6142,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
     }
     }
 
 
     // GL_KHR_shader_subgroup
     // GL_KHR_shader_subgroup
-    if (spvVersion.vulkan > 0) {
+    if ((profile == EEsProfile && version >= 310) ||
+        (profile != EEsProfile && version >= 140)) {
         const char* ballotDecls = 
         const char* ballotDecls = 
             "in mediump uint  gl_SubgroupSize;"
             "in mediump uint  gl_SubgroupSize;"
             "in mediump uint  gl_SubgroupInvocationID;"
             "in mediump uint  gl_SubgroupInvocationID;"
@@ -6207,7 +6257,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
         const char *callableDecls =
         const char *callableDecls =
             "in    uvec3  gl_LaunchIDNV;"
             "in    uvec3  gl_LaunchIDNV;"
             "in    uvec3  gl_LaunchSizeNV;"
             "in    uvec3  gl_LaunchSizeNV;"
-            "in    uint   gl_IncomingRayFlagsNV;"
             "\n";
             "\n";
 
 
         stageBuiltins[EShLangRayGenNV].append(rayGenDecls);
         stageBuiltins[EShLangRayGenNV].append(rayGenDecls);
@@ -7752,11 +7801,12 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf
 static void SpecialQualifier(const char* name, TStorageQualifier qualifier, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
 static void SpecialQualifier(const char* name, TStorageQualifier qualifier, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
 {
 {
     TSymbol* symbol = symbolTable.find(name);
     TSymbol* symbol = symbolTable.find(name);
-    if (symbol) {
-        TQualifier& symQualifier = symbol->getWritableType().getQualifier();
-        symQualifier.storage = qualifier;
-        symQualifier.builtIn = builtIn;
-    }
+    if (symbol == nullptr)
+        return;
+
+    TQualifier& symQualifier = symbol->getWritableType().getQualifier();
+    symQualifier.storage = qualifier;
+    symQualifier.builtIn = builtIn;
 }
 }
 
 
 //
 //
@@ -7772,7 +7822,7 @@ static void SpecialQualifier(const char* name, TStorageQualifier qualifier, TBui
 static void BuiltInVariable(const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
 static void BuiltInVariable(const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
 {
 {
     TSymbol* symbol = symbolTable.find(name);
     TSymbol* symbol = symbolTable.find(name);
-    if (! symbol)
+    if (symbol == nullptr)
         return;
         return;
 
 
     TQualifier& symQualifier = symbol->getWritableType().getQualifier();
     TQualifier& symQualifier = symbol->getWritableType().getQualifier();
@@ -7789,7 +7839,7 @@ static void BuiltInVariable(const char* name, TBuiltInVariable builtIn, TSymbolT
 static void BuiltInVariable(const char* blockName, const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
 static void BuiltInVariable(const char* blockName, const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
 {
 {
     TSymbol* symbol = symbolTable.find(blockName);
     TSymbol* symbol = symbolTable.find(blockName);
-    if (! symbol)
+    if (symbol == nullptr)
         return;
         return;
 
 
     TTypeList& structure = *symbol->getWritableType().getWritableStruct();
     TTypeList& structure = *symbol->getWritableType().getWritableStruct();
@@ -7987,10 +8037,16 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
 
 
     case EShLangTessControl:
     case EShLangTessControl:
         if (profile == EEsProfile && version >= 310) {
         if (profile == EEsProfile && version >= 310) {
+            BuiltInVariable("gl_BoundingBoxEXT", EbvBoundingBox, symbolTable);
+            symbolTable.setVariableExtensions("gl_BoundingBoxEXT", 1,
+                                              &E_GL_EXT_primitive_bounding_box);
             BuiltInVariable("gl_BoundingBoxOES", EbvBoundingBox, symbolTable);
             BuiltInVariable("gl_BoundingBoxOES", EbvBoundingBox, symbolTable);
-            if (version < 320)
-                symbolTable.setVariableExtensions("gl_BoundingBoxOES", Num_AEP_primitive_bounding_box,
-                                                  AEP_primitive_bounding_box);
+            symbolTable.setVariableExtensions("gl_BoundingBoxOES", 1,
+                                              &E_GL_OES_primitive_bounding_box);
+
+            if (version >= 320) {
+                BuiltInVariable("gl_BoundingBox", EbvBoundingBox, symbolTable);
+            }
         }
         }
 
 
         // Fall through
         // Fall through
@@ -8045,9 +8101,18 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         BuiltInVariable("gl_ViewportMaskPerViewNV",     EbvViewportMaskPerViewNV,   symbolTable);
         BuiltInVariable("gl_ViewportMaskPerViewNV",     EbvViewportMaskPerViewNV,   symbolTable);
 
 
         if (language != EShLangVertex) {
         if (language != EShLangVertex) {
+            symbolTable.setVariableExtensions("gl_in", "gl_SecondaryPositionNV", 1, &E_GL_NV_stereo_view_rendering);
+            symbolTable.setVariableExtensions("gl_in", "gl_PositionPerViewNV",   1, &E_GL_NVX_multiview_per_view_attributes);
+
             BuiltInVariable("gl_in", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable);
             BuiltInVariable("gl_in", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable);
             BuiltInVariable("gl_in", "gl_PositionPerViewNV",   EbvPositionPerViewNV,   symbolTable);
             BuiltInVariable("gl_in", "gl_PositionPerViewNV",   EbvPositionPerViewNV,   symbolTable);
         }
         }
+        symbolTable.setVariableExtensions("gl_out", "gl_ViewportMask",            1, &E_GL_NV_viewport_array2);
+        symbolTable.setVariableExtensions("gl_out", "gl_SecondaryPositionNV",     1, &E_GL_NV_stereo_view_rendering);
+        symbolTable.setVariableExtensions("gl_out", "gl_SecondaryViewportMaskNV", 1, &E_GL_NV_stereo_view_rendering);
+        symbolTable.setVariableExtensions("gl_out", "gl_PositionPerViewNV",       1, &E_GL_NVX_multiview_per_view_attributes);
+        symbolTable.setVariableExtensions("gl_out", "gl_ViewportMaskPerViewNV",   1, &E_GL_NVX_multiview_per_view_attributes);
+
         BuiltInVariable("gl_out", "gl_ViewportMask",            EbvViewportMaskNV,          symbolTable);
         BuiltInVariable("gl_out", "gl_ViewportMask",            EbvViewportMaskNV,          symbolTable);
         BuiltInVariable("gl_out", "gl_SecondaryPositionNV",     EbvSecondaryPositionNV,     symbolTable);
         BuiltInVariable("gl_out", "gl_SecondaryPositionNV",     EbvSecondaryPositionNV,     symbolTable);
         BuiltInVariable("gl_out", "gl_SecondaryViewportMaskNV", EbvSecondaryViewportMaskNV, symbolTable);
         BuiltInVariable("gl_out", "gl_SecondaryViewportMaskNV", EbvSecondaryViewportMaskNV, symbolTable);
@@ -8091,15 +8156,16 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
 
 
         // gl_PointSize, when it needs to be tied to an extension, is always a member of a block.
         // gl_PointSize, when it needs to be tied to an extension, is always a member of a block.
         // (Sometimes with an instance name, sometimes anonymous).
         // (Sometimes with an instance name, sometimes anonymous).
-        // However, the current automatic extension scheme does not work per block member,
-        // so for now check when parsing.
-        //
-        // if (profile == EEsProfile) {
-        //    if (language == EShLangGeometry)
-        //        symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size);
-        //    else if (language == EShLangTessEvaluation || language == EShLangTessControl)
-        //        symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
-        //}
+        if (profile == EEsProfile) {
+            if (language == EShLangGeometry) {
+                symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size);
+                symbolTable.setVariableExtensions("gl_in", "gl_PointSize", Num_AEP_geometry_point_size, AEP_geometry_point_size);
+            } else if (language == EShLangTessEvaluation || language == EShLangTessControl) {
+                // gl_in tessellation settings of gl_PointSize are in the context-dependent paths
+                symbolTable.setVariableExtensions("gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
+                symbolTable.setVariableExtensions("gl_out", "gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
+            }
+        }
 
 
         if ((profile != EEsProfile && version >= 140) ||
         if ((profile != EEsProfile && version >= 140) ||
             (profile == EEsProfile && version >= 310)) {
             (profile == EEsProfile && version >= 310)) {
@@ -8110,7 +8176,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         }
         }
         
         
         // GL_KHR_shader_subgroup
         // GL_KHR_shader_subgroup
-        if (spvVersion.vulkan > 0) {
+        if ((profile == EEsProfile && version >= 310) ||
+            (profile != EEsProfile && version >= 140)) {
             symbolTable.setVariableExtensions("gl_SubgroupSize",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupSize",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupEqMask",       1, &E_GL_KHR_shader_subgroup_ballot);
             symbolTable.setVariableExtensions("gl_SubgroupEqMask",       1, &E_GL_KHR_shader_subgroup_ballot);
@@ -8450,7 +8517,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         }
         }
 
 
         // GL_KHR_shader_subgroup
         // GL_KHR_shader_subgroup
-        if (spvVersion.vulkan > 0) {
+        if ((profile == EEsProfile && version >= 310) ||
+            (profile != EEsProfile && version >= 140)) {
             symbolTable.setVariableExtensions("gl_SubgroupSize",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupSize",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupEqMask",       1, &E_GL_KHR_shader_subgroup_ballot);
             symbolTable.setVariableExtensions("gl_SubgroupEqMask",       1, &E_GL_KHR_shader_subgroup_ballot);
@@ -8634,7 +8702,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         }
         }
 
 
         // GL_KHR_shader_subgroup
         // GL_KHR_shader_subgroup
-        if (spvVersion.vulkan > 0) {
+        if ((profile == EEsProfile && version >= 310) ||
+            (profile != EEsProfile && version >= 140)) {
             symbolTable.setVariableExtensions("gl_SubgroupSize",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupSize",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupInvocationID", 1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupEqMask",       1, &E_GL_KHR_shader_subgroup_ballot);
             symbolTable.setVariableExtensions("gl_SubgroupEqMask",       1, &E_GL_KHR_shader_subgroup_ballot);
@@ -8661,7 +8730,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         }
         }
 
 
         // GL_KHR_shader_subgroup
         // GL_KHR_shader_subgroup
-        if (spvVersion.vulkan > 0) {
+        if ((profile == EEsProfile && version >= 310) ||
+            (profile != EEsProfile && version >= 140)) {
             symbolTable.setVariableExtensions("gl_NumSubgroups", 1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_NumSubgroups", 1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupID",   1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupID",   1, &E_GL_KHR_shader_subgroup_basic);
 
 
@@ -8670,6 +8740,11 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
 
 
             symbolTable.setFunctionExtensions("subgroupMemoryBarrierShared", 1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setFunctionExtensions("subgroupMemoryBarrierShared", 1, &E_GL_KHR_shader_subgroup_basic);
         }
         }
+
+        symbolTable.setFunctionExtensions("coopMatLoadNV",              1, &E_GL_NV_cooperative_matrix);
+        symbolTable.setFunctionExtensions("coopMatStoreNV",             1, &E_GL_NV_cooperative_matrix);
+        symbolTable.setFunctionExtensions("coopMatMulAddNV",            1, &E_GL_NV_cooperative_matrix);
+
         break;
         break;
 #ifdef NV_EXTENSIONS
 #ifdef NV_EXTENSIONS
     case EShLangRayGenNV:
     case EShLangRayGenNV:
@@ -8719,25 +8794,44 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         break;
         break;
     case EShLangMeshNV:
     case EShLangMeshNV:
         if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) {
         if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) {
-            // Per-vertex builtins
+            // per-vertex builtins
+            symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_Position",     1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_PointSize",    1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_ClipDistance", 1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_CullDistance", 1, &E_GL_NV_mesh_shader);
+
             BuiltInVariable("gl_MeshVerticesNV", "gl_Position",     EbvPosition,     symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_Position",     EbvPosition,     symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_PointSize",    EbvPointSize,    symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_PointSize",    EbvPointSize,    symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_ClipDistance", EbvClipDistance, symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_ClipDistance", EbvClipDistance, symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_CullDistance", EbvCullDistance, symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_CullDistance", EbvCullDistance, symbolTable);
-            // Per-view builtins
+
+            symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_PositionPerViewNV",     1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_ClipDistancePerViewNV", 1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_CullDistancePerViewNV", 1, &E_GL_NV_mesh_shader);
+
             BuiltInVariable("gl_MeshVerticesNV", "gl_PositionPerViewNV",     EbvPositionPerViewNV,     symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_PositionPerViewNV",     EbvPositionPerViewNV,     symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_ClipDistancePerViewNV", EbvClipDistancePerViewNV, symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_ClipDistancePerViewNV", EbvClipDistancePerViewNV, symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_CullDistancePerViewNV", EbvCullDistancePerViewNV, symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_CullDistancePerViewNV", EbvCullDistancePerViewNV, symbolTable);
 
 
-            // Per-primitive builtins
+            // per-primitive builtins
+            symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_PrimitiveID",   1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_Layer",         1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_ViewportIndex", 1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_ViewportMask",  1, &E_GL_NV_mesh_shader);
+
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_PrimitiveID",   EbvPrimitiveId,    symbolTable);
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_PrimitiveID",   EbvPrimitiveId,    symbolTable);
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_Layer",         EbvLayer,          symbolTable);
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_Layer",         EbvLayer,          symbolTable);
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_ViewportIndex", EbvViewportIndex,  symbolTable);
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_ViewportIndex", EbvViewportIndex,  symbolTable);
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_ViewportMask",  EbvViewportMaskNV, symbolTable);
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_ViewportMask",  EbvViewportMaskNV, symbolTable);
-            // Per-view builtins
+
+            // per-view per-primitive builtins
+            symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_LayerPerViewNV",        1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MeshPrimitivesNV", "gl_ViewportMaskPerViewNV", 1, &E_GL_NV_mesh_shader);
+
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_LayerPerViewNV",        EbvLayerPerViewNV,        symbolTable);
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_LayerPerViewNV",        EbvLayerPerViewNV,        symbolTable);
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_ViewportMaskPerViewNV", EbvViewportMaskPerViewNV, symbolTable);
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_ViewportMaskPerViewNV", EbvViewportMaskPerViewNV, symbolTable);
 
 
+            // other builtins
             symbolTable.setVariableExtensions("gl_PrimitiveCountNV",     1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_PrimitiveCountNV",     1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_PrimitiveIndicesNV",   1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_PrimitiveIndicesNV",   1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_MeshViewCountNV",      1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_MeshViewCountNV",      1, &E_GL_NV_mesh_shader);
@@ -8758,11 +8852,13 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
             BuiltInVariable("gl_GlobalInvocationID",   EbvGlobalInvocationId,   symbolTable);
             BuiltInVariable("gl_GlobalInvocationID",   EbvGlobalInvocationId,   symbolTable);
             BuiltInVariable("gl_LocalInvocationIndex", EbvLocalInvocationIndex, symbolTable);
             BuiltInVariable("gl_LocalInvocationIndex", EbvLocalInvocationIndex, symbolTable);
 
 
+            // builtin constants
             symbolTable.setVariableExtensions("gl_MaxMeshOutputVerticesNV",   1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_MaxMeshOutputVerticesNV",   1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_MaxMeshOutputPrimitivesNV", 1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_MaxMeshOutputPrimitivesNV", 1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_MaxMeshWorkGroupSizeNV",    1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_MaxMeshWorkGroupSizeNV",    1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_MaxMeshViewCountNV",        1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_MaxMeshViewCountNV",        1, &E_GL_NV_mesh_shader);
 
 
+            // builtin functions
             symbolTable.setFunctionExtensions("barrier",                      1, &E_GL_NV_mesh_shader);
             symbolTable.setFunctionExtensions("barrier",                      1, &E_GL_NV_mesh_shader);
             symbolTable.setFunctionExtensions("memoryBarrierShared",          1, &E_GL_NV_mesh_shader);
             symbolTable.setFunctionExtensions("memoryBarrierShared",          1, &E_GL_NV_mesh_shader);
             symbolTable.setFunctionExtensions("groupMemoryBarrier",           1, &E_GL_NV_mesh_shader);
             symbolTable.setFunctionExtensions("groupMemoryBarrier",           1, &E_GL_NV_mesh_shader);
@@ -8804,7 +8900,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         }
         }
 
 
         // GL_KHR_shader_subgroup
         // GL_KHR_shader_subgroup
-        if (spvVersion.vulkan > 0) {
+        if ((profile == EEsProfile && version >= 310) ||
+            (profile != EEsProfile && version >= 140)) {
             symbolTable.setVariableExtensions("gl_NumSubgroups",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_NumSubgroups",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupID",           1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupID",           1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupSize",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupSize",         1, &E_GL_KHR_shader_subgroup_basic);
@@ -8837,6 +8934,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
             symbolTable.setVariableExtensions("gl_LocalInvocationID",    1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_LocalInvocationID",    1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_GlobalInvocationID",   1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_GlobalInvocationID",   1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_LocalInvocationIndex", 1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_LocalInvocationIndex", 1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MeshViewCountNV",      1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MeshViewIndicesNV",    1, &E_GL_NV_mesh_shader);
 
 
             BuiltInVariable("gl_TaskCountNV",          EbvTaskCountNV,          symbolTable);
             BuiltInVariable("gl_TaskCountNV",          EbvTaskCountNV,          symbolTable);
             BuiltInVariable("gl_WorkGroupSize",        EbvWorkGroupSize,        symbolTable);
             BuiltInVariable("gl_WorkGroupSize",        EbvWorkGroupSize,        symbolTable);
@@ -8844,8 +8943,11 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
             BuiltInVariable("gl_LocalInvocationID",    EbvLocalInvocationId,    symbolTable);
             BuiltInVariable("gl_LocalInvocationID",    EbvLocalInvocationId,    symbolTable);
             BuiltInVariable("gl_GlobalInvocationID",   EbvGlobalInvocationId,   symbolTable);
             BuiltInVariable("gl_GlobalInvocationID",   EbvGlobalInvocationId,   symbolTable);
             BuiltInVariable("gl_LocalInvocationIndex", EbvLocalInvocationIndex, symbolTable);
             BuiltInVariable("gl_LocalInvocationIndex", EbvLocalInvocationIndex, symbolTable);
+            BuiltInVariable("gl_MeshViewCountNV",      EbvMeshViewCountNV,      symbolTable);
+            BuiltInVariable("gl_MeshViewIndicesNV",    EbvMeshViewIndicesNV,    symbolTable);
 
 
             symbolTable.setVariableExtensions("gl_MaxTaskWorkGroupSizeNV", 1, &E_GL_NV_mesh_shader);
             symbolTable.setVariableExtensions("gl_MaxTaskWorkGroupSizeNV", 1, &E_GL_NV_mesh_shader);
+            symbolTable.setVariableExtensions("gl_MaxMeshViewCountNV",     1, &E_GL_NV_mesh_shader);
 
 
             symbolTable.setFunctionExtensions("barrier",                   1, &E_GL_NV_mesh_shader);
             symbolTable.setFunctionExtensions("barrier",                   1, &E_GL_NV_mesh_shader);
             symbolTable.setFunctionExtensions("memoryBarrierShared",       1, &E_GL_NV_mesh_shader);
             symbolTable.setFunctionExtensions("memoryBarrierShared",       1, &E_GL_NV_mesh_shader);
@@ -8888,7 +8990,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         }
         }
 
 
         // GL_KHR_shader_subgroup
         // GL_KHR_shader_subgroup
-        if (spvVersion.vulkan > 0) {
+        if ((profile == EEsProfile && version >= 310) ||
+            (profile != EEsProfile && version >= 140)) {
             symbolTable.setVariableExtensions("gl_NumSubgroups",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_NumSubgroups",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupID",           1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupID",           1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupSize",         1, &E_GL_KHR_shader_subgroup_basic);
             symbolTable.setVariableExtensions("gl_SubgroupSize",         1, &E_GL_KHR_shader_subgroup_basic);
@@ -9314,7 +9417,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         }
         }
 
 
         // GL_KHR_shader_subgroup
         // GL_KHR_shader_subgroup
-        if (spvVersion.vulkan > 0) {
+        if ((profile == EEsProfile && version >= 310) ||
+            (profile != EEsProfile && version >= 140)) {
             symbolTable.relateToOperator("subgroupBarrier",                 EOpSubgroupBarrier);
             symbolTable.relateToOperator("subgroupBarrier",                 EOpSubgroupBarrier);
             symbolTable.relateToOperator("subgroupMemoryBarrier",           EOpSubgroupMemoryBarrier);
             symbolTable.relateToOperator("subgroupMemoryBarrier",           EOpSubgroupMemoryBarrier);
             symbolTable.relateToOperator("subgroupMemoryBarrierBuffer",     EOpSubgroupMemoryBarrierBuffer);
             symbolTable.relateToOperator("subgroupMemoryBarrierBuffer",     EOpSubgroupMemoryBarrierBuffer);
@@ -9457,6 +9561,9 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
             symbolTable.relateToOperator("fwidthCoarse",EOpFwidthCoarse);
             symbolTable.relateToOperator("fwidthCoarse",EOpFwidthCoarse);
         }
         }
 #endif
 #endif
+        symbolTable.relateToOperator("coopMatLoadNV",              EOpCooperativeMatrixLoad);
+        symbolTable.relateToOperator("coopMatStoreNV",             EOpCooperativeMatrixStore);
+        symbolTable.relateToOperator("coopMatMulAddNV",            EOpCooperativeMatrixMulAdd);
         break;
         break;
 
 
 #ifdef NV_EXTENSIONS
 #ifdef NV_EXTENSIONS
@@ -9556,6 +9663,12 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         BuiltInVariable("gl_in", "gl_BackSecondaryColor",  EbvBackSecondaryColor,  symbolTable);
         BuiltInVariable("gl_in", "gl_BackSecondaryColor",  EbvBackSecondaryColor,  symbolTable);
         BuiltInVariable("gl_in", "gl_TexCoord",            EbvTexCoord,            symbolTable);
         BuiltInVariable("gl_in", "gl_TexCoord",            EbvTexCoord,            symbolTable);
         BuiltInVariable("gl_in", "gl_FogFragCoord",        EbvFogFragCoord,        symbolTable);
         BuiltInVariable("gl_in", "gl_FogFragCoord",        EbvFogFragCoord,        symbolTable);
+
+        // extension requirements
+        if (profile == EEsProfile) {
+            symbolTable.setVariableExtensions("gl_in", "gl_PointSize", Num_AEP_tessellation_point_size, AEP_tessellation_point_size);
+        }
+
         break;
         break;
 
 
     default:
     default:

+ 190 - 4
src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp

@@ -119,6 +119,62 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn
     if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
     if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
         return nullptr;
         return nullptr;
 
 
+    // Convert "reference +/- int" and "reference - reference" to integer math
+    if ((op == EOpAdd || op == EOpSub) && extensionRequested(E_GL_EXT_buffer_reference2)) {
+
+        // No addressing math on struct with unsized array.
+        if ((left->getBasicType() == EbtReference && left->getType().getReferentType()->containsUnsizedArray()) ||
+            (right->getBasicType() == EbtReference && right->getType().getReferentType()->containsUnsizedArray())) {
+            return nullptr;
+        }
+
+        if (left->getBasicType() == EbtReference && isTypeInt(right->getBasicType())) {
+            const TType& referenceType = left->getType();
+            TIntermConstantUnion* size = addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(left->getType()), loc, true);
+            left  = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64));
+
+            right = createConversion(EbtInt64, right);
+            right = addBinaryMath(EOpMul, right, size, loc);
+
+            TIntermTyped *node = addBinaryMath(op, left, right, loc);
+            node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType);
+            return node;
+        }
+
+        if (op == EOpAdd && right->getBasicType() == EbtReference && isTypeInt(left->getBasicType())) {
+            const TType& referenceType = right->getType();
+            TIntermConstantUnion* size = addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(right->getType()), loc, true);
+            right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64));
+
+            left  = createConversion(EbtInt64, left);
+            left  = addBinaryMath(EOpMul, left, size, loc);
+
+            TIntermTyped *node = addBinaryMath(op, left, right, loc);
+            node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType);
+            return node;
+        }
+
+        if (op == EOpSub && left->getBasicType() == EbtReference && right->getBasicType() == EbtReference) {
+            TIntermConstantUnion* size = addConstantUnion((long long)computeBufferReferenceTypeSize(left->getType()), loc, true);
+
+            left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64));
+            right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64));
+
+            left = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, left, TType(EbtInt64));
+            right = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, right, TType(EbtInt64));
+
+            left = addBinaryMath(EOpSub, left, right, loc);
+
+            TIntermTyped *node = addBinaryMath(EOpDiv, left, size, loc);
+            return node;
+        }
+
+        // No other math operators supported on references
+        if (left->getBasicType() == EbtReference || right->getBasicType() == EbtReference) {
+            return nullptr;
+        }
+    }
+
     // Try converting the children's base types to compatible types.
     // Try converting the children's base types to compatible types.
     auto children = addConversion(op, left, right);
     auto children = addConversion(op, left, right);
     left = std::get<0>(children);
     left = std::get<0>(children);
@@ -231,6 +287,26 @@ TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TInterm
     if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
     if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
         return nullptr;
         return nullptr;
 
 
+    // Convert "reference += int" to "reference = reference + int". We need this because the
+    // "reference + int" calculation involves a cast back to the original type, which makes it
+    // not an lvalue.
+    if ((op == EOpAddAssign || op == EOpSubAssign) && left->getBasicType() == EbtReference &&
+        extensionRequested(E_GL_EXT_buffer_reference2)) {
+
+        if (!(right->getType().isScalar() && right->getType().isIntegerDomain()))
+            return nullptr;
+
+        TIntermTyped* node = addBinaryMath(op == EOpAddAssign ? EOpAdd : EOpSub, left, right, loc);
+        if (!node)
+            return nullptr;
+
+        TIntermSymbol* symbol = left->getAsSymbolNode();
+        left = addSymbol(*symbol);
+
+        node = addAssign(EOpAssign, left, node, loc);
+        return node;
+    }
+
     //
     //
     // Like adding binary math, except the conversion can only go
     // Like adding binary math, except the conversion can only go
     // from right to left.
     // from right to left.
@@ -410,7 +486,7 @@ TIntermTyped* TIntermediate::addBuiltInFunctionCall(const TSourceLoc& loc, TOper
 //
 //
 // This is the safe way to change the operator on an aggregate, as it
 // This is the safe way to change the operator on an aggregate, as it
 // does lots of error checking and fixing.  Especially for establishing
 // does lots of error checking and fixing.  Especially for establishing
-// a function call's operation on it's set of parameters.  Sequences
+// a function call's operation on its set of parameters.  Sequences
 // of instructions are also aggregates, but they just directly set
 // of instructions are also aggregates, but they just directly set
 // their operator to EOpSequence.
 // their operator to EOpSequence.
 //
 //
@@ -498,6 +574,58 @@ TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped
 
 
     TOperator newOp = EOpNull;
     TOperator newOp = EOpNull;
 
 
+    // Certain explicit conversions are allowed conditionally
+    bool arithemeticInt8Enabled = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) ||
+                                  extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int8);
+#ifdef AMD_EXTENSIONS
+    bool arithemeticInt16Enabled = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) ||
+                                   extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int16) ||
+                                   extensionRequested(E_GL_AMD_gpu_shader_int16);
+
+    bool arithemeticFloat16Enabled = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) ||
+                                     extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_float16) ||
+                                     extensionRequested(E_GL_AMD_gpu_shader_half_float);
+#else
+    bool arithemeticInt16Enabled = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) ||
+                                   extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_int16);
+
+    bool arithemeticFloat16Enabled = extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types) ||
+                                     extensionRequested(E_GL_EXT_shader_explicit_arithmetic_types_float16);
+#endif
+    bool convertToIntTypes = (convertTo == EbtInt8  || convertTo == EbtUint8  ||
+                              convertTo == EbtInt16 || convertTo == EbtUint16 ||
+                              convertTo == EbtInt   || convertTo == EbtUint   ||
+                              convertTo == EbtInt64 || convertTo == EbtUint64);
+
+    bool convertFromIntTypes = (node->getBasicType() == EbtInt8  || node->getBasicType() == EbtUint8  ||
+                                node->getBasicType() == EbtInt16 || node->getBasicType() == EbtUint16 ||
+                                node->getBasicType() == EbtInt   || node->getBasicType() == EbtUint   ||
+                                node->getBasicType() == EbtInt64 || node->getBasicType() == EbtUint64);
+
+    bool convertToFloatTypes = (convertTo == EbtFloat16 || convertTo == EbtFloat || convertTo == EbtDouble);
+
+    bool convertFromFloatTypes = (node->getBasicType() == EbtFloat16 ||
+                                  node->getBasicType() == EbtFloat ||
+                                  node->getBasicType() == EbtDouble);
+
+    if (! arithemeticInt8Enabled) {
+        if (((convertTo == EbtInt8 || convertTo == EbtUint8) && ! convertFromIntTypes) ||
+            ((node->getBasicType() == EbtInt8 || node->getBasicType() == EbtUint8) && ! convertToIntTypes))
+            return nullptr;
+    }
+
+    if (! arithemeticInt16Enabled) {
+        if (((convertTo == EbtInt16 || convertTo == EbtUint16) && ! convertFromIntTypes) ||
+            ((node->getBasicType() == EbtInt16 || node->getBasicType() == EbtUint16) && ! convertToIntTypes))
+            return nullptr;
+    }
+
+    if (! arithemeticFloat16Enabled) {
+        if ((convertTo == EbtFloat16 && ! convertFromFloatTypes) ||
+            (node->getBasicType() == EbtFloat16 && ! convertToFloatTypes))
+            return nullptr;
+    }
+
     switch (convertTo) {
     switch (convertTo) {
     case EbtDouble:
     case EbtDouble:
         switch (node->getBasicType()) {
         switch (node->getBasicType()) {
@@ -725,6 +853,11 @@ TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped
     return newNode;
     return newNode;
 }
 }
 
 
+TIntermTyped* TIntermediate::addConversion(TBasicType convertTo, TIntermTyped* node) const
+{
+    return createConversion(convertTo, node);
+}
+
 // For converting a pair of operands to a binary operation to compatible
 // For converting a pair of operands to a binary operation to compatible
 // types with each other, relative to the operation in 'op'.
 // types with each other, relative to the operation in 'op'.
 // This does not cover assignment operations, which is asymmetric in that the
 // This does not cover assignment operations, which is asymmetric in that the
@@ -738,7 +871,7 @@ TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped
 // Returns the converted pair of nodes.
 // Returns the converted pair of nodes.
 // Returns <nullptr, nullptr> when there is no conversion.
 // Returns <nullptr, nullptr> when there is no conversion.
 std::tuple<TIntermTyped*, TIntermTyped*>
 std::tuple<TIntermTyped*, TIntermTyped*>
-TIntermediate::addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1) const
+TIntermediate::addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1)
 {
 {
     if (!isConversionAllowed(op, node0) || !isConversionAllowed(op, node1))
     if (!isConversionAllowed(op, node0) || !isConversionAllowed(op, node1))
         return std::make_tuple(nullptr, nullptr);
         return std::make_tuple(nullptr, nullptr);
@@ -751,6 +884,10 @@ TIntermediate::addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* no
         // If differing arrays, then no conversions.
         // If differing arrays, then no conversions.
         if (node0->getType().isArray() || node1->getType().isArray())
         if (node0->getType().isArray() || node1->getType().isArray())
             return std::make_tuple(nullptr, nullptr);
             return std::make_tuple(nullptr, nullptr);
+
+        // No implicit conversions for operations involving cooperative matrices
+        if (node0->getType().isCoopMat() || node1->getType().isCoopMat())
+            return std::make_tuple(node0, node1);
     }
     }
 
 
     auto promoteTo = std::make_tuple(EbtNumTypes, EbtNumTypes);
     auto promoteTo = std::make_tuple(EbtNumTypes, EbtNumTypes);
@@ -867,7 +1004,7 @@ TIntermediate::addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* no
 //
 //
 // Return nullptr if a conversion can't be done.
 // Return nullptr if a conversion can't be done.
 //
 //
-TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) const
+TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
 {
 {
     if (!isConversionAllowed(op, node))
     if (!isConversionAllowed(op, node))
         return nullptr;
         return nullptr;
@@ -983,6 +1120,15 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
 
 
     case EOpSequence:
     case EOpSequence:
     case EOpConstructStruct:
     case EOpConstructStruct:
+    case EOpConstructCooperativeMatrix:
+
+        if (type.getBasicType() == EbtReference || node->getType().getBasicType() == EbtReference) {
+            // types must match to assign a reference
+            if (type == node->getType())
+                return node;
+            else
+                return nullptr;
+        }
 
 
         if (type.getBasicType() == node->getType().getBasicType())
         if (type.getBasicType() == node->getType().getBasicType())
             return node;
             return node;
@@ -990,7 +1136,7 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
         if (canImplicitlyPromote(node->getBasicType(), type.getBasicType(), op))
         if (canImplicitlyPromote(node->getBasicType(), type.getBasicType(), op))
             promoteTo = type.getBasicType();
             promoteTo = type.getBasicType();
         else
         else
-           return nullptr;
+            return nullptr;
         break;
         break;
 
 
     // For GLSL, there are no conversions needed; the shift amount just needs to be an
     // For GLSL, there are no conversions needed; the shift amount just needs to be an
@@ -1839,6 +1985,9 @@ TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const
     if (type.getQualifier().nonUniform)
     if (type.getQualifier().nonUniform)
         return EOpConstructNonuniform;
         return EOpConstructNonuniform;
 
 
+    if (type.isCoopMat())
+        return EOpConstructCooperativeMatrix;
+
     switch (type.getBasicType()) {
     switch (type.getBasicType()) {
     case EbtStruct:
     case EbtStruct:
         op = EOpConstructStruct;
         op = EOpConstructStruct;
@@ -2131,6 +2280,9 @@ TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const
             }
             }
         }
         }
         break;
         break;
+    case EbtReference:
+        op = EOpConstructReference;
+        break;
     default:
     default:
         break;
         break;
     }
     }
@@ -3308,6 +3460,40 @@ bool TIntermediate::promoteBinary(TIntermBinary& node)
         break;
         break;
     }
     }
 
 
+    if (left->getType().isCoopMat() || right->getType().isCoopMat()) {
+        if (left->getType().isCoopMat() && right->getType().isCoopMat() &&
+            *left->getType().getTypeParameters() != *right->getType().getTypeParameters()) {
+            return false;
+        }
+        switch (op) {
+        case EOpMul:
+        case EOpMulAssign:
+            if (left->getType().isCoopMat() && right->getType().isCoopMat()) {
+                return false;
+            }
+            if (op == EOpMulAssign && right->getType().isCoopMat()) {
+                return false;
+            }
+            node.setOp(op == EOpMulAssign ? EOpMatrixTimesScalarAssign : EOpMatrixTimesScalar);
+            if (right->getType().isCoopMat()) {
+                node.setType(right->getType());
+            }
+            return true;
+        case EOpAdd:
+        case EOpSub:
+        case EOpDiv:
+        case EOpAssign:
+            // These require both to be cooperative matrices
+            if (!left->getType().isCoopMat() || !right->getType().isCoopMat()) {
+                return false;
+            }
+            return true;
+        default:
+            break;
+        }
+        return false;
+    }
+
     // Finish handling the case, for all ops, where both operands are scalars.
     // Finish handling the case, for all ops, where both operands are scalars.
     if (left->isScalar() && right->isScalar())
     if (left->isScalar() && right->isScalar())
         return true;
         return true;

+ 4 - 0
src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp

@@ -152,6 +152,10 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op,
     case EvqBuffer:
     case EvqBuffer:
         if (node->getQualifier().readonly)
         if (node->getQualifier().readonly)
             message = "can't modify a readonly buffer";
             message = "can't modify a readonly buffer";
+#ifdef NV_EXTENSIONS
+        if (node->getQualifier().layoutShaderRecordNV)
+            message = "can't modify a shaderrecordnv qualified buffer";
+#endif
         break;
         break;
 #ifdef NV_EXTENSIONS
 #ifdef NV_EXTENSIONS
     case EvqHitAttrNV:
     case EvqHitAttrNV:

File diff suppressed because it is too large
+ 407 - 89
src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp


+ 5 - 4
src/libraries/glslang/glslang/MachineIndependent/ParseHelper.h

@@ -299,14 +299,14 @@ public:
     void fixIoArraySize(const TSourceLoc&, TType&);
     void fixIoArraySize(const TSourceLoc&, TType&);
     void ioArrayCheck(const TSourceLoc&, const TType&, const TString& identifier);
     void ioArrayCheck(const TSourceLoc&, const TType&, const TString& identifier);
     void handleIoResizeArrayAccess(const TSourceLoc&, TIntermTyped* base);
     void handleIoResizeArrayAccess(const TSourceLoc&, TIntermTyped* base);
-    void checkIoArraysConsistency(const TSourceLoc&, bool tailOnly = false, bool isPerPrimitive = false);
-    int getIoArrayImplicitSize(bool isPerPrimitive = false) const;
+    void checkIoArraysConsistency(const TSourceLoc&, bool tailOnly = false);
+    int getIoArrayImplicitSize(const TQualifier&, TString* featureString = nullptr) const;
     void checkIoArrayConsistency(const TSourceLoc&, int requiredSize, const char* feature, TType&, const TString&);
     void checkIoArrayConsistency(const TSourceLoc&, int requiredSize, const char* feature, TType&, const TString&);
 
 
     TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right);
     TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right);
     TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode);
     TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode);
     TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field);
     TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field);
-    void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, const TString& field);
+    void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, int member, const TString& memberName);
     TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
     TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
     TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
     TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
     TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
     TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
@@ -337,7 +337,7 @@ public:
     void globalCheck(const TSourceLoc&, const char* token);
     void globalCheck(const TSourceLoc&, const char* token);
     bool constructorError(const TSourceLoc&, TIntermNode*, TFunction&, TOperator, TType&);
     bool constructorError(const TSourceLoc&, TIntermNode*, TFunction&, TOperator, TType&);
     bool constructorTextureSamplerError(const TSourceLoc&, const TFunction&);
     bool constructorTextureSamplerError(const TSourceLoc&, const TFunction&);
-    void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&);
+    void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&, const char *sizeType);
     bool arrayQualifierError(const TSourceLoc&, const TQualifier&);
     bool arrayQualifierError(const TSourceLoc&, const TQualifier&);
     bool arrayError(const TSourceLoc&, const TType&);
     bool arrayError(const TSourceLoc&, const TType&);
     void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&);
     void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&);
@@ -370,6 +370,7 @@ public:
     void nestedStructCheck(const TSourceLoc&);
     void nestedStructCheck(const TSourceLoc&);
     void arrayObjectCheck(const TSourceLoc&, const TType&, const char* op);
     void arrayObjectCheck(const TSourceLoc&, const TType&, const char* op);
     void opaqueCheck(const TSourceLoc&, const TType&, const char* op);
     void opaqueCheck(const TSourceLoc&, const TType&, const char* op);
+    void referenceCheck(const TSourceLoc&, const TType&, const char* op);
     void storage16BitAssignmentCheck(const TSourceLoc&, const TType&, const char* op);
     void storage16BitAssignmentCheck(const TSourceLoc&, const TType&, const char* op);
     void specializationCheck(const TSourceLoc&, const TType&, const char* op);
     void specializationCheck(const TSourceLoc&, const TType&, const char* op);
     void structTypeCheck(const TSourceLoc&, TPublicType&);
     void structTypeCheck(const TSourceLoc&, TPublicType&);

+ 24 - 3
src/libraries/glslang/glslang/MachineIndependent/Scan.cpp

@@ -592,6 +592,8 @@ void TScanContext::fillInKeywordMap()
 
 
     (*KeywordMap)["samplerExternalOES"] =      SAMPLEREXTERNALOES; // GL_OES_EGL_image_external
     (*KeywordMap)["samplerExternalOES"] =      SAMPLEREXTERNALOES; // GL_OES_EGL_image_external
 
 
+    (*KeywordMap)["__samplerExternal2DY2YEXT"] = SAMPLEREXTERNAL2DY2YEXT; // GL_EXT_YUV_target
+
     (*KeywordMap)["sampler"] =                 SAMPLER;
     (*KeywordMap)["sampler"] =                 SAMPLER;
     (*KeywordMap)["samplerShadow"] =           SAMPLERSHADOW;
     (*KeywordMap)["samplerShadow"] =           SAMPLERSHADOW;
 
 
@@ -712,6 +714,8 @@ void TScanContext::fillInKeywordMap()
     (*KeywordMap)["taskNV"] =                  PERTASKNV;
     (*KeywordMap)["taskNV"] =                  PERTASKNV;
 #endif
 #endif
 
 
+    (*KeywordMap)["fcoopmatNV"] =              FCOOPMATNV;
+
     ReservedSet = new std::unordered_set<const char*, str_hash, str_eq>;
     ReservedSet = new std::unordered_set<const char*, str_hash, str_eq>;
 
 
     ReservedSet->insert("common");
     ReservedSet->insert("common");
@@ -776,7 +780,7 @@ int TScanContext::tokenize(TPpContext* pp, TParserToken& token)
         loc = ppToken.loc;
         loc = ppToken.loc;
         parserToken->sType.lex.loc = loc;
         parserToken->sType.lex.loc = loc;
         switch (token) {
         switch (token) {
-        case ';':  afterType = false;   return SEMICOLON;
+        case ';':  afterType = false; afterBuffer = false; return SEMICOLON;
         case ',':  afterType = false;   return COMMA;
         case ',':  afterType = false;   return COMMA;
         case ':':                       return COLON;
         case ':':                       return COLON;
         case '=':  afterType = false;   return EQUAL;
         case '=':  afterType = false;   return EQUAL;
@@ -798,7 +802,7 @@ int TScanContext::tokenize(TPpContext* pp, TParserToken& token)
         case '?':                       return QUESTION;
         case '?':                       return QUESTION;
         case '[':                       return LEFT_BRACKET;
         case '[':                       return LEFT_BRACKET;
         case ']':                       return RIGHT_BRACKET;
         case ']':                       return RIGHT_BRACKET;
-        case '{':  afterStruct = false; return LEFT_BRACE;
+        case '{':  afterStruct = false; afterBuffer = false; return LEFT_BRACE;
         case '}':                       return RIGHT_BRACE;
         case '}':                       return RIGHT_BRACE;
         case '\\':
         case '\\':
             parseContext.error(loc, "illegal use of escape character", "\\", "");
             parseContext.error(loc, "illegal use of escape character", "\\", "");
@@ -945,6 +949,7 @@ int TScanContext::tokenizeIdentifier()
         return keyword;
         return keyword;
 
 
     case BUFFER:
     case BUFFER:
+        afterBuffer = true;
         if ((parseContext.profile == EEsProfile && parseContext.version < 310) ||
         if ((parseContext.profile == EEsProfile && parseContext.version < 310) ||
             (parseContext.profile != EEsProfile && parseContext.version < 430))
             (parseContext.profile != EEsProfile && parseContext.version < 430))
             return identifierOrType();
             return identifierOrType();
@@ -1428,6 +1433,13 @@ int TScanContext::tokenizeIdentifier()
             return keyword;
             return keyword;
         return identifierOrType();
         return identifierOrType();
 
 
+    case SAMPLEREXTERNAL2DY2YEXT:
+        afterType = true;
+        if (parseContext.symbolTable.atBuiltInLevel() ||
+            parseContext.extensionTurnedOn(E_GL_EXT_YUV_target))
+            return keyword;
+        return identifierOrType();
+
     case TEXTURE2D:
     case TEXTURE2D:
     case TEXTURECUBE:
     case TEXTURECUBE:
     case TEXTURECUBEARRAY:
     case TEXTURECUBEARRAY:
@@ -1621,6 +1633,13 @@ int TScanContext::tokenizeIdentifier()
         return identifierOrType();
         return identifierOrType();
 #endif
 #endif
 
 
+    case FCOOPMATNV:
+        afterType = true;
+        if (parseContext.symbolTable.atBuiltInLevel() ||
+            parseContext.extensionTurnedOn(E_GL_NV_cooperative_matrix))
+            return keyword;
+        return identifierOrType();
+
     default:
     default:
         parseContext.infoSink.info.message(EPrefixInternalError, "Unknown glslang keyword", loc);
         parseContext.infoSink.info.message(EPrefixInternalError, "Unknown glslang keyword", loc);
         return 0;
         return 0;
@@ -1636,7 +1655,9 @@ int TScanContext::identifierOrType()
     parserToken->sType.lex.symbol = parseContext.symbolTable.find(*parserToken->sType.lex.string);
     parserToken->sType.lex.symbol = parseContext.symbolTable.find(*parserToken->sType.lex.string);
     if ((afterType == false && afterStruct == false) && parserToken->sType.lex.symbol != nullptr) {
     if ((afterType == false && afterStruct == false) && parserToken->sType.lex.symbol != nullptr) {
         if (const TVariable* variable = parserToken->sType.lex.symbol->getAsVariable()) {
         if (const TVariable* variable = parserToken->sType.lex.symbol->getAsVariable()) {
-            if (variable->isUserType()) {
+            if (variable->isUserType() &&
+                // treat redeclaration of forward-declared buffer/uniform reference as an identifier
+                !(variable->getType().getBasicType() == EbtReference && afterBuffer)) {
                 afterType = true;
                 afterType = true;
 
 
                 return TYPE_NAME;
                 return TYPE_NAME;

+ 2 - 1
src/libraries/glslang/glslang/MachineIndependent/ScanContext.h

@@ -53,7 +53,7 @@ public:
     explicit TScanContext(TParseContextBase& pc) :
     explicit TScanContext(TParseContextBase& pc) :
         parseContext(pc),
         parseContext(pc),
         afterType(false), afterStruct(false),
         afterType(false), afterStruct(false),
-        field(false) { }
+        field(false), afterBuffer(false) { }
     virtual ~TScanContext() { }
     virtual ~TScanContext() { }
 
 
     static void fillInKeywordMap();
     static void fillInKeywordMap();
@@ -81,6 +81,7 @@ protected:
     bool afterType;           // true if we've recognized a type, so can only be looking for an identifier
     bool afterType;           // true if we've recognized a type, so can only be looking for an identifier
     bool afterStruct;         // true if we've recognized the STRUCT keyword, so can only be looking for an identifier
     bool afterStruct;         // true if we've recognized the STRUCT keyword, so can only be looking for an identifier
     bool field;               // true if we're on a field, right after a '.'
     bool field;               // true if we're on a field, right after a '.'
+    bool afterBuffer;         // true if we've recognized the BUFFER keyword
     TSourceLoc loc;
     TSourceLoc loc;
     TParserToken* parserToken;
     TParserToken* parserToken;
     TPpToken* ppToken;
     TPpToken* ppToken;

+ 55 - 26
src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp

@@ -377,6 +377,8 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable,  TS
                                    infoSink, commonTable, symbolTables);
                                    infoSink, commonTable, symbolTables);
 #endif
 #endif
 
 
+
+
     return true;
     return true;
 }
 }
 
 
@@ -474,6 +476,16 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp
     glslang::ReleaseGlobalLock();
     glslang::ReleaseGlobalLock();
 }
 }
 
 
+// Function to Print all builtins
+void DumpBuiltinSymbolTable(TInfoSink& infoSink, const TSymbolTable& symbolTable)
+{
+    infoSink.debug << "BuiltinSymbolTable {\n";
+
+    symbolTable.dump(infoSink, true);
+
+    infoSink.debug << "}\n";
+}
+
 // Return true if the shader was correctly specified for version/profile/stage.
 // Return true if the shader was correctly specified for version/profile/stage.
 bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNotFirst, int defaultVersion,
 bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNotFirst, int defaultVersion,
                           EShSource source, int& version, EProfile& profile, const SpvVersion& spvVersion)
                           EShSource source, int& version, EProfile& profile, const SpvVersion& spvVersion)
@@ -879,8 +891,11 @@ bool ProcessDeferred(
         intermediate.setHlslOffsets();
         intermediate.setHlslOffsets();
     if (messages & EShMsgDebugInfo) {
     if (messages & EShMsgDebugInfo) {
         intermediate.setSourceFile(names[numPre]);
         intermediate.setSourceFile(names[numPre]);
-        for (int s = 0; s < numStrings; ++s)
-            intermediate.addSourceText(strings[numPre + s]);
+        for (int s = 0; s < numStrings; ++s) {
+            // The string may not be null-terminated, so make sure we provide
+            // the length along with the string.
+            intermediate.addSourceText(strings[numPre + s], lengths[numPre + s]);
+        }
     }
     }
     SetupBuiltinSymbolTable(version, profile, spvVersion, source);
     SetupBuiltinSymbolTable(version, profile, spvVersion, source);
 
 
@@ -902,6 +917,9 @@ bool ProcessDeferred(
         return false;
         return false;
     }
     }
 
 
+    if (messages & EShMsgBuiltinSymbolTable)
+        DumpBuiltinSymbolTable(compiler->infoSink, *symbolTable);
+
     //
     //
     // Now we can process the full shader under proper symbols and rules.
     // Now we can process the full shader under proper symbols and rules.
     //
     //
@@ -1332,7 +1350,7 @@ void ShDestruct(ShHandle handle)
 //
 //
 // Cleanup symbol tables
 // Cleanup symbol tables
 //
 //
-int __fastcall ShFinalize()
+int ShFinalize()
 {
 {
     glslang::GetGlobalLock();
     glslang::GetGlobalLock();
     --NumberOfClients;
     --NumberOfClients;
@@ -1963,12 +1981,27 @@ const char* TProgram::getInfoDebugLog()
 // Reflection implementation.
 // Reflection implementation.
 //
 //
 
 
-bool TProgram::buildReflection()
+bool TProgram::buildReflection(int opts)
 {
 {
     if (! linked || reflection)
     if (! linked || reflection)
         return false;
         return false;
 
 
-    reflection = new TReflection;
+    int firstStage = EShLangVertex, lastStage = EShLangFragment;
+
+    if (opts & EShReflectionIntermediateIO) {
+        // if we're reflecting intermediate I/O, determine the first and last stage linked and use those as the
+        // boundaries for which stages generate pipeline inputs/outputs
+        firstStage = EShLangCount;
+        lastStage = 0;
+        for (int s = 0; s < EShLangCount; ++s) {
+            if (intermediate[s]) {
+                firstStage = std::min(firstStage, s);
+                lastStage = std::max(lastStage, s);
+            }
+        }
+    }
+
+    reflection = new TReflection((EShReflectionOptions)opts, (EShLanguage)firstStage, (EShLanguage)lastStage);
 
 
     for (int s = 0; s < EShLangCount; ++s) {
     for (int s = 0; s < EShLangCount; ++s) {
         if (intermediate[s]) {
         if (intermediate[s]) {
@@ -1980,27 +2013,23 @@ bool TProgram::buildReflection()
     return true;
     return true;
 }
 }
 
 
-int TProgram::getNumLiveUniformVariables() const             { return reflection->getNumUniforms(); }
-int TProgram::getNumLiveUniformBlocks() const                { return reflection->getNumUniformBlocks(); }
-const char* TProgram::getUniformName(int index) const        { return reflection->getUniform(index).name.c_str(); }
-const char* TProgram::getUniformBlockName(int index) const   { return reflection->getUniformBlock(index).name.c_str(); }
-int TProgram::getUniformBlockSize(int index) const           { return reflection->getUniformBlock(index).size; }
-int TProgram::getUniformIndex(const char* name) const        { return reflection->getIndex(name); }
-int TProgram::getUniformBinding(int index) const             { return reflection->getUniform(index).getBinding(); }
-EShLanguageMask TProgram::getUniformStages(int index) const  { return reflection->getUniform(index).stages; }
-int TProgram::getUniformBlockBinding(int index) const        { return reflection->getUniformBlock(index).getBinding(); }
-int TProgram::getUniformBlockIndex(int index) const          { return reflection->getUniform(index).index; }
-int TProgram::getUniformBlockCounterIndex(int index) const   { return reflection->getUniformBlock(index).counterIndex; }
-int TProgram::getUniformType(int index) const                { return reflection->getUniform(index).glDefineType; }
-int TProgram::getUniformBufferOffset(int index) const        { return reflection->getUniform(index).offset; }
-int TProgram::getUniformArraySize(int index) const           { return reflection->getUniform(index).size; }
-int TProgram::getNumLiveAttributes() const                   { return reflection->getNumAttributes(); }
-const char* TProgram::getAttributeName(int index) const      { return reflection->getAttribute(index).name.c_str(); }
-int TProgram::getAttributeType(int index) const              { return reflection->getAttribute(index).glDefineType; }
-const TType* TProgram::getAttributeTType(int index) const    { return reflection->getAttribute(index).getType(); }
-const TType* TProgram::getUniformTType(int index) const      { return reflection->getUniform(index).getType(); }
-const TType* TProgram::getUniformBlockTType(int index) const { return reflection->getUniformBlock(index).getType(); }
-unsigned TProgram::getLocalSize(int dim) const               { return reflection->getLocalSize(dim); }
+unsigned TProgram::getLocalSize(int dim) const                      { return reflection->getLocalSize(dim); }
+int TProgram::getReflectionIndex(const char* name) const            { return reflection->getIndex(name); }
+
+int TProgram::getNumUniformVariables() const                          { return reflection->getNumUniforms(); }
+const TObjectReflection& TProgram::getUniform(int index) const        { return reflection->getUniform(index); }
+int TProgram::getNumUniformBlocks() const                             { return reflection->getNumUniformBlocks(); }
+const TObjectReflection& TProgram::getUniformBlock(int index) const   { return reflection->getUniformBlock(index); }
+int TProgram::getNumPipeInputs() const                                { return reflection->getNumPipeInputs(); }
+const TObjectReflection& TProgram::getPipeInput(int index) const      { return reflection->getPipeInput(index); }
+int TProgram::getNumPipeOutputs() const                               { return reflection->getNumPipeOutputs(); }
+const TObjectReflection& TProgram::getPipeOutput(int index) const     { return reflection->getPipeOutput(index); }
+int TProgram::getNumBufferVariables() const                           { return reflection->getNumBufferVariables(); }
+const TObjectReflection& TProgram::getBufferVariable(int index) const { return reflection->getBufferVariable(index); }
+int TProgram::getNumBufferBlocks() const                              { return reflection->getNumStorageBuffers(); }
+const TObjectReflection& TProgram::getBufferBlock(int index) const    { return reflection->getStorageBufferBlock(index); }
+int TProgram::getNumAtomicCounters() const                            { return reflection->getNumAtomicCounters(); }
+const TObjectReflection& TProgram::getAtomicCounter(int index) const  { return reflection->getAtomicCounter(index); }
 
 
 void TProgram::dumpReflection()                      { reflection->dump(); }
 void TProgram::dumpReflection()                      { reflection->dump(); }
 
 

+ 72 - 25
src/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp

@@ -99,6 +99,8 @@ void TType::buildMangledName(TString& mangledName) const
             mangledName += "S";
             mangledName += "S";
         if (sampler.external)
         if (sampler.external)
             mangledName += "E";
             mangledName += "E";
+        if (sampler.yuv)
+            mangledName += "Y";
         switch (sampler.dim) {
         switch (sampler.dim) {
         case Esd1D:       mangledName += "1";  break;
         case Esd1D:       mangledName += "1";  break;
         case Esd2D:       mangledName += "2";  break;
         case Esd2D:       mangledName += "2";  break;
@@ -174,37 +176,77 @@ void TType::buildMangledName(TString& mangledName) const
 // Dump functions.
 // Dump functions.
 //
 //
 
 
-void TVariable::dump(TInfoSink& infoSink) const
+void TSymbol::dumpExtensions(TInfoSink& infoSink) const
 {
 {
-    infoSink.debug << getName().c_str() << ": " << type.getStorageQualifierString() << " " << type.getBasicTypeString();
-    if (type.isArray()) {
-        infoSink.debug << "[0]";
+    int numExtensions = getNumExtensions();
+    if (numExtensions) {
+        infoSink.debug << " <";
+
+        for (int i = 0; i < numExtensions; i++)
+            infoSink.debug << getExtensions()[i] << ",";
+        
+        infoSink.debug << ">";
     }
     }
+}
+
+void TVariable::dump(TInfoSink& infoSink, bool complete) const
+{
+    if (complete) {
+        infoSink.debug << getName().c_str() << ": " << type.getCompleteString();
+        dumpExtensions(infoSink);
+    } else {
+        infoSink.debug << getName().c_str() << ": " << type.getStorageQualifierString() << " "
+                       << type.getBasicTypeString();
+
+        if (type.isArray())
+            infoSink.debug << "[0]";
+    }
+
     infoSink.debug << "\n";
     infoSink.debug << "\n";
 }
 }
 
 
-void TFunction::dump(TInfoSink& infoSink) const
+void TFunction::dump(TInfoSink& infoSink, bool complete) const
 {
 {
-    infoSink.debug << getName().c_str() << ": " <<  returnType.getBasicTypeString() << " " << getMangledName().c_str() << "\n";
+    if (complete) {
+        infoSink.debug << getName().c_str() << ": " << returnType.getCompleteString() << " " << getName().c_str()
+                       << "(";
+
+        int numParams = getParamCount();
+        for (int i = 0; i < numParams; i++) {
+            const TParameter &param = parameters[i];
+            infoSink.debug << param.type->getCompleteString() << " "
+                           << (param.type->isStruct() ? "of " + param.type->getTypeName() + " " : "")
+                           << (param.name ? *param.name : "") << (i < numParams - 1 ? "," : "");
+        }
+
+        infoSink.debug << ")";
+        dumpExtensions(infoSink);
+    } else {
+        infoSink.debug << getName().c_str() << ": " << returnType.getBasicTypeString() << " "
+                       << getMangledName().c_str() << "n";
+    }
+
+    infoSink.debug << "\n";
 }
 }
 
 
-void TAnonMember::dump(TInfoSink& TInfoSink) const
+void TAnonMember::dump(TInfoSink& TInfoSink, bool complete) const
 {
 {
-    TInfoSink.debug << "anonymous member " << getMemberNumber() << " of " << getAnonContainer().getName().c_str() << "\n";
+    TInfoSink.debug << "anonymous member " << getMemberNumber() << " of " << getAnonContainer().getName().c_str()
+                    << "\n";
 }
 }
 
 
-void TSymbolTableLevel::dump(TInfoSink &infoSink) const
+void TSymbolTableLevel::dump(TInfoSink& infoSink, bool complete) const
 {
 {
     tLevel::const_iterator it;
     tLevel::const_iterator it;
     for (it = level.begin(); it != level.end(); ++it)
     for (it = level.begin(); it != level.end(); ++it)
-        (*it).second->dump(infoSink);
+        (*it).second->dump(infoSink, complete);
 }
 }
 
 
-void TSymbolTable::dump(TInfoSink &infoSink) const
+void TSymbolTable::dump(TInfoSink& infoSink, bool complete) const
 {
 {
     for (int level = currentLevel(); level >= 0; --level) {
     for (int level = currentLevel(); level >= 0; --level) {
         infoSink.debug << "LEVEL " << level << "\n";
         infoSink.debug << "LEVEL " << level << "\n";
-        table[level]->dump(infoSink);
+        table[level]->dump(infoSink, complete);
     }
     }
 }
 }
 
 
@@ -287,19 +329,25 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
 {
 {
     type.deepCopy(copyOf.type);
     type.deepCopy(copyOf.type);
     userType = copyOf.userType;
     userType = copyOf.userType;
-    numExtensions = 0;
-    extensions = 0;
-    if (copyOf.numExtensions != 0)
-        setExtensions(copyOf.numExtensions, copyOf.extensions);
+
+    // we don't support specialization-constant subtrees in cloned tables, only extensions
+    constSubtree = nullptr;
+    extensions = nullptr;
+    memberExtensions = nullptr;
+    if (copyOf.getNumExtensions() > 0)
+        setExtensions(copyOf.getNumExtensions(), copyOf.getExtensions());
+    if (copyOf.hasMemberExtensions()) {
+        for (int m = 0; m < (int)copyOf.type.getStruct()->size(); ++m) {
+            if (copyOf.getNumMemberExtensions(m) > 0)
+                setMemberExtensions(m, copyOf.getNumMemberExtensions(m), copyOf.getMemberExtensions(m));
+        }
+    }
 
 
     if (! copyOf.constArray.empty()) {
     if (! copyOf.constArray.empty()) {
         assert(! copyOf.type.isStruct());
         assert(! copyOf.type.isStruct());
         TConstUnionArray newArray(copyOf.constArray, 0, copyOf.constArray.size());
         TConstUnionArray newArray(copyOf.constArray, 0, copyOf.constArray.size());
         constArray = newArray;
         constArray = newArray;
     }
     }
-
-    // don't support specialization-constant subtrees in cloned tables
-    constSubtree = nullptr;
 }
 }
 
 
 TVariable* TVariable::clone() const
 TVariable* TVariable::clone() const
@@ -317,10 +365,9 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
         parameters.back().copyParam(copyOf.parameters[i]);
         parameters.back().copyParam(copyOf.parameters[i]);
     }
     }
 
 
-    numExtensions = 0;
-    extensions = 0;
-    if (copyOf.extensions != 0)
-        setExtensions(copyOf.numExtensions, copyOf.extensions);
+    extensions = nullptr;
+    if (copyOf.getNumExtensions() > 0)
+        setExtensions(copyOf.getNumExtensions(), copyOf.getExtensions());
     returnType.deepCopy(copyOf.returnType);
     returnType.deepCopy(copyOf.returnType);
     mangledName = copyOf.mangledName;
     mangledName = copyOf.mangledName;
     op = copyOf.op;
     op = copyOf.op;
@@ -359,12 +406,12 @@ TSymbolTableLevel* TSymbolTableLevel::clone() const
         const TAnonMember* anon = iter->second->getAsAnonMember();
         const TAnonMember* anon = iter->second->getAsAnonMember();
         if (anon) {
         if (anon) {
             // Insert all the anonymous members of this same container at once,
             // Insert all the anonymous members of this same container at once,
-            // avoid inserting the other members in the future, once this has been done,
+            // avoid inserting the remaining members in the future, once this has been done,
             // allowing them to all be part of the same new container.
             // allowing them to all be part of the same new container.
             if (! containerCopied[anon->getAnonId()]) {
             if (! containerCopied[anon->getAnonId()]) {
                 TVariable* container = anon->getAnonContainer().clone();
                 TVariable* container = anon->getAnonContainer().clone();
                 container->changeName(NewPoolTString(""));
                 container->changeName(NewPoolTString(""));
-                // insert the whole container
+                // insert the container and all its members
                 symTableLevel->insert(*container, false);
                 symTableLevel->insert(*container, false);
                 containerCopied[anon->getAnonId()] = true;
                 containerCopied[anon->getAnonId()] = true;
             }
             }

+ 79 - 33
src/libraries/glslang/glslang/MachineIndependent/SymbolTable.h

@@ -79,10 +79,12 @@ class TVariable;
 class TFunction;
 class TFunction;
 class TAnonMember;
 class TAnonMember;
 
 
+typedef TVector<const char*> TExtensionList;
+
 class TSymbol {
 class TSymbol {
 public:
 public:
     POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
     POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
-    explicit TSymbol(const TString *n) :  name(n), numExtensions(0), extensions(0), writable(true) { }
+    explicit TSymbol(const TString *n) :  name(n), extensions(0), writable(true) { }
     virtual TSymbol* clone() const = 0;
     virtual TSymbol* clone() const = 0;
     virtual ~TSymbol() { }  // rely on all symbol owned memory coming from the pool
     virtual ~TSymbol() { }  // rely on all symbol owned memory coming from the pool
 
 
@@ -104,18 +106,18 @@ public:
     virtual TType& getWritableType() = 0;
     virtual TType& getWritableType() = 0;
     virtual void setUniqueId(int id) { uniqueId = id; }
     virtual void setUniqueId(int id) { uniqueId = id; }
     virtual int getUniqueId() const { return uniqueId; }
     virtual int getUniqueId() const { return uniqueId; }
-    virtual void setExtensions(int num, const char* const exts[])
+    virtual void setExtensions(int numExts, const char* const exts[])
     {
     {
         assert(extensions == 0);
         assert(extensions == 0);
-        assert(num > 0);
-        numExtensions = num;
-        extensions = NewPoolObject(exts[0], num);
-        for (int e = 0; e < num; ++e)
-            extensions[e] = exts[e];
+        assert(numExts > 0);
+        extensions = NewPoolObject(extensions);
+        for (int e = 0; e < numExts; ++e)
+            extensions->push_back(exts[e]);
     }
     }
-    virtual int getNumExtensions() const { return numExtensions; }
-    virtual const char** getExtensions() const { return extensions; }
-    virtual void dump(TInfoSink &infoSink) const = 0;
+    virtual int getNumExtensions() const { return extensions == nullptr ? 0 : (int)extensions->size(); }
+    virtual const char** getExtensions() const { return extensions->data(); }
+    virtual void dump(TInfoSink& infoSink, bool complete = false) const = 0;
+    void dumpExtensions(TInfoSink& infoSink) const;
 
 
     virtual bool isReadOnly() const { return ! writable; }
     virtual bool isReadOnly() const { return ! writable; }
     virtual void makeReadOnly() { writable = false; }
     virtual void makeReadOnly() { writable = false; }
@@ -129,8 +131,7 @@ protected:
 
 
     // For tracking what extensions must be present
     // For tracking what extensions must be present
     // (don't use if correct version/profile is present).
     // (don't use if correct version/profile is present).
-    int numExtensions;
-    const char** extensions; // an array of pointers to existing constant char strings
+    TExtensionList* extensions; // an array of pointers to existing constant char strings
 
 
     //
     //
     // N.B.: Non-const functions that will be generally used should assert on this,
     // N.B.: Non-const functions that will be generally used should assert on this,
@@ -155,7 +156,9 @@ public:
         : TSymbol(name),
         : TSymbol(name),
           userType(uT),
           userType(uT),
           constSubtree(nullptr),
           constSubtree(nullptr),
-          anonId(-1) { type.shallowCopy(t); }
+          memberExtensions(nullptr),
+          anonId(-1)
+        { type.shallowCopy(t); }
     virtual TVariable* clone() const;
     virtual TVariable* clone() const;
     virtual ~TVariable() { }
     virtual ~TVariable() { }
 
 
@@ -172,7 +175,25 @@ public:
     virtual void setAnonId(int i) { anonId = i; }
     virtual void setAnonId(int i) { anonId = i; }
     virtual int getAnonId() const { return anonId; }
     virtual int getAnonId() const { return anonId; }
 
 
-    virtual void dump(TInfoSink &infoSink) const;
+    virtual void setMemberExtensions(int member, int numExts, const char* const exts[])
+    {
+        assert(type.isStruct());
+        assert(numExts > 0);
+        if (memberExtensions == nullptr) {
+            memberExtensions = NewPoolObject(memberExtensions);
+            memberExtensions->resize(type.getStruct()->size());
+        }
+        for (int e = 0; e < numExts; ++e)
+            (*memberExtensions)[member].push_back(exts[e]);
+    }
+    virtual bool hasMemberExtensions() const { return memberExtensions != nullptr; }
+    virtual int getNumMemberExtensions(int member) const 
+    {
+        return memberExtensions == nullptr ? 0 : (int)(*memberExtensions)[member].size();
+    }
+    virtual const char** getMemberExtensions(int member) const { return (*memberExtensions)[member].data(); }
+
+    virtual void dump(TInfoSink& infoSink, bool complete = false) const;
 
 
 protected:
 protected:
     explicit TVariable(const TVariable&);
     explicit TVariable(const TVariable&);
@@ -180,15 +201,14 @@ protected:
 
 
     TType type;
     TType type;
     bool userType;
     bool userType;
+
     // we are assuming that Pool Allocator will free the memory allocated to unionArray
     // we are assuming that Pool Allocator will free the memory allocated to unionArray
     // when this object is destroyed
     // when this object is destroyed
 
 
-    // TODO: these two should be a union
-    // A variable could be a compile-time constant, or a specialization
-    // constant, or neither, but never both.
-    TConstUnionArray constArray;  // for compile-time constant value
-    TIntermTyped* constSubtree;   // for specialization constant computation
-    int anonId;                   // the ID used for anonymous blocks: TODO: see if uniqueId could serve a dual purpose
+    TConstUnionArray constArray;               // for compile-time constant value
+    TIntermTyped* constSubtree;                // for specialization constant computation
+    TVector<TExtensionList>* memberExtensions; // per-member extension list, allocated only when needed
+    int anonId; // the ID used for anonymous blocks: TODO: see if uniqueId could serve a dual purpose
 };
 };
 
 
 //
 //
@@ -294,7 +314,7 @@ public:
     virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
     virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
     virtual const TParameter& operator[](int i) const { return parameters[i]; }
     virtual const TParameter& operator[](int i) const { return parameters[i]; }
 
 
-    virtual void dump(TInfoSink &infoSink) const override;
+    virtual void dump(TInfoSink& infoSink, bool complete = false) const override;
 
 
 protected:
 protected:
     explicit TFunction(const TFunction&);
     explicit TFunction(const TFunction&);
@@ -325,35 +345,42 @@ protected:
 //
 //
 class TAnonMember : public TSymbol {
 class TAnonMember : public TSymbol {
 public:
 public:
-    TAnonMember(const TString* n, unsigned int m, const TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
-    virtual TAnonMember* clone() const;
+    TAnonMember(const TString* n, unsigned int m, TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
+    virtual TAnonMember* clone() const override;
     virtual ~TAnonMember() { }
     virtual ~TAnonMember() { }
 
 
-    virtual const TAnonMember* getAsAnonMember() const { return this; }
+    virtual const TAnonMember* getAsAnonMember() const override { return this; }
     virtual const TVariable& getAnonContainer() const { return anonContainer; }
     virtual const TVariable& getAnonContainer() const { return anonContainer; }
     virtual unsigned int getMemberNumber() const { return memberNumber; }
     virtual unsigned int getMemberNumber() const { return memberNumber; }
 
 
-    virtual const TType& getType() const
+    virtual const TType& getType() const override
     {
     {
         const TTypeList& types = *anonContainer.getType().getStruct();
         const TTypeList& types = *anonContainer.getType().getStruct();
         return *types[memberNumber].type;
         return *types[memberNumber].type;
     }
     }
 
 
-    virtual TType& getWritableType()
+    virtual TType& getWritableType() override
     {
     {
         assert(writable);
         assert(writable);
         const TTypeList& types = *anonContainer.getType().getStruct();
         const TTypeList& types = *anonContainer.getType().getStruct();
         return *types[memberNumber].type;
         return *types[memberNumber].type;
     }
     }
 
 
+    virtual void setExtensions(int numExts, const char* const exts[]) override
+    {
+        anonContainer.setMemberExtensions(memberNumber, numExts, exts);
+    }
+    virtual int getNumExtensions() const override { return anonContainer.getNumMemberExtensions(memberNumber); }
+    virtual const char** getExtensions() const override { return anonContainer.getMemberExtensions(memberNumber); }
+
     virtual int getAnonId() const { return anonId; }
     virtual int getAnonId() const { return anonId; }
-    virtual void dump(TInfoSink &infoSink) const;
+    virtual void dump(TInfoSink& infoSink, bool complete = false) const override;
 
 
 protected:
 protected:
     explicit TAnonMember(const TAnonMember&);
     explicit TAnonMember(const TAnonMember&);
     TAnonMember& operator=(const TAnonMember&);
     TAnonMember& operator=(const TAnonMember&);
 
 
-    const TVariable& anonContainer;
+    TVariable& anonContainer;
     unsigned int memberNumber;
     unsigned int memberNumber;
     int anonId;
     int anonId;
 };
 };
@@ -515,7 +542,7 @@ public:
 
 
     void relateToOperator(const char* name, TOperator op);
     void relateToOperator(const char* name, TOperator op);
     void setFunctionExtensions(const char* name, int num, const char* const extensions[]);
     void setFunctionExtensions(const char* name, int num, const char* const extensions[]);
-    void dump(TInfoSink &infoSink) const;
+    void dump(TInfoSink& infoSink, bool complete = false) const;
     TSymbolTableLevel* clone() const;
     TSymbolTableLevel* clone() const;
     void readOnly();
     void readOnly();
 
 
@@ -789,15 +816,34 @@ public:
             table[level]->setFunctionExtensions(name, num, extensions);
             table[level]->setFunctionExtensions(name, num, extensions);
     }
     }
 
 
-    void setVariableExtensions(const char* name, int num, const char* const extensions[])
+    void setVariableExtensions(const char* name, int numExts, const char* const extensions[])
     {
     {
         TSymbol* symbol = find(TString(name));
         TSymbol* symbol = find(TString(name));
-        if (symbol)
-            symbol->setExtensions(num, extensions);
+        if (symbol == nullptr)
+            return;
+
+        symbol->setExtensions(numExts, extensions);
+    }
+
+    void setVariableExtensions(const char* blockName, const char* name, int numExts, const char* const extensions[])
+    {
+        TSymbol* symbol = find(TString(blockName));
+        if (symbol == nullptr)
+            return;
+        TVariable* variable = symbol->getAsVariable();
+        assert(variable != nullptr);
+
+        const TTypeList& structure = *variable->getAsVariable()->getType().getStruct();
+        for (int member = 0; member < (int)structure.size(); ++member) {
+            if (structure[member].type->getFieldName().compare(name) == 0) {
+                variable->setMemberExtensions(member, numExts, extensions);
+                return;
+            }
+        }
     }
     }
 
 
     int getMaxSymbolId() { return uniqueId; }
     int getMaxSymbolId() { return uniqueId; }
-    void dump(TInfoSink &infoSink) const;
+    void dump(TInfoSink& infoSink, bool complete = false) const;
     void copyTable(const TSymbolTable& copyOf);
     void copyTable(const TSymbolTable& copyOf);
 
 
     void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
     void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }

+ 21 - 1
src/libraries/glslang/glslang/MachineIndependent/Versions.cpp

@@ -157,6 +157,7 @@ void TParseVersions::initializeExtensionBehavior()
     extensionBehavior[E_GL_EXT_frag_depth]                   = EBhDisable;
     extensionBehavior[E_GL_EXT_frag_depth]                   = EBhDisable;
     extensionBehavior[E_GL_OES_EGL_image_external]           = EBhDisable;
     extensionBehavior[E_GL_OES_EGL_image_external]           = EBhDisable;
     extensionBehavior[E_GL_OES_EGL_image_external_essl3]     = EBhDisable;
     extensionBehavior[E_GL_OES_EGL_image_external_essl3]     = EBhDisable;
+    extensionBehavior[E_GL_EXT_YUV_target]                   = EBhDisable;
     extensionBehavior[E_GL_EXT_shader_texture_lod]           = EBhDisable;
     extensionBehavior[E_GL_EXT_shader_texture_lod]           = EBhDisable;
     extensionBehavior[E_GL_EXT_texture_array]                = EBhDisable;
     extensionBehavior[E_GL_EXT_texture_array]                = EBhDisable;
     extensionBehavior[E_GL_EXT_shadow_samplers]              = EBhDisable;
     extensionBehavior[E_GL_EXT_shadow_samplers]              = EBhDisable;
@@ -208,6 +209,8 @@ void TParseVersions::initializeExtensionBehavior()
     extensionBehavior[E_GL_EXT_samplerless_texture_functions]           = EBhDisable;
     extensionBehavior[E_GL_EXT_samplerless_texture_functions]           = EBhDisable;
     extensionBehavior[E_GL_EXT_scalar_block_layout]                     = EBhDisable;
     extensionBehavior[E_GL_EXT_scalar_block_layout]                     = EBhDisable;
     extensionBehavior[E_GL_EXT_fragment_invocation_density]             = EBhDisable;
     extensionBehavior[E_GL_EXT_fragment_invocation_density]             = EBhDisable;
+    extensionBehavior[E_GL_EXT_buffer_reference]                        = EBhDisable;
+    extensionBehavior[E_GL_EXT_buffer_reference2]                       = EBhDisable;
 
 
     extensionBehavior[E_GL_EXT_shader_16bit_storage]                    = EBhDisable;
     extensionBehavior[E_GL_EXT_shader_16bit_storage]                    = EBhDisable;
     extensionBehavior[E_GL_EXT_shader_8bit_storage]                     = EBhDisable;
     extensionBehavior[E_GL_EXT_shader_8bit_storage]                     = EBhDisable;
@@ -247,6 +250,8 @@ void TParseVersions::initializeExtensionBehavior()
     extensionBehavior[E_GL_NV_mesh_shader]                           = EBhDisable;
     extensionBehavior[E_GL_NV_mesh_shader]                           = EBhDisable;
 #endif
 #endif
 
 
+    extensionBehavior[E_GL_NV_cooperative_matrix]                    = EBhDisable;
+
     // AEP
     // AEP
     extensionBehavior[E_GL_ANDROID_extension_pack_es31a]             = EBhDisable;
     extensionBehavior[E_GL_ANDROID_extension_pack_es31a]             = EBhDisable;
     extensionBehavior[E_GL_KHR_blend_equation_advanced]              = EBhDisable;
     extensionBehavior[E_GL_KHR_blend_equation_advanced]              = EBhDisable;
@@ -308,6 +313,7 @@ void TParseVersions::getPreamble(std::string& preamble)
             "#define GL_EXT_frag_depth 1\n"
             "#define GL_EXT_frag_depth 1\n"
             "#define GL_OES_EGL_image_external 1\n"
             "#define GL_OES_EGL_image_external 1\n"
             "#define GL_OES_EGL_image_external_essl3 1\n"
             "#define GL_OES_EGL_image_external_essl3 1\n"
+            "#define GL_EXT_YUV_target 1\n"
             "#define GL_EXT_shader_texture_lod 1\n"
             "#define GL_EXT_shader_texture_lod 1\n"
             "#define GL_EXT_shadow_samplers 1\n"
             "#define GL_EXT_shadow_samplers 1\n"
 
 
@@ -386,6 +392,8 @@ void TParseVersions::getPreamble(std::string& preamble)
             "#define GL_EXT_samplerless_texture_functions 1\n"
             "#define GL_EXT_samplerless_texture_functions 1\n"
             "#define GL_EXT_scalar_block_layout 1\n"
             "#define GL_EXT_scalar_block_layout 1\n"
             "#define GL_EXT_fragment_invocation_density 1\n"
             "#define GL_EXT_fragment_invocation_density 1\n"
+            "#define GL_EXT_buffer_reference 1\n"
+            "#define GL_EXT_buffer_reference2 1\n"
 
 
             // GL_KHR_shader_subgroup
             // GL_KHR_shader_subgroup
             "#define GL_KHR_shader_subgroup_basic 1\n"
             "#define GL_KHR_shader_subgroup_basic 1\n"
@@ -426,6 +434,8 @@ void TParseVersions::getPreamble(std::string& preamble)
             "#define GL_NV_shader_texture_footprint 1\n"
             "#define GL_NV_shader_texture_footprint 1\n"
             "#define GL_NV_mesh_shader 1\n"
             "#define GL_NV_mesh_shader 1\n"
 #endif
 #endif
+            "#define GL_NV_cooperative_matrix 1\n"
+
             "#define GL_EXT_shader_explicit_arithmetic_types 1\n"
             "#define GL_EXT_shader_explicit_arithmetic_types 1\n"
             "#define GL_EXT_shader_explicit_arithmetic_types_int8 1\n"
             "#define GL_EXT_shader_explicit_arithmetic_types_int8 1\n"
             "#define GL_EXT_shader_explicit_arithmetic_types_int16 1\n"
             "#define GL_EXT_shader_explicit_arithmetic_types_int16 1\n"
@@ -803,6 +813,8 @@ void TParseVersions::updateExtensionBehavior(int line, const char* extension, co
     else if (strcmp(extension, "GL_NV_shader_subgroup_partitioned") == 0)
     else if (strcmp(extension, "GL_NV_shader_subgroup_partitioned") == 0)
         updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
         updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
 #endif
 #endif
+    else if (strcmp(extension, "GL_EXT_buffer_reference2") == 0)
+        updateExtensionBehavior(line, "GL_EXT_buffer_reference", behaviorString);
 }
 }
 
 
 void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
 void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
@@ -1024,7 +1036,7 @@ void TParseVersions::float16OpaqueCheck(const TSourceLoc& loc, const char* op, b
 void TParseVersions::explicitInt16Check(const TSourceLoc& loc, const char* op, bool builtIn)
 void TParseVersions::explicitInt16Check(const TSourceLoc& loc, const char* op, bool builtIn)
 {
 {
     if (! builtIn) {
     if (! builtIn) {
-    	const char* const extensions[] = {
+        const char* const extensions[] = {
 #if AMD_EXTENSIONS
 #if AMD_EXTENSIONS
                                            E_GL_AMD_gpu_shader_int16,
                                            E_GL_AMD_gpu_shader_int16,
 #endif
 #endif
@@ -1082,6 +1094,14 @@ void TParseVersions::int64Check(const TSourceLoc& loc, const char* op, bool buil
     }
     }
 }
 }
 
 
+void TParseVersions::fcoopmatCheck(const TSourceLoc& loc, const char* op, bool builtIn)
+{
+    if (!builtIn) {
+        const char* const extensions[] = {E_GL_NV_cooperative_matrix};
+        requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
+    }
+}
+
 // Call for any operation removed because SPIR-V is in use.
 // Call for any operation removed because SPIR-V is in use.
 void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op)
 void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op)
 {
 {

+ 6 - 1
src/libraries/glslang/glslang/MachineIndependent/Versions.h

@@ -74,7 +74,7 @@ inline const char* ProfileName(EProfile profile)
 }
 }
 
 
 //
 //
-// What source rules, validation rules, target language, etc. are needed
+// What source rules, validation rules, target language, etc. are needed or
 // desired for SPIR-V?
 // desired for SPIR-V?
 //
 //
 // 0 means a target or rule set is not enabled (ignore rules from that entity).
 // 0 means a target or rule set is not enabled (ignore rules from that entity).
@@ -110,6 +110,7 @@ const char* const E_GL_OES_standard_derivatives         = "GL_OES_standard_deriv
 const char* const E_GL_EXT_frag_depth                   = "GL_EXT_frag_depth";
 const char* const E_GL_EXT_frag_depth                   = "GL_EXT_frag_depth";
 const char* const E_GL_OES_EGL_image_external           = "GL_OES_EGL_image_external";
 const char* const E_GL_OES_EGL_image_external           = "GL_OES_EGL_image_external";
 const char* const E_GL_OES_EGL_image_external_essl3     = "GL_OES_EGL_image_external_essl3";
 const char* const E_GL_OES_EGL_image_external_essl3     = "GL_OES_EGL_image_external_essl3";
+const char* const E_GL_EXT_YUV_target                   = "GL_EXT_YUV_target";
 const char* const E_GL_EXT_shader_texture_lod           = "GL_EXT_shader_texture_lod";
 const char* const E_GL_EXT_shader_texture_lod           = "GL_EXT_shader_texture_lod";
 const char* const E_GL_EXT_shadow_samplers              = "GL_EXT_shadow_samplers";
 const char* const E_GL_EXT_shadow_samplers              = "GL_EXT_shadow_samplers";
 
 
@@ -170,6 +171,8 @@ const char* const E_GL_EXT_nonuniform_qualifier             = "GL_EXT_nonuniform
 const char* const E_GL_EXT_samplerless_texture_functions    = "GL_EXT_samplerless_texture_functions";
 const char* const E_GL_EXT_samplerless_texture_functions    = "GL_EXT_samplerless_texture_functions";
 const char* const E_GL_EXT_scalar_block_layout              = "GL_EXT_scalar_block_layout";
 const char* const E_GL_EXT_scalar_block_layout              = "GL_EXT_scalar_block_layout";
 const char* const E_GL_EXT_fragment_invocation_density      = "GL_EXT_fragment_invocation_density";
 const char* const E_GL_EXT_fragment_invocation_density      = "GL_EXT_fragment_invocation_density";
+const char* const E_GL_EXT_buffer_reference                 = "GL_EXT_buffer_reference";
+const char* const E_GL_EXT_buffer_reference2                = "GL_EXT_buffer_reference2";
 
 
 // Arrays of extensions for the above viewportEXTs duplications
 // Arrays of extensions for the above viewportEXTs duplications
 
 
@@ -224,6 +227,8 @@ const char* const viewportEXTs[] = { E_GL_ARB_shader_viewport_layer_array, E_GL_
 const int Num_viewportEXTs = sizeof(viewportEXTs) / sizeof(viewportEXTs[0]);
 const int Num_viewportEXTs = sizeof(viewportEXTs) / sizeof(viewportEXTs[0]);
 #endif
 #endif
 
 
+const char* const E_GL_NV_cooperative_matrix                    = "GL_NV_cooperative_matrix";
+
 // AEP
 // AEP
 const char* const E_GL_ANDROID_extension_pack_es31a             = "GL_ANDROID_extension_pack_es31a";
 const char* const E_GL_ANDROID_extension_pack_es31a             = "GL_ANDROID_extension_pack_es31a";
 const char* const E_GL_KHR_blend_equation_advanced              = "GL_KHR_blend_equation_advanced";
 const char* const E_GL_KHR_blend_equation_advanced              = "GL_KHR_blend_equation_advanced";

+ 99 - 13
src/libraries/glslang/glslang/MachineIndependent/attribute.cpp

@@ -52,6 +52,7 @@ bool TAttributeArgs::getInt(int& value, int argNum) const
     return true;
     return true;
 }
 }
 
 
+
 // extract strings out of attribute arguments stored in attribute aggregate.
 // extract strings out of attribute arguments stored in attribute aggregate.
 // convert to lower case if converToLower is true (for case-insensitive compare convenience)
 // convert to lower case if converToLower is true (for case-insensitive compare convenience)
 bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const 
 bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const 
@@ -85,6 +86,9 @@ const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNu
     if (argNum >= (int)args->getSequence().size())
     if (argNum >= (int)args->getSequence().size())
         return nullptr;
         return nullptr;
 
 
+    if (args->getSequence()[argNum]->getAsConstantUnion() == nullptr)
+        return nullptr;
+
     const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
     const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
     if (constVal == nullptr || constVal->getType() != basicType)
     if (constVal == nullptr || constVal->getType() != basicType)
         return nullptr;
         return nullptr;
@@ -107,6 +111,16 @@ TAttributeType TParseContext::attributeFromName(const TString& name) const
         return EatDependencyInfinite;
         return EatDependencyInfinite;
     else if (name == "dependency_length")
     else if (name == "dependency_length")
         return EatDependencyLength;
         return EatDependencyLength;
+    else if (name == "min_iterations")
+        return EatMinIterations;
+    else if (name == "max_iterations")
+        return EatMaxIterations;
+    else if (name == "iteration_multiple")
+        return EatIterationMultiple;
+    else if (name == "peel_count")
+        return EatPeelCount;
+    else if (name == "partial_count")
+        return EatPartialCount;
     else
     else
         return EatNone;
         return EatNone;
 }
 }
@@ -222,29 +236,101 @@ void TParseContext::handleLoopAttributes(const TAttributes& attributes, TIntermN
     }
     }
 
 
     for (auto it = attributes.begin(); it != attributes.end(); ++it) {
     for (auto it = attributes.begin(); it != attributes.end(); ++it) {
-        if (it->name != EatDependencyLength && it->size() > 0) {
-            warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
-            continue;
-        }
 
 
-        int value;
+        const auto noArgument = [&](const char* feature) {
+            if (it->size() > 0) {
+                warn(node->getLoc(), "expected no arguments", feature, "");
+                return false;
+            }
+            return true;
+        };
+
+        const auto positiveSignedArgument = [&](const char* feature, int& value) {
+            if (it->size() == 1 && it->getInt(value)) {
+                if (value <= 0) {
+                    error(node->getLoc(), "must be positive", feature, "");
+                    return false;
+                }
+            } else {
+                warn(node->getLoc(), "expected a single integer argument", feature, "");
+                return false;
+            }
+            return true;
+        };
+
+        const auto unsignedArgument = [&](const char* feature, unsigned int& uiValue) {
+            int value;
+            if (!(it->size() == 1 && it->getInt(value))) {
+                warn(node->getLoc(), "expected a single integer argument", feature, "");
+                return false;
+            }
+            uiValue = (unsigned int)value;
+            return true;
+        };
+
+        const auto positiveUnsignedArgument = [&](const char* feature, unsigned int& uiValue) {
+            int value;
+            if (it->size() == 1 && it->getInt(value)) {
+                if (value == 0) {
+                    error(node->getLoc(), "must be greater than or equal to 1", feature, "");
+                    return false;
+                }
+            } else {
+                warn(node->getLoc(), "expected a single integer argument", feature, "");
+                return false;
+            }
+            uiValue = (unsigned int)value;
+            return true;
+        };
+
+        const auto spirv14 = [&](const char* feature) {
+            if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_4)
+                warn(node->getLoc(), "attribute requires a SPIR-V 1.4 target-env", feature, "");
+        };
+
+        int value = 0;
+        unsigned uiValue = 0;
         switch (it->name) {
         switch (it->name) {
         case EatUnroll:
         case EatUnroll:
-            loop->setUnroll();
+            if (noArgument("unroll"))
+                loop->setUnroll();
             break;
             break;
         case EatLoop:
         case EatLoop:
-            loop->setDontUnroll();
+            if (noArgument("dont_unroll"))
+                loop->setDontUnroll();
             break;
             break;
         case EatDependencyInfinite:
         case EatDependencyInfinite:
-            loop->setLoopDependency(TIntermLoop::dependencyInfinite);
+            if (noArgument("dependency_infinite"))
+                loop->setLoopDependency(TIntermLoop::dependencyInfinite);
             break;
             break;
         case EatDependencyLength:
         case EatDependencyLength:
-            if (it->size() == 1 && it->getInt(value)) {
-                if (value <= 0)
-                    error(node->getLoc(), "must be positive", "dependency_length", "");
+            if (positiveSignedArgument("dependency_length", value))
                 loop->setLoopDependency(value);
                 loop->setLoopDependency(value);
-            } else
-                warn(node->getLoc(), "expected a single integer argument", "dependency_length", "");
+            break;
+        case EatMinIterations:
+            spirv14("min_iterations");
+            if (unsignedArgument("min_iterations", uiValue))
+                loop->setMinIterations(uiValue);
+            break;
+        case EatMaxIterations:
+            spirv14("max_iterations");
+            if (unsignedArgument("max_iterations", uiValue))
+                loop->setMaxIterations(uiValue);
+            break;
+        case EatIterationMultiple:
+            spirv14("iteration_multiple");
+            if (positiveUnsignedArgument("iteration_multiple", uiValue))
+                loop->setIterationMultiple(uiValue);
+            break;
+        case EatPeelCount:
+            spirv14("peel_count");
+            if (unsignedArgument("peel_count", uiValue))
+                loop->setPeelCount(uiValue);
+            break;
+        case EatPartialCount:
+            spirv14("partial_count");
+            if (unsignedArgument("partial_count", uiValue))
+                loop->setPartialCount(uiValue);
             break;
             break;
         default:
         default:
             warn(node->getLoc(), "attribute does not apply to a loop", "", "");
             warn(node->getLoc(), "attribute does not apply to a loop", "", "");

+ 6 - 1
src/libraries/glslang/glslang/MachineIndependent/attribute.h

@@ -71,7 +71,12 @@ namespace glslang {
         EatPushConstant,
         EatPushConstant,
         EatConstantId,
         EatConstantId,
         EatDependencyInfinite,
         EatDependencyInfinite,
-        EatDependencyLength
+        EatDependencyLength,
+        EatMinIterations,
+        EatMaxIterations,
+        EatIterationMultiple,
+        EatPeelCount,
+        EatPartialCount
     };
     };
 
 
     class TIntermAggregate;
     class TIntermAggregate;

File diff suppressed because it is too large
+ 518 - 511
src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp


+ 233 - 230
src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h

@@ -220,234 +220,236 @@ extern int yydebug;
     F64MAT4X4 = 430,
     F64MAT4X4 = 430,
     ATOMIC_UINT = 431,
     ATOMIC_UINT = 431,
     ACCSTRUCTNV = 432,
     ACCSTRUCTNV = 432,
-    SAMPLER1D = 433,
-    SAMPLER2D = 434,
-    SAMPLER3D = 435,
-    SAMPLERCUBE = 436,
-    SAMPLER1DSHADOW = 437,
-    SAMPLER2DSHADOW = 438,
-    SAMPLERCUBESHADOW = 439,
-    SAMPLER1DARRAY = 440,
-    SAMPLER2DARRAY = 441,
-    SAMPLER1DARRAYSHADOW = 442,
-    SAMPLER2DARRAYSHADOW = 443,
-    ISAMPLER1D = 444,
-    ISAMPLER2D = 445,
-    ISAMPLER3D = 446,
-    ISAMPLERCUBE = 447,
-    ISAMPLER1DARRAY = 448,
-    ISAMPLER2DARRAY = 449,
-    USAMPLER1D = 450,
-    USAMPLER2D = 451,
-    USAMPLER3D = 452,
-    USAMPLERCUBE = 453,
-    USAMPLER1DARRAY = 454,
-    USAMPLER2DARRAY = 455,
-    SAMPLER2DRECT = 456,
-    SAMPLER2DRECTSHADOW = 457,
-    ISAMPLER2DRECT = 458,
-    USAMPLER2DRECT = 459,
-    SAMPLERBUFFER = 460,
-    ISAMPLERBUFFER = 461,
-    USAMPLERBUFFER = 462,
-    SAMPLERCUBEARRAY = 463,
-    SAMPLERCUBEARRAYSHADOW = 464,
-    ISAMPLERCUBEARRAY = 465,
-    USAMPLERCUBEARRAY = 466,
-    SAMPLER2DMS = 467,
-    ISAMPLER2DMS = 468,
-    USAMPLER2DMS = 469,
-    SAMPLER2DMSARRAY = 470,
-    ISAMPLER2DMSARRAY = 471,
-    USAMPLER2DMSARRAY = 472,
-    SAMPLEREXTERNALOES = 473,
-    F16SAMPLER1D = 474,
-    F16SAMPLER2D = 475,
-    F16SAMPLER3D = 476,
-    F16SAMPLER2DRECT = 477,
-    F16SAMPLERCUBE = 478,
-    F16SAMPLER1DARRAY = 479,
-    F16SAMPLER2DARRAY = 480,
-    F16SAMPLERCUBEARRAY = 481,
-    F16SAMPLERBUFFER = 482,
-    F16SAMPLER2DMS = 483,
-    F16SAMPLER2DMSARRAY = 484,
-    F16SAMPLER1DSHADOW = 485,
-    F16SAMPLER2DSHADOW = 486,
-    F16SAMPLER1DARRAYSHADOW = 487,
-    F16SAMPLER2DARRAYSHADOW = 488,
-    F16SAMPLER2DRECTSHADOW = 489,
-    F16SAMPLERCUBESHADOW = 490,
-    F16SAMPLERCUBEARRAYSHADOW = 491,
-    SAMPLER = 492,
-    SAMPLERSHADOW = 493,
-    TEXTURE1D = 494,
-    TEXTURE2D = 495,
-    TEXTURE3D = 496,
-    TEXTURECUBE = 497,
-    TEXTURE1DARRAY = 498,
-    TEXTURE2DARRAY = 499,
-    ITEXTURE1D = 500,
-    ITEXTURE2D = 501,
-    ITEXTURE3D = 502,
-    ITEXTURECUBE = 503,
-    ITEXTURE1DARRAY = 504,
-    ITEXTURE2DARRAY = 505,
-    UTEXTURE1D = 506,
-    UTEXTURE2D = 507,
-    UTEXTURE3D = 508,
-    UTEXTURECUBE = 509,
-    UTEXTURE1DARRAY = 510,
-    UTEXTURE2DARRAY = 511,
-    TEXTURE2DRECT = 512,
-    ITEXTURE2DRECT = 513,
-    UTEXTURE2DRECT = 514,
-    TEXTUREBUFFER = 515,
-    ITEXTUREBUFFER = 516,
-    UTEXTUREBUFFER = 517,
-    TEXTURECUBEARRAY = 518,
-    ITEXTURECUBEARRAY = 519,
-    UTEXTURECUBEARRAY = 520,
-    TEXTURE2DMS = 521,
-    ITEXTURE2DMS = 522,
-    UTEXTURE2DMS = 523,
-    TEXTURE2DMSARRAY = 524,
-    ITEXTURE2DMSARRAY = 525,
-    UTEXTURE2DMSARRAY = 526,
-    F16TEXTURE1D = 527,
-    F16TEXTURE2D = 528,
-    F16TEXTURE3D = 529,
-    F16TEXTURE2DRECT = 530,
-    F16TEXTURECUBE = 531,
-    F16TEXTURE1DARRAY = 532,
-    F16TEXTURE2DARRAY = 533,
-    F16TEXTURECUBEARRAY = 534,
-    F16TEXTUREBUFFER = 535,
-    F16TEXTURE2DMS = 536,
-    F16TEXTURE2DMSARRAY = 537,
-    SUBPASSINPUT = 538,
-    SUBPASSINPUTMS = 539,
-    ISUBPASSINPUT = 540,
-    ISUBPASSINPUTMS = 541,
-    USUBPASSINPUT = 542,
-    USUBPASSINPUTMS = 543,
-    F16SUBPASSINPUT = 544,
-    F16SUBPASSINPUTMS = 545,
-    IMAGE1D = 546,
-    IIMAGE1D = 547,
-    UIMAGE1D = 548,
-    IMAGE2D = 549,
-    IIMAGE2D = 550,
-    UIMAGE2D = 551,
-    IMAGE3D = 552,
-    IIMAGE3D = 553,
-    UIMAGE3D = 554,
-    IMAGE2DRECT = 555,
-    IIMAGE2DRECT = 556,
-    UIMAGE2DRECT = 557,
-    IMAGECUBE = 558,
-    IIMAGECUBE = 559,
-    UIMAGECUBE = 560,
-    IMAGEBUFFER = 561,
-    IIMAGEBUFFER = 562,
-    UIMAGEBUFFER = 563,
-    IMAGE1DARRAY = 564,
-    IIMAGE1DARRAY = 565,
-    UIMAGE1DARRAY = 566,
-    IMAGE2DARRAY = 567,
-    IIMAGE2DARRAY = 568,
-    UIMAGE2DARRAY = 569,
-    IMAGECUBEARRAY = 570,
-    IIMAGECUBEARRAY = 571,
-    UIMAGECUBEARRAY = 572,
-    IMAGE2DMS = 573,
-    IIMAGE2DMS = 574,
-    UIMAGE2DMS = 575,
-    IMAGE2DMSARRAY = 576,
-    IIMAGE2DMSARRAY = 577,
-    UIMAGE2DMSARRAY = 578,
-    F16IMAGE1D = 579,
-    F16IMAGE2D = 580,
-    F16IMAGE3D = 581,
-    F16IMAGE2DRECT = 582,
-    F16IMAGECUBE = 583,
-    F16IMAGE1DARRAY = 584,
-    F16IMAGE2DARRAY = 585,
-    F16IMAGECUBEARRAY = 586,
-    F16IMAGEBUFFER = 587,
-    F16IMAGE2DMS = 588,
-    F16IMAGE2DMSARRAY = 589,
-    STRUCT = 590,
-    VOID = 591,
-    WHILE = 592,
-    IDENTIFIER = 593,
-    TYPE_NAME = 594,
-    FLOATCONSTANT = 595,
-    DOUBLECONSTANT = 596,
-    INT16CONSTANT = 597,
-    UINT16CONSTANT = 598,
-    INT32CONSTANT = 599,
-    UINT32CONSTANT = 600,
-    INTCONSTANT = 601,
-    UINTCONSTANT = 602,
-    INT64CONSTANT = 603,
-    UINT64CONSTANT = 604,
-    BOOLCONSTANT = 605,
-    FLOAT16CONSTANT = 606,
-    LEFT_OP = 607,
-    RIGHT_OP = 608,
-    INC_OP = 609,
-    DEC_OP = 610,
-    LE_OP = 611,
-    GE_OP = 612,
-    EQ_OP = 613,
-    NE_OP = 614,
-    AND_OP = 615,
-    OR_OP = 616,
-    XOR_OP = 617,
-    MUL_ASSIGN = 618,
-    DIV_ASSIGN = 619,
-    ADD_ASSIGN = 620,
-    MOD_ASSIGN = 621,
-    LEFT_ASSIGN = 622,
-    RIGHT_ASSIGN = 623,
-    AND_ASSIGN = 624,
-    XOR_ASSIGN = 625,
-    OR_ASSIGN = 626,
-    SUB_ASSIGN = 627,
-    LEFT_PAREN = 628,
-    RIGHT_PAREN = 629,
-    LEFT_BRACKET = 630,
-    RIGHT_BRACKET = 631,
-    LEFT_BRACE = 632,
-    RIGHT_BRACE = 633,
-    DOT = 634,
-    COMMA = 635,
-    COLON = 636,
-    EQUAL = 637,
-    SEMICOLON = 638,
-    BANG = 639,
-    DASH = 640,
-    TILDE = 641,
-    PLUS = 642,
-    STAR = 643,
-    SLASH = 644,
-    PERCENT = 645,
-    LEFT_ANGLE = 646,
-    RIGHT_ANGLE = 647,
-    VERTICAL_BAR = 648,
-    CARET = 649,
-    AMPERSAND = 650,
-    QUESTION = 651,
-    INVARIANT = 652,
-    PRECISE = 653,
-    HIGH_PRECISION = 654,
-    MEDIUM_PRECISION = 655,
-    LOW_PRECISION = 656,
-    PRECISION = 657,
-    PACKED = 658,
-    RESOURCE = 659,
-    SUPERP = 660
+    FCOOPMATNV = 433,
+    SAMPLER1D = 434,
+    SAMPLER2D = 435,
+    SAMPLER3D = 436,
+    SAMPLERCUBE = 437,
+    SAMPLER1DSHADOW = 438,
+    SAMPLER2DSHADOW = 439,
+    SAMPLERCUBESHADOW = 440,
+    SAMPLER1DARRAY = 441,
+    SAMPLER2DARRAY = 442,
+    SAMPLER1DARRAYSHADOW = 443,
+    SAMPLER2DARRAYSHADOW = 444,
+    ISAMPLER1D = 445,
+    ISAMPLER2D = 446,
+    ISAMPLER3D = 447,
+    ISAMPLERCUBE = 448,
+    ISAMPLER1DARRAY = 449,
+    ISAMPLER2DARRAY = 450,
+    USAMPLER1D = 451,
+    USAMPLER2D = 452,
+    USAMPLER3D = 453,
+    USAMPLERCUBE = 454,
+    USAMPLER1DARRAY = 455,
+    USAMPLER2DARRAY = 456,
+    SAMPLER2DRECT = 457,
+    SAMPLER2DRECTSHADOW = 458,
+    ISAMPLER2DRECT = 459,
+    USAMPLER2DRECT = 460,
+    SAMPLERBUFFER = 461,
+    ISAMPLERBUFFER = 462,
+    USAMPLERBUFFER = 463,
+    SAMPLERCUBEARRAY = 464,
+    SAMPLERCUBEARRAYSHADOW = 465,
+    ISAMPLERCUBEARRAY = 466,
+    USAMPLERCUBEARRAY = 467,
+    SAMPLER2DMS = 468,
+    ISAMPLER2DMS = 469,
+    USAMPLER2DMS = 470,
+    SAMPLER2DMSARRAY = 471,
+    ISAMPLER2DMSARRAY = 472,
+    USAMPLER2DMSARRAY = 473,
+    SAMPLEREXTERNALOES = 474,
+    SAMPLEREXTERNAL2DY2YEXT = 475,
+    F16SAMPLER1D = 476,
+    F16SAMPLER2D = 477,
+    F16SAMPLER3D = 478,
+    F16SAMPLER2DRECT = 479,
+    F16SAMPLERCUBE = 480,
+    F16SAMPLER1DARRAY = 481,
+    F16SAMPLER2DARRAY = 482,
+    F16SAMPLERCUBEARRAY = 483,
+    F16SAMPLERBUFFER = 484,
+    F16SAMPLER2DMS = 485,
+    F16SAMPLER2DMSARRAY = 486,
+    F16SAMPLER1DSHADOW = 487,
+    F16SAMPLER2DSHADOW = 488,
+    F16SAMPLER1DARRAYSHADOW = 489,
+    F16SAMPLER2DARRAYSHADOW = 490,
+    F16SAMPLER2DRECTSHADOW = 491,
+    F16SAMPLERCUBESHADOW = 492,
+    F16SAMPLERCUBEARRAYSHADOW = 493,
+    SAMPLER = 494,
+    SAMPLERSHADOW = 495,
+    TEXTURE1D = 496,
+    TEXTURE2D = 497,
+    TEXTURE3D = 498,
+    TEXTURECUBE = 499,
+    TEXTURE1DARRAY = 500,
+    TEXTURE2DARRAY = 501,
+    ITEXTURE1D = 502,
+    ITEXTURE2D = 503,
+    ITEXTURE3D = 504,
+    ITEXTURECUBE = 505,
+    ITEXTURE1DARRAY = 506,
+    ITEXTURE2DARRAY = 507,
+    UTEXTURE1D = 508,
+    UTEXTURE2D = 509,
+    UTEXTURE3D = 510,
+    UTEXTURECUBE = 511,
+    UTEXTURE1DARRAY = 512,
+    UTEXTURE2DARRAY = 513,
+    TEXTURE2DRECT = 514,
+    ITEXTURE2DRECT = 515,
+    UTEXTURE2DRECT = 516,
+    TEXTUREBUFFER = 517,
+    ITEXTUREBUFFER = 518,
+    UTEXTUREBUFFER = 519,
+    TEXTURECUBEARRAY = 520,
+    ITEXTURECUBEARRAY = 521,
+    UTEXTURECUBEARRAY = 522,
+    TEXTURE2DMS = 523,
+    ITEXTURE2DMS = 524,
+    UTEXTURE2DMS = 525,
+    TEXTURE2DMSARRAY = 526,
+    ITEXTURE2DMSARRAY = 527,
+    UTEXTURE2DMSARRAY = 528,
+    F16TEXTURE1D = 529,
+    F16TEXTURE2D = 530,
+    F16TEXTURE3D = 531,
+    F16TEXTURE2DRECT = 532,
+    F16TEXTURECUBE = 533,
+    F16TEXTURE1DARRAY = 534,
+    F16TEXTURE2DARRAY = 535,
+    F16TEXTURECUBEARRAY = 536,
+    F16TEXTUREBUFFER = 537,
+    F16TEXTURE2DMS = 538,
+    F16TEXTURE2DMSARRAY = 539,
+    SUBPASSINPUT = 540,
+    SUBPASSINPUTMS = 541,
+    ISUBPASSINPUT = 542,
+    ISUBPASSINPUTMS = 543,
+    USUBPASSINPUT = 544,
+    USUBPASSINPUTMS = 545,
+    F16SUBPASSINPUT = 546,
+    F16SUBPASSINPUTMS = 547,
+    IMAGE1D = 548,
+    IIMAGE1D = 549,
+    UIMAGE1D = 550,
+    IMAGE2D = 551,
+    IIMAGE2D = 552,
+    UIMAGE2D = 553,
+    IMAGE3D = 554,
+    IIMAGE3D = 555,
+    UIMAGE3D = 556,
+    IMAGE2DRECT = 557,
+    IIMAGE2DRECT = 558,
+    UIMAGE2DRECT = 559,
+    IMAGECUBE = 560,
+    IIMAGECUBE = 561,
+    UIMAGECUBE = 562,
+    IMAGEBUFFER = 563,
+    IIMAGEBUFFER = 564,
+    UIMAGEBUFFER = 565,
+    IMAGE1DARRAY = 566,
+    IIMAGE1DARRAY = 567,
+    UIMAGE1DARRAY = 568,
+    IMAGE2DARRAY = 569,
+    IIMAGE2DARRAY = 570,
+    UIMAGE2DARRAY = 571,
+    IMAGECUBEARRAY = 572,
+    IIMAGECUBEARRAY = 573,
+    UIMAGECUBEARRAY = 574,
+    IMAGE2DMS = 575,
+    IIMAGE2DMS = 576,
+    UIMAGE2DMS = 577,
+    IMAGE2DMSARRAY = 578,
+    IIMAGE2DMSARRAY = 579,
+    UIMAGE2DMSARRAY = 580,
+    F16IMAGE1D = 581,
+    F16IMAGE2D = 582,
+    F16IMAGE3D = 583,
+    F16IMAGE2DRECT = 584,
+    F16IMAGECUBE = 585,
+    F16IMAGE1DARRAY = 586,
+    F16IMAGE2DARRAY = 587,
+    F16IMAGECUBEARRAY = 588,
+    F16IMAGEBUFFER = 589,
+    F16IMAGE2DMS = 590,
+    F16IMAGE2DMSARRAY = 591,
+    STRUCT = 592,
+    VOID = 593,
+    WHILE = 594,
+    IDENTIFIER = 595,
+    TYPE_NAME = 596,
+    FLOATCONSTANT = 597,
+    DOUBLECONSTANT = 598,
+    INT16CONSTANT = 599,
+    UINT16CONSTANT = 600,
+    INT32CONSTANT = 601,
+    UINT32CONSTANT = 602,
+    INTCONSTANT = 603,
+    UINTCONSTANT = 604,
+    INT64CONSTANT = 605,
+    UINT64CONSTANT = 606,
+    BOOLCONSTANT = 607,
+    FLOAT16CONSTANT = 608,
+    LEFT_OP = 609,
+    RIGHT_OP = 610,
+    INC_OP = 611,
+    DEC_OP = 612,
+    LE_OP = 613,
+    GE_OP = 614,
+    EQ_OP = 615,
+    NE_OP = 616,
+    AND_OP = 617,
+    OR_OP = 618,
+    XOR_OP = 619,
+    MUL_ASSIGN = 620,
+    DIV_ASSIGN = 621,
+    ADD_ASSIGN = 622,
+    MOD_ASSIGN = 623,
+    LEFT_ASSIGN = 624,
+    RIGHT_ASSIGN = 625,
+    AND_ASSIGN = 626,
+    XOR_ASSIGN = 627,
+    OR_ASSIGN = 628,
+    SUB_ASSIGN = 629,
+    LEFT_PAREN = 630,
+    RIGHT_PAREN = 631,
+    LEFT_BRACKET = 632,
+    RIGHT_BRACKET = 633,
+    LEFT_BRACE = 634,
+    RIGHT_BRACE = 635,
+    DOT = 636,
+    COMMA = 637,
+    COLON = 638,
+    EQUAL = 639,
+    SEMICOLON = 640,
+    BANG = 641,
+    DASH = 642,
+    TILDE = 643,
+    PLUS = 644,
+    STAR = 645,
+    SLASH = 646,
+    PERCENT = 647,
+    LEFT_ANGLE = 648,
+    RIGHT_ANGLE = 649,
+    VERTICAL_BAR = 650,
+    CARET = 651,
+    AMPERSAND = 652,
+    QUESTION = 653,
+    INVARIANT = 654,
+    PRECISE = 655,
+    HIGH_PRECISION = 656,
+    MEDIUM_PRECISION = 657,
+    LOW_PRECISION = 658,
+    PRECISION = 659,
+    PACKED = 660,
+    RESOURCE = 661,
+    SUPERP = 662
   };
   };
 #endif
 #endif
 
 
@@ -456,7 +458,7 @@ extern int yydebug;
 
 
 union YYSTYPE
 union YYSTYPE
 {
 {
-#line 70 "MachineIndependent/glslang.y" /* yacc.c:1909  */
+#line 71 "MachineIndependent/glslang.y" /* yacc.c:1909  */
 
 
     struct {
     struct {
         glslang::TSourceLoc loc;
         glslang::TSourceLoc loc;
@@ -489,9 +491,10 @@ union YYSTYPE
             glslang::TArraySizes* arraySizes;
             glslang::TArraySizes* arraySizes;
             glslang::TIdentifierList* identifierList;
             glslang::TIdentifierList* identifierList;
         };
         };
+        glslang::TArraySizes* typeParameters;
     } interm;
     } interm;
 
 
-#line 495 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909  */
+#line 498 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909  */
 };
 };
 
 
 typedef union YYSTYPE YYSTYPE;
 typedef union YYSTYPE YYSTYPE;

+ 22 - 3
src/libraries/glslang/glslang/MachineIndependent/intermOut.cpp

@@ -43,6 +43,7 @@
 #else
 #else
 #include <cmath>
 #include <cmath>
 #endif
 #endif
+#include <cstdint>
 
 
 namespace {
 namespace {
 
 
@@ -172,8 +173,12 @@ bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
     case EOpIndexDirect:   out.debug << "direct index";   break;
     case EOpIndexDirect:   out.debug << "direct index";   break;
     case EOpIndexIndirect: out.debug << "indirect index"; break;
     case EOpIndexIndirect: out.debug << "indirect index"; break;
     case EOpIndexDirectStruct:
     case EOpIndexDirectStruct:
-        out.debug << (*node->getLeft()->getType().getStruct())[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName();
-        out.debug << ": direct index for structure";      break;
+        {
+            bool reference = node->getLeft()->getType().getBasicType() == EbtReference;
+            const TTypeList *members = reference ? node->getLeft()->getType().getReferentType()->getStruct() : node->getLeft()->getType().getStruct();
+            out.debug << (*members)[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName();
+            out.debug << ": direct index for structure";      break;
+        }
     case EOpVectorSwizzle: out.debug << "vector swizzle"; break;
     case EOpVectorSwizzle: out.debug << "vector swizzle"; break;
     case EOpMatrixSwizzle: out.debug << "matrix swizzle"; break;
     case EOpMatrixSwizzle: out.debug << "matrix swizzle"; break;
 
 
@@ -232,6 +237,7 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
     case EOpPostDecrement:  out.debug << "Post-Decrement";       break;
     case EOpPostDecrement:  out.debug << "Post-Decrement";       break;
     case EOpPreIncrement:   out.debug << "Pre-Increment";        break;
     case EOpPreIncrement:   out.debug << "Pre-Increment";        break;
     case EOpPreDecrement:   out.debug << "Pre-Decrement";        break;
     case EOpPreDecrement:   out.debug << "Pre-Decrement";        break;
+    case EOpCopyObject:     out.debug << "copy object";          break;
 
 
     // * -> bool
     // * -> bool
     case EOpConvInt8ToBool:    out.debug << "Convert int8_t to bool";  break;
     case EOpConvInt8ToBool:    out.debug << "Convert int8_t to bool";  break;
@@ -419,6 +425,8 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
     case EOpConvDoubleToUint:   out.debug << "Convert double to uint"; break;
     case EOpConvDoubleToUint:   out.debug << "Convert double to uint"; break;
     case EOpConvDoubleToUint64: out.debug << "Convert double to uint64"; break;
     case EOpConvDoubleToUint64: out.debug << "Convert double to uint64"; break;
 
 
+    case EOpConvUint64ToPtr:  out.debug << "Convert uint64_t to pointer";   break;
+    case EOpConvPtrToUint64:  out.debug << "Convert pointer to uint64_t";   break;
 
 
     case EOpRadians:        out.debug << "radians";              break;
     case EOpRadians:        out.debug << "radians";              break;
     case EOpDegrees:        out.debug << "degrees";              break;
     case EOpDegrees:        out.debug << "degrees";              break;
@@ -674,6 +682,8 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
     case EOpSubpassLoad:   out.debug << "subpassLoad";   break;
     case EOpSubpassLoad:   out.debug << "subpassLoad";   break;
     case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break;
     case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break;
 
 
+    case EOpConstructReference: out.debug << "Construct reference type"; break;
+
     default: out.debug.message(EPrefixError, "Bad unary op");
     default: out.debug.message(EPrefixError, "Bad unary op");
     }
     }
 
 
@@ -808,6 +818,8 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
     case EOpConstructF16Mat4x4: out.debug << "Construct f16mat4";   break;
     case EOpConstructF16Mat4x4: out.debug << "Construct f16mat4";   break;
     case EOpConstructStruct:  out.debug << "Construct structure";  break;
     case EOpConstructStruct:  out.debug << "Construct structure";  break;
     case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break;
     case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break;
+    case EOpConstructReference:  out.debug << "Construct reference";  break;
+    case EOpConstructCooperativeMatrix:  out.debug << "Construct cooperative matrix";  break;
 
 
     case EOpLessThan:         out.debug << "Compare Less Than";             break;
     case EOpLessThan:         out.debug << "Compare Less Than";             break;
     case EOpGreaterThan:      out.debug << "Compare Greater Than";          break;
     case EOpGreaterThan:      out.debug << "Compare Greater Than";          break;
@@ -1057,6 +1069,10 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node
     case EOpWritePackedPrimitiveIndices4x8NV: out.debug << "writePackedPrimitiveIndices4x8NV"; break;
     case EOpWritePackedPrimitiveIndices4x8NV: out.debug << "writePackedPrimitiveIndices4x8NV"; break;
 #endif
 #endif
 
 
+    case EOpCooperativeMatrixLoad:  out.debug << "Load cooperative matrix";  break;
+    case EOpCooperativeMatrixStore:  out.debug << "Store cooperative matrix";  break;
+    case EOpCooperativeMatrixMulAdd: out.debug << "MulAdd cooperative matrices"; break;
+
     default: out.debug.message(EPrefixError, "Bad aggregation op");
     default: out.debug.message(EPrefixError, "Bad aggregation op");
     }
     }
 
 
@@ -1148,8 +1164,11 @@ static void OutputDouble(TInfoSink& out, double value, TOutputTraverser::EExtraO
         switch (extra) {
         switch (extra) {
         case TOutputTraverser::BinaryDoubleOutput:
         case TOutputTraverser::BinaryDoubleOutput:
         {
         {
+            uint64_t b;
+            static_assert(sizeof(b) == sizeof(value), "sizeof(uint64_t) != sizeof(double)");
+            memcpy(&b, &value, sizeof(b));
+
             out.debug << " : ";
             out.debug << " : ";
-            long long b = *reinterpret_cast<long long*>(&value);
             for (size_t i = 0; i < 8 * sizeof(value); ++i, ++b) {
             for (size_t i = 0; i < 8 * sizeof(value); ++i, ++b) {
                 out.debug << ((b & 0x8000000000000000) != 0 ? "1" : "0");
                 out.debug << ((b & 0x8000000000000000) != 0 ? "1" : "0");
                 b <<= 1;
                 b <<= 1;

+ 172 - 22
src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp

@@ -222,8 +222,14 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
         else if (xfbBuffers[b].stride != unit.xfbBuffers[b].stride)
         else if (xfbBuffers[b].stride != unit.xfbBuffers[b].stride)
             error(infoSink, "Contradictory xfb_stride");
             error(infoSink, "Contradictory xfb_stride");
         xfbBuffers[b].implicitStride = std::max(xfbBuffers[b].implicitStride, unit.xfbBuffers[b].implicitStride);
         xfbBuffers[b].implicitStride = std::max(xfbBuffers[b].implicitStride, unit.xfbBuffers[b].implicitStride);
-        if (unit.xfbBuffers[b].containsDouble)
-            xfbBuffers[b].containsDouble = true;
+        if (unit.xfbBuffers[b].contains64BitType)
+            xfbBuffers[b].contains64BitType = true;
+#ifdef AMD_EXTENSIONS
+        if (unit.xfbBuffers[b].contains32BitType)
+            xfbBuffers[b].contains32BitType = true;
+        if (unit.xfbBuffers[b].contains16BitType)
+            xfbBuffers[b].contains16BitType = true;
+#endif
         // TODO: 4.4 link: enhanced layouts: compare ranges
         // TODO: 4.4 link: enhanced layouts: compare ranges
     }
     }
 
 
@@ -261,6 +267,7 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit)
 
 
     MERGE_TRUE(needToLegalize);
     MERGE_TRUE(needToLegalize);
     MERGE_TRUE(binaryDoubleOutput);
     MERGE_TRUE(binaryDoubleOutput);
+    MERGE_TRUE(usePhysicalStorageBuffer);
 }
 }
 
 
 //
 //
@@ -633,8 +640,14 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
         error(infoSink, "Cannot use both gl_FragColor and gl_FragData");
         error(infoSink, "Cannot use both gl_FragColor and gl_FragData");
 
 
     for (size_t b = 0; b < xfbBuffers.size(); ++b) {
     for (size_t b = 0; b < xfbBuffers.size(); ++b) {
-        if (xfbBuffers[b].containsDouble)
+        if (xfbBuffers[b].contains64BitType)
             RoundToPow2(xfbBuffers[b].implicitStride, 8);
             RoundToPow2(xfbBuffers[b].implicitStride, 8);
+#ifdef AMD_EXTENSIONS
+        else if (xfbBuffers[b].contains32BitType)
+            RoundToPow2(xfbBuffers[b].implicitStride, 4);
+        else if (xfbBuffers[b].contains16BitType)
+            RoundToPow2(xfbBuffers[b].implicitStride, 2);
+#endif
 
 
         // "It is a compile-time or link-time error to have
         // "It is a compile-time or link-time error to have
         // any xfb_offset that overflows xfb_stride, whether stated on declarations before or after the xfb_stride, or
         // any xfb_offset that overflows xfb_stride, whether stated on declarations before or after the xfb_stride, or
@@ -649,18 +662,31 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
             xfbBuffers[b].stride = xfbBuffers[b].implicitStride;
             xfbBuffers[b].stride = xfbBuffers[b].implicitStride;
 
 
         // "If the buffer is capturing any
         // "If the buffer is capturing any
-        // outputs with double-precision components, the stride must be a multiple of 8, otherwise it must be a
+        // outputs with double-precision or 64-bit integer components, the stride must be a multiple of 8, otherwise it must be a
         // multiple of 4, or a compile-time or link-time error results."
         // multiple of 4, or a compile-time or link-time error results."
-        if (xfbBuffers[b].containsDouble && ! IsMultipleOfPow2(xfbBuffers[b].stride, 8)) {
-            error(infoSink, "xfb_stride must be multiple of 8 for buffer holding a double:");
+        if (xfbBuffers[b].contains64BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 8)) {
+            error(infoSink, "xfb_stride must be multiple of 8 for buffer holding a double or 64-bit integer:");
             infoSink.info.prefix(EPrefixError);
             infoSink.info.prefix(EPrefixError);
             infoSink.info << "    xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
             infoSink.info << "    xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
+#ifdef AMD_EXTENSIONS
+        } else if (xfbBuffers[b].contains32BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 4)) {
+#else
         } else if (! IsMultipleOfPow2(xfbBuffers[b].stride, 4)) {
         } else if (! IsMultipleOfPow2(xfbBuffers[b].stride, 4)) {
+#endif
             error(infoSink, "xfb_stride must be multiple of 4:");
             error(infoSink, "xfb_stride must be multiple of 4:");
             infoSink.info.prefix(EPrefixError);
             infoSink.info.prefix(EPrefixError);
             infoSink.info << "    xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
             infoSink.info << "    xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
         }
         }
+#ifdef AMD_EXTENSIONS
+        // "If the buffer is capturing any
+        // outputs with half-precision or 16-bit integer components, the stride must be a multiple of 2"
+        else if (xfbBuffers[b].contains16BitType && ! IsMultipleOfPow2(xfbBuffers[b].stride, 2)) {
+            error(infoSink, "xfb_stride must be multiple of 2 for buffer holding a half float or 16-bit integer:");
+            infoSink.info.prefix(EPrefixError);
+            infoSink.info << "    xfb_buffer " << (unsigned int)b << ", xfb_stride " << xfbBuffers[b].stride << "\n";
+        }
 
 
+#endif
         // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the
         // "The resulting stride (implicit or explicit), when divided by 4, must be less than or equal to the
         // implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents."
         // implementation-dependent constant gl_MaxTransformFeedbackInterleavedComponents."
         if (xfbBuffers[b].stride > (unsigned int)(4 * resources.maxTransformFeedbackInterleavedComponents)) {
         if (xfbBuffers[b].stride > (unsigned int)(4 * resources.maxTransformFeedbackInterleavedComponents)) {
@@ -1259,7 +1285,11 @@ int TIntermediate::addXfbBufferOffset(const TType& type)
     TXfbBuffer& buffer = xfbBuffers[qualifier.layoutXfbBuffer];
     TXfbBuffer& buffer = xfbBuffers[qualifier.layoutXfbBuffer];
 
 
     // compute the range
     // compute the range
-    unsigned int size = computeTypeXfbSize(type, buffer.containsDouble);
+#ifdef AMD_EXTENSIONS
+    unsigned int size = computeTypeXfbSize(type, buffer.contains64BitType, buffer.contains32BitType, buffer.contains16BitType);
+#else
+    unsigned int size = computeTypeXfbSize(type, buffer.contains64BitType);
+#endif
     buffer.implicitStride = std::max(buffer.implicitStride, qualifier.layoutXfbOffset + size);
     buffer.implicitStride = std::max(buffer.implicitStride, qualifier.layoutXfbOffset + size);
     TRange range(qualifier.layoutXfbOffset, qualifier.layoutXfbOffset + size - 1);
     TRange range(qualifier.layoutXfbOffset, qualifier.layoutXfbOffset + size - 1);
 
 
@@ -1278,11 +1308,18 @@ int TIntermediate::addXfbBufferOffset(const TType& type)
 
 
 // Recursively figure out how many bytes of xfb buffer are used by the given type.
 // Recursively figure out how many bytes of xfb buffer are used by the given type.
 // Return the size of type, in bytes.
 // Return the size of type, in bytes.
-// Sets containsDouble to true if the type contains a double.
-// N.B. Caller must set containsDouble to false before calling.
-unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& containsDouble) const
+// Sets contains64BitType to true if the type contains a 64-bit data type.
+#ifdef AMD_EXTENSIONS
+// Sets contains32BitType to true if the type contains a 32-bit data type.
+// Sets contains16BitType to true if the type contains a 16-bit data type.
+// N.B. Caller must set contains64BitType, contains32BitType, and contains16BitType to false before calling.
+unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const
+#else
+// N.B. Caller must set contains64BitType to false before calling.
+unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains64BitType) const
+#endif
 {
 {
-    // "...if applied to an aggregate containing a double, the offset must also be a multiple of 8,
+    // "...if applied to an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8,
     // and the space taken in the buffer will be a multiple of 8.
     // and the space taken in the buffer will be a multiple of 8.
     // ...within the qualified entity, subsequent components are each
     // ...within the qualified entity, subsequent components are each
     // assigned, in order, to the next available offset aligned to a multiple of
     // assigned, in order, to the next available offset aligned to a multiple of
@@ -1293,29 +1330,59 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains
         // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
         // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness
         assert(type.isSizedArray());
         assert(type.isSizedArray());
         TType elementType(type, 0);
         TType elementType(type, 0);
-        return type.getOuterArraySize() * computeTypeXfbSize(elementType, containsDouble);
+#ifdef AMD_EXTENSIONS
+        return type.getOuterArraySize() * computeTypeXfbSize(elementType, contains64BitType, contains16BitType, contains16BitType);
+#else
+        return type.getOuterArraySize() * computeTypeXfbSize(elementType, contains64BitType);
+#endif
     }
     }
 
 
     if (type.isStruct()) {
     if (type.isStruct()) {
         unsigned int size = 0;
         unsigned int size = 0;
-        bool structContainsDouble = false;
+        bool structContains64BitType = false;
+#ifdef AMD_EXTENSIONS
+        bool structContains32BitType = false;
+        bool structContains16BitType = false;
+#endif
         for (int member = 0; member < (int)type.getStruct()->size(); ++member) {
         for (int member = 0; member < (int)type.getStruct()->size(); ++member) {
             TType memberType(type, member);
             TType memberType(type, member);
             // "... if applied to
             // "... if applied to
-            // an aggregate containing a double, the offset must also be a multiple of 8,
+            // an aggregate containing a double or 64-bit integer, the offset must also be a multiple of 8,
             // and the space taken in the buffer will be a multiple of 8."
             // and the space taken in the buffer will be a multiple of 8."
-            bool memberContainsDouble = false;
-            int memberSize = computeTypeXfbSize(memberType, memberContainsDouble);
-            if (memberContainsDouble) {
-                structContainsDouble = true;
+            bool memberContains64BitType = false;
+#ifdef AMD_EXTENSIONS
+            bool memberContains32BitType = false;
+            bool memberContains16BitType = false;
+            int memberSize = computeTypeXfbSize(memberType, memberContains64BitType, memberContains32BitType, memberContains16BitType);
+#else
+            int memberSize = computeTypeXfbSize(memberType, memberContains64BitType);
+#endif
+            if (memberContains64BitType) {
+                structContains64BitType = true;
                 RoundToPow2(size, 8);
                 RoundToPow2(size, 8);
+#ifdef AMD_EXTENSIONS
+            } else if (memberContains32BitType) {
+                structContains32BitType = true;
+                RoundToPow2(size, 4);
+            } else if (memberContains16BitType) {
+                structContains16BitType = true;
+                RoundToPow2(size, 2);
+#endif
             }
             }
             size += memberSize;
             size += memberSize;
         }
         }
 
 
-        if (structContainsDouble) {
-            containsDouble = true;
+        if (structContains64BitType) {
+            contains64BitType = true;
             RoundToPow2(size, 8);
             RoundToPow2(size, 8);
+#ifdef AMD_EXTENSIONS
+        } else if (structContains32BitType) {
+            contains32BitType = true;
+            RoundToPow2(size, 4);
+        } else if (structContains16BitType) {
+            contains16BitType = true;
+            RoundToPow2(size, 2);
+#endif
         }
         }
         return size;
         return size;
     }
     }
@@ -1332,11 +1399,23 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains
         numComponents = 1;
         numComponents = 1;
     }
     }
 
 
-    if (type.getBasicType() == EbtDouble) {
-        containsDouble = true;
+    if (type.getBasicType() == EbtDouble || type.getBasicType() == EbtInt64 || type.getBasicType() == EbtUint64) {
+        contains64BitType = true;
         return 8 * numComponents;
         return 8 * numComponents;
+#ifdef AMD_EXTENSIONS
+    } else if (type.getBasicType() == EbtFloat16 || type.getBasicType() == EbtInt16 || type.getBasicType() == EbtUint16) {
+        contains16BitType = true;
+        return 2 * numComponents;
+    } else if (type.getBasicType() == EbtInt8 || type.getBasicType() == EbtUint8)
+        return numComponents;
+    else {
+        contains32BitType = true;
+        return 4 * numComponents;
+    }
+#else
     } else
     } else
         return 4 * numComponents;
         return 4 * numComponents;
+#endif
 }
 }
 
 
 const int baseAlignmentVec4Std140 = 16;
 const int baseAlignmentVec4Std140 = 16;
@@ -1355,6 +1434,7 @@ int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size)
     case EbtUint8:   size = 1; return 1;
     case EbtUint8:   size = 1; return 1;
     case EbtInt16:
     case EbtInt16:
     case EbtUint16:  size = 2; return 2;
     case EbtUint16:  size = 2; return 2;
+    case EbtReference: size = 8; return 8;
     default:         size = 4; return 4;
     default:         size = 4; return 4;
     }
     }
 }
 }
@@ -1603,4 +1683,74 @@ int TIntermediate::getMemberAlignment(const TType& type, int& size, int& stride,
     }
     }
 }
 }
 
 
+// shared calculation by getOffset and getOffsets
+void TIntermediate::updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize)
+{
+    int dummyStride;
+
+    // modify just the children's view of matrix layout, if there is one for this member
+    TLayoutMatrix subMatrixLayout = memberType.getQualifier().layoutMatrix;
+    int memberAlignment = getMemberAlignment(memberType, memberSize, dummyStride,
+                                             parentType.getQualifier().layoutPacking,
+                                             subMatrixLayout != ElmNone
+                                                 ? subMatrixLayout == ElmRowMajor
+                                                 : parentType.getQualifier().layoutMatrix == ElmRowMajor);
+    RoundToPow2(offset, memberAlignment);
+}
+
+// Lookup or calculate the offset of a block member, using the recursively
+// defined block offset rules.
+int TIntermediate::getOffset(const TType& type, int index)
+{
+    const TTypeList& memberList = *type.getStruct();
+
+    // Don't calculate offset if one is present, it could be user supplied
+    // and different than what would be calculated.  That is, this is faster,
+    // but not just an optimization.
+    if (memberList[index].type->getQualifier().hasOffset())
+        return memberList[index].type->getQualifier().layoutOffset;
+
+    int memberSize = 0;
+    int offset = 0;
+    for (int m = 0; m <= index; ++m) {
+        updateOffset(type, *memberList[m].type, offset, memberSize);
+
+        if (m < index)
+            offset += memberSize;
+    }
+
+    return offset;
+}
+
+// Calculate the block data size.
+// Block arrayness is not taken into account, each element is backed by a separate buffer.
+int TIntermediate::getBlockSize(const TType& blockType)
+{
+    const TTypeList& memberList = *blockType.getStruct();
+    int lastIndex = (int)memberList.size() - 1;
+    int lastOffset = getOffset(blockType, lastIndex);
+
+    int lastMemberSize;
+    int dummyStride;
+    getMemberAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride,
+                       blockType.getQualifier().layoutPacking,
+                       blockType.getQualifier().layoutMatrix == ElmRowMajor);
+
+    return lastOffset + lastMemberSize;
+}
+
+int TIntermediate::computeBufferReferenceTypeSize(const TType& type)
+{
+    assert(type.getBasicType() == EbtReference);
+    int size = getBlockSize(*type.getReferentType());
+
+    int align = type.getBufferReferenceAlignment();
+
+    if (align) {
+        size = (size + align - 1) & ~(align-1);
+    }
+
+    return size;
+}
+
 } // end namespace glslang
 } // end namespace glslang

+ 75 - 8
src/libraries/glslang/glslang/MachineIndependent/localintermediate.h

@@ -149,11 +149,20 @@ struct TOffsetRange {
 
 
 // Things that need to be tracked per xfb buffer.
 // Things that need to be tracked per xfb buffer.
 struct TXfbBuffer {
 struct TXfbBuffer {
-    TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), containsDouble(false) { }
+#ifdef AMD_EXTENSIONS
+    TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), contains64BitType(false),
+                   contains32BitType(false), contains16BitType(false) { }
+#else
+    TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), contains64BitType(false) { }
+#endif
     std::vector<TRange> ranges;  // byte offsets that have already been assigned
     std::vector<TRange> ranges;  // byte offsets that have already been assigned
     unsigned int stride;
     unsigned int stride;
     unsigned int implicitStride;
     unsigned int implicitStride;
-    bool containsDouble;
+    bool contains64BitType;
+#ifdef AMD_EXTENSIONS
+    bool contains32BitType;
+    bool contains16BitType;
+#endif
 };
 };
 
 
 // Track a set of strings describing how the module was processed.
 // Track a set of strings describing how the module was processed.
@@ -252,9 +261,11 @@ public:
         useStorageBuffer(false),
         useStorageBuffer(false),
         useVulkanMemoryModel(false),
         useVulkanMemoryModel(false),
         hlslIoMapping(false),
         hlslIoMapping(false),
+        useVariablePointers(false),
         textureSamplerTransformMode(EShTexSampTransKeep),
         textureSamplerTransformMode(EShTexSampTransKeep),
         needToLegalize(false),
         needToLegalize(false),
         binaryDoubleOutput(false),
         binaryDoubleOutput(false),
+        usePhysicalStorageBuffer(false),
         uniformLocationBase(0)
         uniformLocationBase(0)
     {
     {
         localSize[0] = 1;
         localSize[0] = 1;
@@ -390,6 +401,17 @@ public:
         processes.addProcess("use-vulkan-memory-model");
         processes.addProcess("use-vulkan-memory-model");
     }
     }
     bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; }
     bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; }
+    void setUsePhysicalStorageBuffer()
+    {
+        usePhysicalStorageBuffer = true;
+    }
+    bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; }
+    void setUseVariablePointers()
+    {
+        useVariablePointers = true;
+        processes.addProcess("use-variable-pointers");
+    }
+    bool usingVariablePointers() const { return useVariablePointers; }
 
 
     template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; }
     template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; }
     bool hasCounterBufferName(const TString& name) const {
     bool hasCounterBufferName(const TString& name) const {
@@ -414,11 +436,40 @@ public:
         if (spvVersion.openGl > 0)
         if (spvVersion.openGl > 0)
             processes.addProcess("client opengl100");
             processes.addProcess("client opengl100");
 
 
+        // target SPV
+        switch (spvVersion.spv) {
+        case 0:
+            break;
+        case EShTargetSpv_1_0:
+            break;
+        case EShTargetSpv_1_1:
+            processes.addProcess("target-env spirv1.1");
+            break;
+        case EShTargetSpv_1_2:
+            processes.addProcess("target-env spirv1.2");
+            break;
+        case EShTargetSpv_1_3:
+            processes.addProcess("target-env spirv1.3");
+            break;
+        default:
+            processes.addProcess("target-env spirvUnknown");
+            break;
+        }
+
         // target-environment processes
         // target-environment processes
-        if (spvVersion.vulkan > 0)
+        switch (spvVersion.vulkan) {
+        case 0:
+            break;
+        case EShTargetVulkan_1_0:
             processes.addProcess("target-env vulkan1.0");
             processes.addProcess("target-env vulkan1.0");
-        else if (spvVersion.vulkan > 0)
+            break;
+        case EShTargetVulkan_1_1:
+            processes.addProcess("target-env vulkan1.1");
+            break;
+        default:
             processes.addProcess("target-env vulkanUnknown");
             processes.addProcess("target-env vulkanUnknown");
+            break;
+        }
         if (spvVersion.openGl > 0)
         if (spvVersion.openGl > 0)
             processes.addProcess("target-env opengl");
             processes.addProcess("target-env opengl");
     }
     }
@@ -444,9 +495,10 @@ public:
     TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
     TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
     TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
     TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
     TIntermSymbol* addSymbol(const TIntermSymbol&);
     TIntermSymbol* addSymbol(const TIntermSymbol&);
-    TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
-    std::tuple<TIntermTyped*, TIntermTyped*> addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1) const;
+    TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
+    std::tuple<TIntermTyped*, TIntermTyped*> addConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1);
     TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*);
     TIntermTyped* addUniShapeConversion(TOperator, const TType&, TIntermTyped*);
+    TIntermTyped* addConversion(TBasicType convertTo, TIntermTyped* node) const;
     void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode);
     void addBiShapeConversion(TOperator, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode);
     TIntermTyped* addShapeConversion(const TType&, TIntermTyped*);
     TIntermTyped* addShapeConversion(const TType&, TIntermTyped*);
     TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
     TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
@@ -634,12 +686,20 @@ public:
     }
     }
     unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; }
     unsigned getXfbStride(int buffer) const { return xfbBuffers[buffer].stride; }
     int addXfbBufferOffset(const TType&);
     int addXfbBufferOffset(const TType&);
-    unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const;
+#ifdef AMD_EXTENSIONS
+    unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType, bool& contains32BitType, bool& contains16BitType) const;
+#else
+    unsigned int computeTypeXfbSize(const TType&, bool& contains64BitType) const;
+#endif
     static int getBaseAlignmentScalar(const TType&, int& size);
     static int getBaseAlignmentScalar(const TType&, int& size);
     static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
     static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
     static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);
     static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor);
     static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
     static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor);
     static bool improperStraddle(const TType& type, int size, int offset);
     static bool improperStraddle(const TType& type, int size, int offset);
+    static void updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize);
+    static int getOffset(const TType& type, int index);
+    static int getBlockSize(const TType& blockType);
+    static int computeBufferReferenceTypeSize(const TType&);
     bool promote(TIntermOperator*);
     bool promote(TIntermOperator*);
 
 
 #ifdef NV_EXTENSIONS
 #ifdef NV_EXTENSIONS
@@ -666,8 +726,10 @@ public:
 
 
     void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; }
     void setSourceFile(const char* file) { if (file != nullptr) sourceFile = file; }
     const std::string& getSourceFile() const { return sourceFile; }
     const std::string& getSourceFile() const { return sourceFile; }
-    void addSourceText(const char* text) { sourceText = sourceText + text; }
+    void addSourceText(const char* text, size_t len) { sourceText.append(text, len); }
     const std::string& getSourceText() const { return sourceText; }
     const std::string& getSourceText() const { return sourceText; }
+    const std::map<std::string, std::string>& getIncludeText() const { return includeText; }
+    void addIncludeText(const char* name, const char* text, size_t len) { includeText[name].assign(text,len); }
     void addProcesses(const std::vector<std::string>& p)
     void addProcesses(const std::vector<std::string>& p)
     {
     {
         for (int i = 0; i < (int)p.size(); ++i)
         for (int i = 0; i < (int)p.size(); ++i)
@@ -802,6 +864,7 @@ protected:
     bool useStorageBuffer;
     bool useStorageBuffer;
     bool useVulkanMemoryModel;
     bool useVulkanMemoryModel;
     bool hlslIoMapping;
     bool hlslIoMapping;
+    bool useVariablePointers;
 
 
     std::set<TString> ioAccessed;           // set of names of statically read/written I/O that might need extra checking
     std::set<TString> ioAccessed;           // set of names of statically read/written I/O that might need extra checking
     std::vector<TIoRange> usedIo[4];        // sets of used locations, one for each of in, out, uniform, and buffers
     std::vector<TIoRange> usedIo[4];        // sets of used locations, one for each of in, out, uniform, and buffers
@@ -815,11 +878,15 @@ protected:
     std::string sourceFile;
     std::string sourceFile;
     std::string sourceText;
     std::string sourceText;
 
 
+    // Included text. First string is a name, second is the included text
+    std::map<std::string, std::string> includeText;
+
     // for OpModuleProcessed, or equivalent
     // for OpModuleProcessed, or equivalent
     TProcesses processes;
     TProcesses processes;
 
 
     bool needToLegalize;
     bool needToLegalize;
     bool binaryDoubleOutput;
     bool binaryDoubleOutput;
+    bool usePhysicalStorageBuffer;
 
 
     std::unordered_map<std::string, int> uniformLocationOverrides;
     std::unordered_map<std::string, int> uniformLocationOverrides;
     int uniformLocationBase;
     int uniformLocationBase;

+ 1 - 0
src/libraries/glslang/glslang/MachineIndependent/parseVersions.h

@@ -104,6 +104,7 @@ public:
     virtual bool checkExtensionsRequested(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
     virtual bool checkExtensionsRequested(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
     virtual void updateExtensionBehavior(const char* const extension, TExtensionBehavior);
     virtual void updateExtensionBehavior(const char* const extension, TExtensionBehavior);
     virtual void checkExtensionStage(const TSourceLoc&, const char* const extension);
     virtual void checkExtensionStage(const TSourceLoc&, const char* const extension);
+    virtual void fcoopmatCheck(const TSourceLoc&, const char* op, bool builtIn = false);
 
 
     virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
     virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
         const char* szExtraInfoFormat, ...) = 0;
         const char* szExtraInfoFormat, ...) = 0;

+ 36 - 19
src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp

@@ -147,6 +147,10 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
         }
         }
 
 
         token = scanToken(ppToken);
         token = scanToken(ppToken);
+    } else if (token != '\n' && token != EndOfInput && !ppToken->space) {
+        parseContext.ppWarn(ppToken->loc, "missing space after macro name", "#define", "");
+
+        return token;
     }
     }
 
 
     // record the definition of the macro
     // record the definition of the macro
@@ -162,29 +166,43 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
     if (existing != nullptr) {
     if (existing != nullptr) {
         if (! existing->undef) {
         if (! existing->undef) {
             // Already defined -- need to make sure they are identical:
             // Already defined -- need to make sure they are identical:
-            // "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number,
-            // ordering, spelling, and white-space separation, where all white-space separations are considered identical."
-            if (existing->functionLike != mac.functionLike)
-                parseContext.ppError(defineLoc, "Macro redefined; function-like versus object-like:", "#define", atomStrings.getString(defAtom));
-            else if (existing->args.size() != mac.args.size())
-                parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", atomStrings.getString(defAtom));
-            else {
-                if (existing->args != mac.args)
-                    parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", atomStrings.getString(defAtom));
+            // "Two replacement lists are identical if and only if the
+            // preprocessing tokens in both have the same number,
+            // ordering, spelling, and white-space separation, where all
+            // white-space separations are considered identical."
+            if (existing->functionLike != mac.functionLike) {
+                parseContext.ppError(defineLoc, "Macro redefined; function-like versus object-like:", "#define",
+                    atomStrings.getString(defAtom));
+            } else if (existing->args.size() != mac.args.size()) {
+                parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define",
+                    atomStrings.getString(defAtom));
+            } else {
+                if (existing->args != mac.args) {
+                    parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define",
+                       atomStrings.getString(defAtom));
+                }
+                // set up to compare the two
                 existing->body.reset();
                 existing->body.reset();
                 mac.body.reset();
                 mac.body.reset();
                 int newToken;
                 int newToken;
+                bool firstToken = true;
                 do {
                 do {
                     int oldToken;
                     int oldToken;
                     TPpToken oldPpToken;
                     TPpToken oldPpToken;
                     TPpToken newPpToken;
                     TPpToken newPpToken;
                     oldToken = existing->body.getToken(parseContext, &oldPpToken);
                     oldToken = existing->body.getToken(parseContext, &oldPpToken);
                     newToken = mac.body.getToken(parseContext, &newPpToken);
                     newToken = mac.body.getToken(parseContext, &newPpToken);
+                    // for the first token, preceding spaces don't matter
+                    if (firstToken) {
+                        newPpToken.space = oldPpToken.space;
+                        firstToken = false;
+                    }
                     if (oldToken != newToken || oldPpToken != newPpToken) {
                     if (oldToken != newToken || oldPpToken != newPpToken) {
-                        parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", atomStrings.getString(defAtom));
+                        parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define",
+                            atomStrings.getString(defAtom));
                         break;
                         break;
                     }
                     }
-                } while (newToken > 0);
+                } while (newToken != EndOfInput);
             }
             }
         }
         }
         *existing = mac;
         *existing = mac;
@@ -653,6 +671,7 @@ int TPpContext::CPPinclude(TPpToken* ppToken)
             epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") <<
             epilogue << (res->headerData[res->headerLength - 1] == '\n'? "" : "\n") <<
                 "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
                 "#line " << directiveLoc.line + forNextLine << " " << directiveLoc.getStringNameOrNum() << "\n";
             pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this));
             pushInput(new TokenizableIncludeFile(directiveLoc, prologue.str(), res, epilogue.str(), this));
+            parseContext.intermediate.addIncludeText(res->headerName.c_str(), res->headerData, res->headerLength);
             // There's no "current" location anymore.
             // There's no "current" location anymore.
             parseContext.setCurrentColumn(0);
             parseContext.setCurrentColumn(0);
         } else {
         } else {
@@ -861,8 +880,7 @@ int TPpContext::CPPextension(TPpToken* ppToken)
     if (token != PpAtomIdentifier)
     if (token != PpAtomIdentifier)
         parseContext.ppError(ppToken->loc, "extension name expected", "#extension", "");
         parseContext.ppError(ppToken->loc, "extension name expected", "#extension", "");
 
 
-    assert(strlen(ppToken->name) <= MaxTokenLength);
-    strcpy(extensionName, ppToken->name);
+    snprintf(extensionName, sizeof(extensionName), "%s", ppToken->name);
 
 
     token = scanToken(ppToken);
     token = scanToken(ppToken);
     if (token != ':') {
     if (token != ':') {
@@ -1022,7 +1040,9 @@ TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken*
             case MacroExpandNotStarted:
             case MacroExpandNotStarted:
                 break;
                 break;
             case MacroExpandError:
             case MacroExpandError:
-                token = EndOfInput;
+                // toss the rest of the pushed-input argument by scanning until tMarkerInput
+                while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput)
+                    ;
                 break;
                 break;
             case MacroExpandStarted:
             case MacroExpandStarted:
             case MacroExpandUndef:
             case MacroExpandUndef:
@@ -1034,13 +1054,10 @@ TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken*
         expandedArg->putToken(token, ppToken);
         expandedArg->putToken(token, ppToken);
     }
     }
 
 
-    if (token == EndOfInput) {
+    if (token != tMarkerInput::marker) {
         // Error, or MacroExpand ate the marker, so had bad input, recover
         // Error, or MacroExpand ate the marker, so had bad input, recover
         delete expandedArg;
         delete expandedArg;
         expandedArg = nullptr;
         expandedArg = nullptr;
-    } else {
-        // remove the marker
-        popInput();
     }
     }
 
 
     return expandedArg;
     return expandedArg;
@@ -1257,7 +1274,7 @@ MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, b
 
 
             if (token == ')') {
             if (token == ')') {
                 // closing paren of call
                 // closing paren of call
-                if (in->mac->args.size() == 1 && tokenRecorded == 0)
+                if (in->mac->args.size() == 1 && !tokenRecorded)
                     break;
                     break;
                 arg++;
                 arg++;
                 break;
                 break;

+ 81 - 15
src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h

@@ -84,6 +84,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <sstream>
 #include <sstream>
 
 
 #include "../ParseHelper.h"
 #include "../ParseHelper.h"
+#include "PpTokens.h"
 
 
 /* windows only pragma */
 /* windows only pragma */
 #ifdef _MSC_VER
 #ifdef _MSC_VER
@@ -212,7 +213,8 @@ public:
         virtual int scan(TPpToken*) = 0;
         virtual int scan(TPpToken*) = 0;
         virtual int getch() = 0;
         virtual int getch() = 0;
         virtual void ungetch() = 0;
         virtual void ungetch() = 0;
-        virtual bool peekPasting() { return false; }          // true when about to see ##
+        virtual bool peekPasting() { return false; }             // true when about to see ##
+        virtual bool peekContinuedPasting(int) { return false; } // true when non-spaced tokens can paste
         virtual bool endOfReplacementList() { return false; } // true when at the end of a macro replacement list (RHS of #define)
         virtual bool endOfReplacementList() { return false; } // true when at the end of a macro replacement list (RHS of #define)
         virtual bool isMacroInput() { return false; }
         virtual bool isMacroInput() { return false; }
 
 
@@ -243,24 +245,79 @@ public:
     // From PpTokens.cpp
     // From PpTokens.cpp
     //
     //
 
 
+    // Capture the needed parts of a token stream for macro recording/playback.
     class TokenStream {
     class TokenStream {
     public:
     public:
-        TokenStream() : current(0) { }
+        // Manage a stream of these 'Token', which capture the relevant parts
+        // of a TPpToken, plus its atom.
+        class Token {
+        public:
+            Token(int atom, const TPpToken& ppToken) : 
+                atom(atom),
+                space(ppToken.space),
+                i64val(ppToken.i64val),
+                name(ppToken.name) { }
+            int get(TPpToken& ppToken)
+            {
+                ppToken.clear();
+                ppToken.space = space;
+                ppToken.i64val = i64val;
+                snprintf(ppToken.name, sizeof(ppToken.name), "%s", name.c_str());
+                return atom;
+            }
+            bool isAtom(int a) const { return atom == a; }
+            int getAtom() const { return atom; }
+            bool nonSpaced() const { return !space; }
+        protected:
+            Token() {}
+            int atom;
+            bool space;        // did a space precede the token?
+            long long i64val;
+            TString name;
+        };
+
+        TokenStream() : currentPos(0) { }
 
 
         void putToken(int token, TPpToken* ppToken);
         void putToken(int token, TPpToken* ppToken);
+        bool peekToken(int atom) { return !atEnd() && stream[currentPos].isAtom(atom); }
+        bool peekContinuedPasting(int atom)
+        {
+            // This is basically necessary because, for example, the PP
+            // tokenizer only accepts valid numeric-literals plus suffixes, so
+            // separates numeric-literals plus bad suffix into two tokens, which
+            // should get both pasted together as one token when token pasting.
+            //
+            // The following code is a bit more generalized than the above example.
+            if (!atEnd() && atom == PpAtomIdentifier && stream[currentPos].nonSpaced()) {
+                switch(stream[currentPos].getAtom()) {
+                    case PpAtomConstInt:
+                    case PpAtomConstUint:
+                    case PpAtomConstInt64:
+                    case PpAtomConstUint64:
+                    case PpAtomConstInt16:
+                    case PpAtomConstUint16:
+                    case PpAtomConstFloat:
+                    case PpAtomConstDouble:
+                    case PpAtomConstFloat16:
+                    case PpAtomConstString:
+                    case PpAtomIdentifier:
+                        return true;
+                    default:
+                        break;
+                }
+            }
+
+            return false;
+        }
         int getToken(TParseContextBase&, TPpToken*);
         int getToken(TParseContextBase&, TPpToken*);
-        bool atEnd() { return current >= data.size(); }
+        bool atEnd() { return currentPos >= stream.size(); }
         bool peekTokenizedPasting(bool lastTokenPastes);
         bool peekTokenizedPasting(bool lastTokenPastes);
         bool peekUntokenizedPasting();
         bool peekUntokenizedPasting();
-        void reset() { current = 0; }
+        void reset() { currentPos = 0; }
 
 
     protected:
     protected:
-        void putSubtoken(char);
-        int getSubtoken();
-        void ungetSubtoken();
-
-        TVector<unsigned char> data;
-        size_t current;
+        TVector<Token> stream;
+        size_t currentPos;
     };
     };
 
 
     //
     //
@@ -320,6 +377,10 @@ protected:
     int  getChar() { return inputStack.back()->getch(); }
     int  getChar() { return inputStack.back()->getch(); }
     void ungetChar() { inputStack.back()->ungetch(); }
     void ungetChar() { inputStack.back()->ungetch(); }
     bool peekPasting() { return !inputStack.empty() && inputStack.back()->peekPasting(); }
     bool peekPasting() { return !inputStack.empty() && inputStack.back()->peekPasting(); }
+    bool peekContinuedPasting(int a)
+    {
+        return !inputStack.empty() && inputStack.back()->peekContinuedPasting(a);
+    }
     bool endOfReplacementList() { return inputStack.empty() || inputStack.back()->endOfReplacementList(); }
     bool endOfReplacementList() { return inputStack.empty() || inputStack.back()->endOfReplacementList(); }
     bool isMacroInput() { return inputStack.size() > 0 && inputStack.back()->isMacroInput(); }
     bool isMacroInput() { return inputStack.size() > 0 && inputStack.back()->isMacroInput(); }
 
 
@@ -344,6 +405,7 @@ protected:
         virtual int getch() override { assert(0); return EndOfInput; }
         virtual int getch() override { assert(0); return EndOfInput; }
         virtual void ungetch() override { assert(0); }
         virtual void ungetch() override { assert(0); }
         bool peekPasting() override { return prepaste; }
         bool peekPasting() override { return prepaste; }
+        bool peekContinuedPasting(int a) override { return mac->body.peekContinuedPasting(a); }
         bool endOfReplacementList() override { return mac->body.atEnd(); }
         bool endOfReplacementList() override { return mac->body.atEnd(); }
         bool isMacroInput() override { return true; }
         bool isMacroInput() override { return true; }
 
 
@@ -418,14 +480,18 @@ protected:
 
 
     class tTokenInput : public tInput {
     class tTokenInput : public tInput {
     public:
     public:
-        tTokenInput(TPpContext* pp, TokenStream* t, bool prepasting) : tInput(pp), tokens(t), lastTokenPastes(prepasting) { }
+        tTokenInput(TPpContext* pp, TokenStream* t, bool prepasting) :
+            tInput(pp),
+            tokens(t),
+            lastTokenPastes(prepasting) { }
         virtual int scan(TPpToken *ppToken) override { return tokens->getToken(pp->parseContext, ppToken); }
         virtual int scan(TPpToken *ppToken) override { return tokens->getToken(pp->parseContext, ppToken); }
         virtual int getch() override { assert(0); return EndOfInput; }
         virtual int getch() override { assert(0); return EndOfInput; }
         virtual void ungetch() override { assert(0); }
         virtual void ungetch() override { assert(0); }
         virtual bool peekPasting() override { return tokens->peekTokenizedPasting(lastTokenPastes); }
         virtual bool peekPasting() override { return tokens->peekTokenizedPasting(lastTokenPastes); }
+        bool peekContinuedPasting(int a) override { return tokens->peekContinuedPasting(a); }
     protected:
     protected:
         TokenStream* tokens;
         TokenStream* tokens;
-        bool lastTokenPastes;     // true if the last token in the input is to be pasted, rather than consumed as a token
+        bool lastTokenPastes; // true if the last token in the input is to be pasted, rather than consumed as a token
     };
     };
 
 
     class tUngotTokenInput : public tInput {
     class tUngotTokenInput : public tInput {
@@ -549,9 +615,9 @@ protected:
               scanner.setLine(startLoc.line);
               scanner.setLine(startLoc.line);
               scanner.setString(startLoc.string);
               scanner.setString(startLoc.string);
 
 
-              scanner.setFile(startLoc.name->c_str(), 0);
-              scanner.setFile(startLoc.name->c_str(), 1);
-              scanner.setFile(startLoc.name->c_str(), 2);
+              scanner.setFile(startLoc.getFilenameStr(), 0);
+              scanner.setFile(startLoc.getFilenameStr(), 1);
+              scanner.setFile(startLoc.getFilenameStr(), 2);
         }
         }
 
 
         // tInput methods:
         // tInput methods:

+ 82 - 59
src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp

@@ -96,12 +96,19 @@ namespace glslang {
 /////////////////////////////////// Floating point constants: /////////////////////////////////
 /////////////////////////////////// Floating point constants: /////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 
-/*
-* lFloatConst() - Scan a single- or double-precision floating point constant.  Assumes that the scanner
-*         has seen at least one digit, followed by either a decimal '.' or the
-*         letter 'e', or a precision ending (e.g., F or LF).
-*/
-
+// 
+// Scan a single- or double-precision floating point constant.
+// Assumes that the scanner has seen at least one digit,
+// followed by either a decimal '.' or the letter 'e', or a
+// precision ending (e.g., F or LF).
+//
+// This is technically not correct, as the preprocessor should just
+// accept the numeric literal along with whatever suffix it has, but
+// currently, it stops on seeing a bad suffix, treating that as the
+// next token. This effects things like token pasting, where it is
+// relevant how many tokens something was broken into.
+//
+// See peekContinuedPasting().
 int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
 int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
 {
 {
     const auto saveName = [&](int ch) {
     const auto saveName = [&](int ch) {
@@ -435,6 +442,14 @@ int TPpContext::characterLiteral(TPpToken* ppToken)
 //
 //
 // Scanner used to tokenize source stream.
 // Scanner used to tokenize source stream.
 //
 //
+// N.B. Invalid numeric suffixes are not consumed.//
+// This is technically not correct, as the preprocessor should just
+// accept the numeric literal along with whatever suffix it has, but
+// currently, it stops on seeing a bad suffix, treating that as the
+// next token. This effects things like token pasting, where it is
+// relevant how many tokens something was broken into.
+// See peekContinuedPasting().
+//
 int TPpContext::tStringInput::scan(TPpToken* ppToken)
 int TPpContext::tStringInput::scan(TPpToken* ppToken)
 {
 {
     int AlreadyComplained = 0;
     int AlreadyComplained = 0;
@@ -1116,7 +1131,7 @@ int TPpContext::tokenize(TPpToken& ppToken)
             parseContext.ppError(ppToken.loc, "character literals not supported", "\'", "");
             parseContext.ppError(ppToken.loc, "character literals not supported", "\'", "");
             continue;
             continue;
         default:
         default:
-            strcpy(ppToken.name, atomStrings.getString(token));
+            snprintf(ppToken.name, sizeof(ppToken.name), "%s", atomStrings.getString(token));
             break;
             break;
         }
         }
 
 
@@ -1153,61 +1168,69 @@ int TPpContext::tokenPaste(int token, TPpToken& ppToken)
             break;
             break;
         }
         }
 
 
-        // get the token after the ##
-        token = scanToken(&pastedPpToken);
+        // Get the token(s) after the ##.
+        // Because of "space" semantics, and prior tokenization, what
+        // appeared a single token, e.g. "3A", might have been tokenized
+        // into two tokens "3" and "A", but the "A" will have 'space' set to
+        // false.  Accumulate all of these to recreate the original lexical
+        // appearing token.
+        do {
+            token = scanToken(&pastedPpToken);
 
 
-        // This covers end of argument expansion
-        if (token == tMarkerInput::marker) {
-            parseContext.ppError(ppToken.loc, "unexpected location; end of argument", "##", "");
-            break;
-        }
+            // This covers end of argument expansion
+            if (token == tMarkerInput::marker) {
+                parseContext.ppError(ppToken.loc, "unexpected location; end of argument", "##", "");
+                return resultToken;
+            }
 
 
-        // get the token text
-        switch (resultToken) {
-        case PpAtomIdentifier:
-            // already have the correct text in token.names
-            break;
-        case '=':
-        case '!':
-        case '-':
-        case '~':
-        case '+':
-        case '*':
-        case '/':
-        case '%':
-        case '<':
-        case '>':
-        case '|':
-        case '^':
-        case '&':
-        case PpAtomRight:
-        case PpAtomLeft:
-        case PpAtomAnd:
-        case PpAtomOr:
-        case PpAtomXor:
-            strcpy(ppToken.name, atomStrings.getString(resultToken));
-            strcpy(pastedPpToken.name, atomStrings.getString(token));
-            break;
-        default:
-            parseContext.ppError(ppToken.loc, "not supported for these tokens", "##", "");
-            return resultToken;
-        }
+            // get the token text
+            switch (resultToken) {
+            case PpAtomIdentifier:
+                // already have the correct text in token.names
+                break;
+            case '=':
+            case '!':
+            case '-':
+            case '~':
+            case '+':
+            case '*':
+            case '/':
+            case '%':
+            case '<':
+            case '>':
+            case '|':
+            case '^':
+            case '&':
+            case PpAtomRight:
+            case PpAtomLeft:
+            case PpAtomAnd:
+            case PpAtomOr:
+            case PpAtomXor:
+                snprintf(ppToken.name, sizeof(ppToken.name), "%s", atomStrings.getString(resultToken));
+                snprintf(pastedPpToken.name, sizeof(pastedPpToken.name), "%s", atomStrings.getString(token));
+                break;
+            default:
+                parseContext.ppError(ppToken.loc, "not supported for these tokens", "##", "");
+                return resultToken;
+            }
 
 
-        // combine the tokens
-        if (strlen(ppToken.name) + strlen(pastedPpToken.name) > MaxTokenLength) {
-            parseContext.ppError(ppToken.loc, "combined tokens are too long", "##", "");
-            return resultToken;
-        }
-        strncat(ppToken.name, pastedPpToken.name, MaxTokenLength - strlen(ppToken.name));
-
-        // correct the kind of token we are making, if needed (identifiers stay identifiers)
-        if (resultToken != PpAtomIdentifier) {
-            int newToken = atomStrings.getAtom(ppToken.name);
-            if (newToken > 0)
-                resultToken = newToken;
-            else
-                parseContext.ppError(ppToken.loc, "combined token is invalid", "##", "");
-        }
+            // combine the tokens
+            if (strlen(ppToken.name) + strlen(pastedPpToken.name) > MaxTokenLength) {
+                parseContext.ppError(ppToken.loc, "combined tokens are too long", "##", "");
+                return resultToken;
+            }
+            snprintf(&ppToken.name[0] + strlen(ppToken.name), sizeof(ppToken.name) - strlen(ppToken.name),
+                "%s", pastedPpToken.name);
+
+            // correct the kind of token we are making, if needed (identifiers stay identifiers)
+            if (resultToken != PpAtomIdentifier) {
+                int newToken = atomStrings.getAtom(ppToken.name);
+                if (newToken > 0)
+                    resultToken = newToken;
+                else
+                    parseContext.ppError(ppToken.loc, "combined token is invalid", "##", "");
+            }
+        } while (peekContinuedPasting(resultToken));
     }
     }
 
 
     return resultToken;
     return resultToken;

+ 31 - 152
src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp

@@ -99,151 +99,33 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 namespace glslang {
 namespace glslang {
 
 
-
-namespace {
-
-    // When recording (and playing back) should the backing name string
-    // be saved (restored)?
-    bool SaveName(int atom)
-    {
-        switch (atom) {
-        case PpAtomIdentifier:
-        case PpAtomConstString:
-        case PpAtomConstInt:
-        case PpAtomConstUint:
-        case PpAtomConstInt64:
-        case PpAtomConstUint64:
-    #ifdef AMD_EXTENSIONS
-        case PpAtomConstInt16:
-        case PpAtomConstUint16:
-    #endif
-        case PpAtomConstFloat:
-        case PpAtomConstDouble:
-        case PpAtomConstFloat16:
-            return true;
-        default:
-            return false;
-        }
-    }
-
-    // When recording (and playing back) should the numeric value
-    // be saved (restored)?
-    bool SaveValue(int atom)
-    {
-        switch (atom) {
-        case PpAtomConstInt:
-        case PpAtomConstUint:
-        case PpAtomConstInt64:
-        case PpAtomConstUint64:
-    #ifdef AMD_EXTENSIONS
-        case PpAtomConstInt16:
-        case PpAtomConstUint16:
-    #endif
-        case PpAtomConstFloat:
-        case PpAtomConstDouble:
-        case PpAtomConstFloat16:
-            return true;
-        default:
-            return false;
-        }
-    }
-}
-
-// push onto back of stream
-void TPpContext::TokenStream::putSubtoken(char subtoken)
-{
-    data.push_back(static_cast<unsigned char>(subtoken));
-}
-
-// get the next token in stream
-int TPpContext::TokenStream::getSubtoken()
-{
-    if (current < data.size())
-        return data[current++];
-    else
-        return EndOfInput;
-}
-
-// back up one position in the stream
-void TPpContext::TokenStream::ungetSubtoken()
-{
-    if (current > 0)
-        --current;
-}
-
-// Add a complete token (including backing string) to the end of a list
-// for later playback.
+// Add a token (including backing string) to the end of a macro
+// token stream, for later playback.
 void TPpContext::TokenStream::putToken(int atom, TPpToken* ppToken)
 void TPpContext::TokenStream::putToken(int atom, TPpToken* ppToken)
 {
 {
-    // save the atom
-    assert((atom & ~0xff) == 0);
-    putSubtoken(static_cast<char>(atom));
-
-    // save the backing name string
-    if (SaveName(atom)) {
-        const char* s = ppToken->name;
-        while (*s)
-            putSubtoken(*s++);
-        putSubtoken(0);
-    }
-
-    // save the numeric value
-    if (SaveValue(atom)) {
-        const char* n = reinterpret_cast<const char*>(&ppToken->i64val);
-        for (size_t i = 0; i < sizeof(ppToken->i64val); ++i)
-            putSubtoken(*n++);
-    }
+    TokenStream::Token streamToken(atom, *ppToken);
+    stream.push_back(streamToken);
 }
 }
 
 
-// Read the next token from a token stream.
-// (Not the source stream, but a stream used to hold a tokenized macro).
+// Read the next token from a macro token stream.
 int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken *ppToken)
 int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken *ppToken)
 {
 {
-    // get the atom
-    int atom = getSubtoken();
-    if (atom == EndOfInput)
-        return atom;
+    if (atEnd())
+        return EndOfInput;
 
 
-    // init the token
-    ppToken->clear();
+    int atom = stream[currentPos++].get(*ppToken);
     ppToken->loc = parseContext.getCurrentLoc();
     ppToken->loc = parseContext.getCurrentLoc();
 
 
-    // get the backing name string
-    if (SaveName(atom)) {
-        int ch = getSubtoken();
-        int len = 0;
-        while (ch != 0 && ch != EndOfInput) {
-            if (len < MaxTokenLength) {
-                ppToken->name[len] = (char)ch;
-                len++;
-                ch = getSubtoken();
-            } else {
-                parseContext.error(ppToken->loc, "token too long", "", "");
-                break;
-            }
-        }
-        ppToken->name[len] = 0;
-    }
-
     // Check for ##, unless the current # is the last character
     // Check for ##, unless the current # is the last character
     if (atom == '#') {
     if (atom == '#') {
-        if (current < data.size()) {
-            if (getSubtoken() == '#') {
-                parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
-                parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
-                atom = PpAtomPaste;
-            } else
-                ungetSubtoken();
+        if (peekToken('#')) {
+            parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
+            parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
+            currentPos++;
+            atom = PpAtomPaste;
         }
         }
     }
     }
 
 
-    // get the numeric value
-    if (SaveValue(atom)) {
-        char* n = reinterpret_cast<char*>(&ppToken->i64val);
-        for (size_t i = 0; i < sizeof(ppToken->i64val); ++i)
-            *n++ = (char)getSubtoken();
-    }
-
     return atom;
     return atom;
 }
 }
 
 
@@ -256,15 +138,14 @@ bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes)
 {
 {
     // 1. preceding ##?
     // 1. preceding ##?
 
 
-    size_t savePos = current;
-    int subtoken;
+    size_t savePos = currentPos;
     // skip white space
     // skip white space
-    do {
-        subtoken = getSubtoken();
-    } while (subtoken == ' ');
-    current = savePos;
-    if (subtoken == PpAtomPaste)
+    while (peekToken(' '))
+        ++currentPos;
+    if (peekToken(PpAtomPaste)) {
+        currentPos = savePos;
         return true;
         return true;
+    }
 
 
     // 2. last token and we've been told after this there will be a ##
     // 2. last token and we've been told after this there will be a ##
 
 
@@ -273,18 +154,18 @@ bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes)
     // Getting here means the last token will be pasted, after this
     // Getting here means the last token will be pasted, after this
 
 
     // Are we at the last non-whitespace token?
     // Are we at the last non-whitespace token?
-    savePos = current;
+    savePos = currentPos;
     bool moreTokens = false;
     bool moreTokens = false;
     do {
     do {
-        subtoken = getSubtoken();
-        if (subtoken == EndOfInput)
+        if (atEnd())
             break;
             break;
-        if (subtoken != ' ') {
+        if (!peekToken(' ')) {
             moreTokens = true;
             moreTokens = true;
             break;
             break;
         }
         }
+        ++currentPos;
     } while (true);
     } while (true);
-    current = savePos;
+    currentPos = savePos;
 
 
     return !moreTokens;
     return !moreTokens;
 }
 }
@@ -293,23 +174,21 @@ bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes)
 bool TPpContext::TokenStream::peekUntokenizedPasting()
 bool TPpContext::TokenStream::peekUntokenizedPasting()
 {
 {
     // don't return early, have to restore this
     // don't return early, have to restore this
-    size_t savePos = current;
+    size_t savePos = currentPos;
 
 
     // skip white-space
     // skip white-space
-    int subtoken;
-    do {
-        subtoken = getSubtoken();
-    } while (subtoken == ' ');
+    while (peekToken(' '))
+        ++currentPos;
 
 
     // check for ##
     // check for ##
     bool pasting = false;
     bool pasting = false;
-    if (subtoken == '#') {
-        subtoken = getSubtoken();
-        if (subtoken == '#')
+    if (peekToken('#')) {
+        ++currentPos;
+        if (peekToken('#'))
             pasting = true;
             pasting = true;
     }
     }
 
 
-    current = savePos;
+    currentPos = savePos;
 
 
     return pasting;
     return pasting;
 }
 }

+ 424 - 76
src/libraries/glslang/glslang/MachineIndependent/reflection.cpp

@@ -93,72 +93,128 @@ public:
             // Use a degenerate (empty) set of dereferences to immediately put as at the end of
             // Use a degenerate (empty) set of dereferences to immediately put as at the end of
             // the dereference change expected by blowUpActiveAggregate.
             // the dereference change expected by blowUpActiveAggregate.
             TList<TIntermBinary*> derefs;
             TList<TIntermBinary*> derefs;
-            blowUpActiveAggregate(base.getType(), base.getName(), derefs, derefs.end(), -1, -1, 0);
+            blowUpActiveAggregate(base.getType(), base.getName(), derefs, derefs.end(), -1, -1, 0, 0,
+                                  base.getQualifier().storage, true);
         }
         }
     }
     }
 
 
-    void addAttribute(const TIntermSymbol& base)
+    void addPipeIOVariable(const TIntermSymbol& base)
     {
     {
         if (processedDerefs.find(&base) == processedDerefs.end()) {
         if (processedDerefs.find(&base) == processedDerefs.end()) {
             processedDerefs.insert(&base);
             processedDerefs.insert(&base);
 
 
             const TString &name = base.getName();
             const TString &name = base.getName();
             const TType &type = base.getType();
             const TType &type = base.getType();
+            const bool input = base.getQualifier().isPipeInput();
 
 
-            TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
-            if (it == reflection.nameToIndex.end()) {
-                reflection.nameToIndex[name] = (int)reflection.indexToAttribute.size();
-                reflection.indexToAttribute.push_back(TObjectReflection(name, type, 0, mapToGlType(type), 0, 0));
+            TReflection::TMapIndexToReflection &ioItems =
+                input ? reflection.indexToPipeInput : reflection.indexToPipeOutput;
+
+            if (reflection.options & EShReflectionUnwrapIOBlocks) {
+                bool anonymous = IsAnonymous(name);
+
+                TString baseName;
+                if (type.getBasicType() == EbtBlock) {
+                    baseName = anonymous ? TString() : type.getTypeName();
+                } else {
+                    baseName = anonymous ? TString() : name;
+                }
+
+                // by convention if this is an arrayed block we ignore the array in the reflection
+                if (type.isArray() && type.getBasicType() == EbtBlock) {
+                    blowUpIOAggregate(input, baseName, TType(type, 0));
+                } else {               
+                    blowUpIOAggregate(input, baseName, type);
+                }
+            } else {
+                TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
+                if (it == reflection.nameToIndex.end()) {
+                    reflection.nameToIndex[name.c_str()] = (int)ioItems.size();
+                    ioItems.push_back(
+                        TObjectReflection(name.c_str(), type, 0, mapToGlType(type), mapToGlArraySize(type), 0));
+
+                    EShLanguageMask& stages = ioItems.back().stages;
+                    stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+                } else {
+                    EShLanguageMask& stages = ioItems[it->second].stages;
+                    stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+                }
             }
             }
         }
         }
     }
     }
 
 
-    // Lookup or calculate the offset of a block member, using the recursively
+    // Lookup or calculate the offset of all block members at once, using the recursively
     // defined block offset rules.
     // defined block offset rules.
-    int getOffset(const TType& type, int index)
+    void getOffsets(const TType& type, TVector<int>& offsets)
     {
     {
         const TTypeList& memberList = *type.getStruct();
         const TTypeList& memberList = *type.getStruct();
 
 
-        // Don't calculate offset if one is present, it could be user supplied
-        // and different than what would be calculated.  That is, this is faster,
-        // but not just an optimization.
-        if (memberList[index].type->getQualifier().hasOffset())
-            return memberList[index].type->getQualifier().layoutOffset;
-
-        int memberSize;
-        int dummyStride;
+        int memberSize = 0;
         int offset = 0;
         int offset = 0;
-        for (int m = 0; m <= index; ++m) {
-            // modify just the children's view of matrix layout, if there is one for this member
-            TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix;
-            int memberAlignment = intermediate.getMemberAlignment(*memberList[m].type, memberSize, dummyStride,
-                                                                  type.getQualifier().layoutPacking,
-                                                                  subMatrixLayout != ElmNone
-                                                                      ? subMatrixLayout == ElmRowMajor
-                                                                      : type.getQualifier().layoutMatrix == ElmRowMajor);
-            RoundToPow2(offset, memberAlignment);
-            if (m < index)
-                offset += memberSize;
+        for (size_t m = 0; m < offsets.size(); ++m) {
+            // if the user supplied an offset, snap to it now
+            if (memberList[m].type->getQualifier().hasOffset())
+                offset = memberList[m].type->getQualifier().layoutOffset;
+
+            // calculate the offset of the next member and align the current offset to this member
+            intermediate.updateOffset(type, *memberList[m].type, offset, memberSize);
+
+            // save the offset of this member
+            offsets[m] = offset;
+
+            // update for the next member
+            offset += memberSize;
         }
         }
+    }
+
+    // Calculate the stride of an array type
+    int getArrayStride(const TType& baseType, const TType& type)
+    {
+        int dummySize;
+        int stride;
+
+        // consider blocks to have 0 stride, so that all offsets are relative to the start of their block
+        if (type.getBasicType() == EbtBlock)
+            return 0;
+
+        TLayoutMatrix subMatrixLayout = type.getQualifier().layoutMatrix;
+        intermediate.getMemberAlignment(type, dummySize, stride,
+                                        baseType.getQualifier().layoutPacking,
+                                        subMatrixLayout != ElmNone
+                                            ? subMatrixLayout == ElmRowMajor
+                                            : baseType.getQualifier().layoutMatrix == ElmRowMajor);
 
 
-        return offset;
+        return stride;
     }
     }
 
 
-    // Calculate the block data size.
-    // Block arrayness is not taken into account, each element is backed by a separate buffer.
-    int getBlockSize(const TType& blockType)
+    // count the total number of leaf members from iterating out of a block type
+    int countAggregateMembers(const TType& parentType)
     {
     {
-        const TTypeList& memberList = *blockType.getStruct();
-        int lastIndex = (int)memberList.size() - 1;
-        int lastOffset = getOffset(blockType, lastIndex);
+        if (! parentType.isStruct())
+            return 1;
 
 
-        int lastMemberSize;
-        int dummyStride;
-        intermediate.getMemberAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride,
-                                        blockType.getQualifier().layoutPacking,
-                                        blockType.getQualifier().layoutMatrix == ElmRowMajor);
+        const bool strictArraySuffix = (reflection.options & EShReflectionStrictArraySuffix);
 
 
-        return lastOffset + lastMemberSize;
+        bool blockParent = (parentType.getBasicType() == EbtBlock && parentType.getQualifier().storage == EvqBuffer);
+
+        const TTypeList &memberList = *parentType.getStruct();
+
+        int ret = 0;
+
+        for (size_t i = 0; i < memberList.size(); i++)
+        {
+            const TType &memberType = *memberList[i].type;
+            int numMembers = countAggregateMembers(memberType);
+            // for sized arrays of structs, apply logic to expand out the same as we would below in
+            // blowUpActiveAggregate
+            if (memberType.isArray() && ! memberType.getArraySizes()->hasUnsized() && memberType.isStruct()) {
+                if (! strictArraySuffix || ! blockParent)
+                    numMembers *= memberType.getArraySizes()->getCumulativeSize();
+            }
+            ret += numMembers;
+        }
+
+        return ret;
     }
     }
 
 
     // Traverse the provided deref chain, including the base, and
     // Traverse the provided deref chain, including the base, and
@@ -169,8 +225,19 @@ public:
     // arraySize tracks, just for the final dereference in the chain, if there was a specific known size.
     // arraySize tracks, just for the final dereference in the chain, if there was a specific known size.
     // A value of 0 for arraySize will mean to use the full array's size.
     // A value of 0 for arraySize will mean to use the full array's size.
     void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList<TIntermBinary*>& derefs,
     void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList<TIntermBinary*>& derefs,
-                               TList<TIntermBinary*>::const_iterator deref, int offset, int blockIndex, int arraySize)
+                               TList<TIntermBinary*>::const_iterator deref, int offset, int blockIndex, int arraySize,
+                               int topLevelArrayStride, TStorageQualifier baseStorage, bool active)
     {
     {
+        // when strictArraySuffix is enabled, we closely follow the rules from ARB_program_interface_query.
+        // Broadly:
+        // * arrays-of-structs always have a [x] suffix.
+        // * with array-of-struct variables in the root of a buffer block, only ever return [0].
+        // * otherwise, array suffixes are added whenever we iterate, even if that means expanding out an array.
+        const bool strictArraySuffix = (reflection.options & EShReflectionStrictArraySuffix);
+
+        // is this variable inside a buffer block. This flag is set back to false after we iterate inside the first array element.
+        bool blockParent = (baseType.getBasicType() == EbtBlock && baseType.getQualifier().storage == EvqBuffer);
+
         // process the part of the dereference chain that was explicit in the shader
         // process the part of the dereference chain that was explicit in the shader
         TString name = baseName;
         TString name = baseName;
         const TType* terminalType = &baseType;
         const TType* terminalType = &baseType;
@@ -179,29 +246,54 @@ public:
             terminalType = &visitNode->getType();
             terminalType = &visitNode->getType();
             int index;
             int index;
             switch (visitNode->getOp()) {
             switch (visitNode->getOp()) {
-            case EOpIndexIndirect:
+            case EOpIndexIndirect: {
+                int stride = getArrayStride(baseType, visitNode->getLeft()->getType());
+
+                if (topLevelArrayStride == 0)
+                    topLevelArrayStride = stride;
+
                 // Visit all the indices of this array, and for each one add on the remaining dereferencing
                 // Visit all the indices of this array, and for each one add on the remaining dereferencing
                 for (int i = 0; i < std::max(visitNode->getLeft()->getType().getOuterArraySize(), 1); ++i) {
                 for (int i = 0; i < std::max(visitNode->getLeft()->getType().getOuterArraySize(), 1); ++i) {
                     TString newBaseName = name;
                     TString newBaseName = name;
-                    if (baseType.getBasicType() != EbtBlock)
+                    if (strictArraySuffix && blockParent)
+                        newBaseName.append(TString("[0]"));
+                    else if (strictArraySuffix || baseType.getBasicType() != EbtBlock)
                         newBaseName.append(TString("[") + String(i) + "]");
                         newBaseName.append(TString("[") + String(i) + "]");
                     TList<TIntermBinary*>::const_iterator nextDeref = deref;
                     TList<TIntermBinary*>::const_iterator nextDeref = deref;
                     ++nextDeref;
                     ++nextDeref;
-                    TType derefType(*terminalType, 0);
-                    blowUpActiveAggregate(derefType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize);
+                    blowUpActiveAggregate(*terminalType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize,
+                                          topLevelArrayStride, baseStorage, active);
+
+                    if (offset >= 0)
+                        offset += stride;
                 }
                 }
 
 
                 // it was all completed in the recursive calls above
                 // it was all completed in the recursive calls above
                 return;
                 return;
-            case EOpIndexDirect:
+            }
+            case EOpIndexDirect: {
+                int stride = getArrayStride(baseType, visitNode->getLeft()->getType());
+
                 index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
                 index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
-                if (baseType.getBasicType() != EbtBlock)
+                if (strictArraySuffix && blockParent) {
+                    name.append(TString("[0]"));
+                } else if (strictArraySuffix || baseType.getBasicType() != EbtBlock) {
                     name.append(TString("[") + String(index) + "]");
                     name.append(TString("[") + String(index) + "]");
+
+                    if (offset >= 0)
+                        offset += stride * index;
+                }
+
+                if (topLevelArrayStride == 0)
+                    topLevelArrayStride = stride;
+
+                blockParent = false;
                 break;
                 break;
+            }
             case EOpIndexDirectStruct:
             case EOpIndexDirectStruct:
                 index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
                 index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
                 if (offset >= 0)
                 if (offset >= 0)
-                    offset += getOffset(visitNode->getLeft()->getType(), index);
+                    offset += intermediate.getOffset(visitNode->getLeft()->getType(), index);
                 if (name.size() > 0)
                 if (name.size() > 0)
                     name.append(".");
                     name.append(".");
                 name.append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName());
                 name.append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName());
@@ -213,24 +305,65 @@ public:
 
 
         // if the terminalType is still too coarse a granularity, this is still an aggregate to expand, expand it...
         // if the terminalType is still too coarse a granularity, this is still an aggregate to expand, expand it...
         if (! isReflectionGranularity(*terminalType)) {
         if (! isReflectionGranularity(*terminalType)) {
+            // the base offset of this node, that children are relative to
+            int baseOffset = offset;
+
             if (terminalType->isArray()) {
             if (terminalType->isArray()) {
                 // Visit all the indices of this array, and for each one,
                 // Visit all the indices of this array, and for each one,
                 // fully explode the remaining aggregate to dereference
                 // fully explode the remaining aggregate to dereference
-                for (int i = 0; i < std::max(terminalType->getOuterArraySize(), 1); ++i) {
+
+                int stride = 0;
+                if (offset >= 0)
+                    stride = getArrayStride(baseType, *terminalType);
+
+                if (topLevelArrayStride == 0)
+                    topLevelArrayStride = stride;
+
+                int arrayIterateSize = std::max(terminalType->getOuterArraySize(), 1);
+
+                // for top-level arrays in blocks, only expand [0] to avoid explosion of items
+                if (strictArraySuffix && blockParent)
+                    arrayIterateSize = 1;
+
+                for (int i = 0; i < arrayIterateSize; ++i) {
                     TString newBaseName = name;
                     TString newBaseName = name;
                     newBaseName.append(TString("[") + String(i) + "]");
                     newBaseName.append(TString("[") + String(i) + "]");
                     TType derefType(*terminalType, 0);
                     TType derefType(*terminalType, 0);
-                    blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0);
+                    if (offset >= 0)
+                        offset = baseOffset + stride * i;
+
+                    blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0,
+                                          topLevelArrayStride, baseStorage, active);
                 }
                 }
             } else {
             } else {
                 // Visit all members of this aggregate, and for each one,
                 // Visit all members of this aggregate, and for each one,
                 // fully explode the remaining aggregate to dereference
                 // fully explode the remaining aggregate to dereference
                 const TTypeList& typeList = *terminalType->getStruct();
                 const TTypeList& typeList = *terminalType->getStruct();
+
+                TVector<int> memberOffsets;
+
+                if (baseOffset >= 0) {
+                    memberOffsets.resize(typeList.size());
+                    getOffsets(*terminalType, memberOffsets);
+                }
+
                 for (int i = 0; i < (int)typeList.size(); ++i) {
                 for (int i = 0; i < (int)typeList.size(); ++i) {
                     TString newBaseName = name;
                     TString newBaseName = name;
-                    newBaseName.append(TString(".") + typeList[i].type->getFieldName());
+                    if (newBaseName.size() > 0)
+                        newBaseName.append(".");
+                    newBaseName.append(typeList[i].type->getFieldName());
                     TType derefType(*terminalType, i);
                     TType derefType(*terminalType, i);
-                    blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0);
+                    if (offset >= 0)
+                        offset = baseOffset + memberOffsets[i];
+
+                    int arrayStride = topLevelArrayStride;
+                    if (terminalType->getBasicType() == EbtBlock && terminalType->getQualifier().storage == EvqBuffer &&
+                        derefType.isArray()) {
+                        arrayStride = getArrayStride(baseType, derefType);
+                    }
+
+                    blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0,
+                                          arrayStride, baseStorage, active);
                 }
                 }
             }
             }
 
 
@@ -238,6 +371,10 @@ public:
             return;
             return;
         }
         }
 
 
+        if ((reflection.options & EShReflectionBasicArraySuffix) && terminalType->isArray()) {
+            name.append(TString("[0]"));
+        }
+
         // Finally, add a full string to the reflection database, and update the array size if necessary.
         // Finally, add a full string to the reflection database, and update the array size if necessary.
         // If the dereferenced entity to record is an array, compute the size and update the maximum size.
         // If the dereferenced entity to record is an array, compute the size and update the maximum size.
 
 
@@ -245,15 +382,100 @@ public:
         if (arraySize == 0)
         if (arraySize == 0)
             arraySize = mapToGlArraySize(*terminalType);
             arraySize = mapToGlArraySize(*terminalType);
 
 
-        TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
+        TReflection::TMapIndexToReflection& variables = reflection.GetVariableMapForStorage(baseStorage);
+
+        TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
+        if (it == reflection.nameToIndex.end()) {
+            int uniformIndex = (int)variables.size();
+            reflection.nameToIndex[name.c_str()] = uniformIndex;
+            variables.push_back(TObjectReflection(name.c_str(), *terminalType, offset, mapToGlType(*terminalType),
+                                                  arraySize, blockIndex));
+            if (terminalType->isArray()) {
+                variables.back().arrayStride = getArrayStride(baseType, *terminalType);
+                if (topLevelArrayStride == 0)
+                    topLevelArrayStride = variables.back().arrayStride;
+            }
+
+            if ((reflection.options & EShReflectionSeparateBuffers) && terminalType->getBasicType() == EbtAtomicUint)
+                reflection.atomicCounterUniformIndices.push_back(uniformIndex);
+
+            variables.back().topLevelArrayStride = topLevelArrayStride;
+            
+            if ((reflection.options & EShReflectionAllBlockVariables) && active) {
+                EShLanguageMask& stages = variables.back().stages;
+                stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+            }
+        } else {
+            if (arraySize > 1) {
+                int& reflectedArraySize = variables[it->second].size;
+                reflectedArraySize = std::max(arraySize, reflectedArraySize);
+            }
+
+            if ((reflection.options & EShReflectionAllBlockVariables) && active) {
+              EShLanguageMask& stages = variables[it->second].stages;
+              stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+            }
+        }
+    }
+    
+    // similar to blowUpActiveAggregate, but with simpler rules and no dereferences to follow.
+    void blowUpIOAggregate(bool input, const TString &baseName, const TType &type)
+    {
+        TString name = baseName;
+
+        // if the type is still too coarse a granularity, this is still an aggregate to expand, expand it...
+        if (! isReflectionGranularity(type)) {
+            if (type.isArray()) {
+                // Visit all the indices of this array, and for each one,
+                // fully explode the remaining aggregate to dereference
+                for (int i = 0; i < std::max(type.getOuterArraySize(), 1); ++i) {
+                    TString newBaseName = name;
+                    newBaseName.append(TString("[") + String(i) + "]");
+                    TType derefType(type, 0);
+
+                    blowUpIOAggregate(input, newBaseName, derefType);
+                }
+            } else {
+                // Visit all members of this aggregate, and for each one,
+                // fully explode the remaining aggregate to dereference
+                const TTypeList& typeList = *type.getStruct();
+
+                for (int i = 0; i < (int)typeList.size(); ++i) {
+                    TString newBaseName = name;
+                    if (newBaseName.size() > 0)
+                        newBaseName.append(".");
+                    newBaseName.append(typeList[i].type->getFieldName());
+                    TType derefType(type, i);
+
+                    blowUpIOAggregate(input, newBaseName, derefType);
+                }
+            }
+
+            // it was all completed in the recursive calls above
+            return;
+        }
+
+        if ((reflection.options & EShReflectionBasicArraySuffix) && type.isArray()) {
+            name.append(TString("[0]"));
+        }
+
+        TReflection::TMapIndexToReflection &ioItems =
+            input ? reflection.indexToPipeInput : reflection.indexToPipeOutput;
+
+        std::string namespacedName = input ? "in " : "out ";
+        namespacedName += name.c_str();
+
+        TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(namespacedName);
         if (it == reflection.nameToIndex.end()) {
         if (it == reflection.nameToIndex.end()) {
-            reflection.nameToIndex[name] = (int)reflection.indexToUniform.size();
-            reflection.indexToUniform.push_back(TObjectReflection(name, *terminalType, offset,
-                                                                  mapToGlType(*terminalType),
-                                                                  arraySize, blockIndex));
-        } else if (arraySize > 1) {
-            int& reflectedArraySize = reflection.indexToUniform[it->second].size;
-            reflectedArraySize = std::max(arraySize, reflectedArraySize);
+            reflection.nameToIndex[namespacedName] = (int)ioItems.size();
+            ioItems.push_back(
+                TObjectReflection(name.c_str(), type, 0, mapToGlType(type), mapToGlArraySize(type), 0));
+
+            EShLanguageMask& stages = ioItems.back().stages;
+            stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+        } else {
+            EShLanguageMask& stages = ioItems[it->second].stages;
+            stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
         }
         }
     }
     }
 
 
@@ -303,6 +525,10 @@ public:
             anonymous = IsAnonymous(base->getName());
             anonymous = IsAnonymous(base->getName());
 
 
             const TString& blockName = base->getType().getTypeName();
             const TString& blockName = base->getType().getTypeName();
+            TString baseName;
+            
+            if (! anonymous)
+                baseName = blockName;
 
 
             if (base->getType().isArray()) {
             if (base->getType().isArray()) {
                 TType derefType(base->getType(), 0);
                 TType derefType(base->getType(), 0);
@@ -310,9 +536,57 @@ public:
                 assert(! anonymous);
                 assert(! anonymous);
                 for (int e = 0; e < base->getType().getCumulativeArraySize(); ++e)
                 for (int e = 0; e < base->getType().getCumulativeArraySize(); ++e)
                     blockIndex = addBlockName(blockName + "[" + String(e) + "]", derefType,
                     blockIndex = addBlockName(blockName + "[" + String(e) + "]", derefType,
-                                              getBlockSize(base->getType()));
+                                              intermediate.getBlockSize(base->getType()));
+                baseName.append(TString("[0]"));
             } else
             } else
-                blockIndex = addBlockName(blockName, base->getType(), getBlockSize(base->getType()));
+                blockIndex = addBlockName(blockName, base->getType(), intermediate.getBlockSize(base->getType()));
+
+            if (reflection.options & EShReflectionAllBlockVariables) {
+                // Use a degenerate (empty) set of dereferences to immediately put as at the end of
+                // the dereference change expected by blowUpActiveAggregate.
+                TList<TIntermBinary*> derefs;
+
+                // because we don't have any derefs, the first thing blowUpActiveAggregate will do is iterate over each
+                // member in the struct definition. This will lose any information about whether the parent was a buffer
+                // block. So if we're using strict array rules which don't expand the first child of a buffer block we
+                // instead iterate over the children here.
+                const bool strictArraySuffix = (reflection.options & EShReflectionStrictArraySuffix);
+                bool blockParent = (base->getType().getBasicType() == EbtBlock && base->getQualifier().storage == EvqBuffer);
+
+                if (strictArraySuffix && blockParent) {
+                    const TTypeList& typeList = *base->getType().getStruct();
+
+                    TVector<int> memberOffsets;
+
+                    memberOffsets.resize(typeList.size());
+                    getOffsets(base->getType(), memberOffsets);
+
+                    for (int i = 0; i < (int)typeList.size(); ++i) {
+                        TType derefType(base->getType(), i);
+                        TString name = baseName;
+                        if (name.size() > 0)
+                            name.append(".");
+                        name.append(typeList[i].type->getFieldName());
+
+                        // if this member is an array, store the top-level array stride but start the explosion from
+                        // the inner struct type.
+                        if (derefType.isArray() && derefType.isStruct()) {
+                            name.append("[0]");
+                            blowUpActiveAggregate(TType(derefType, 0), name, derefs, derefs.end(), memberOffsets[i],
+                                                  blockIndex, 0, getArrayStride(base->getType(), derefType),
+                                                  base->getQualifier().storage, false);
+                        } else {
+                            blowUpActiveAggregate(derefType, name, derefs, derefs.end(), memberOffsets[i], blockIndex,
+                                                  0, 0, base->getQualifier().storage, false);
+                        }
+                    }
+                } else {
+                    // otherwise - if we're not using strict array suffix rules, or this isn't a block so we are
+                    // expanding root arrays anyway, just start the iteration from the base block type.
+                    blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.end(), 0, blockIndex, 0, 0,
+                                          base->getQualifier().storage, false);
+                }
+            }
         }
         }
 
 
         // Process the dereference chain, backward, accumulating the pieces for later forward traversal.
         // Process the dereference chain, backward, accumulating the pieces for later forward traversal.
@@ -342,27 +616,39 @@ public:
             else
             else
                 baseName = base->getName();
                 baseName = base->getName();
         }
         }
-        blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize);
+        blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize, 0,
+                              base->getQualifier().storage, true);
     }
     }
 
 
     int addBlockName(const TString& name, const TType& type, int size)
     int addBlockName(const TString& name, const TType& type, int size)
     {
     {
+        TReflection::TMapIndexToReflection& blocks = reflection.GetBlockMapForStorage(type.getQualifier().storage);
+
         int blockIndex;
         int blockIndex;
-        TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
-        if (reflection.nameToIndex.find(name) == reflection.nameToIndex.end()) {
-            blockIndex = (int)reflection.indexToUniformBlock.size();
-            reflection.nameToIndex[name] = blockIndex;
-            reflection.indexToUniformBlock.push_back(TObjectReflection(name, type, -1, -1, size, -1));
-        } else
+        TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
+        if (reflection.nameToIndex.find(name.c_str()) == reflection.nameToIndex.end()) {
+            blockIndex = (int)blocks.size();
+            reflection.nameToIndex[name.c_str()] = blockIndex;
+            blocks.push_back(TObjectReflection(name.c_str(), type, -1, -1, size, -1));
+
+            blocks.back().numMembers = countAggregateMembers(type);
+
+            EShLanguageMask& stages = blocks.back().stages;
+            stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+        } else {
             blockIndex = it->second;
             blockIndex = it->second;
 
 
+            EShLanguageMask& stages = blocks[blockIndex].stages;
+            stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
+        }
+
         return blockIndex;
         return blockIndex;
     }
     }
 
 
     // Are we at a level in a dereference chain at which individual active uniform queries are made?
     // Are we at a level in a dereference chain at which individual active uniform queries are made?
     bool isReflectionGranularity(const TType& type)
     bool isReflectionGranularity(const TType& type)
     {
     {
-        return type.getBasicType() != EbtBlock && type.getBasicType() != EbtStruct;
+        return type.getBasicType() != EbtBlock && type.getBasicType() != EbtStruct && !type.isArrayOfArrays();
     }
     }
 
 
     // For a binary operation indexing into an aggregate, chase down the base of the aggregate.
     // For a binary operation indexing into an aggregate, chase down the base of the aggregate.
@@ -746,8 +1032,47 @@ void TReflectionTraverser::visitSymbol(TIntermSymbol* base)
     if (base->getQualifier().storage == EvqUniform)
     if (base->getQualifier().storage == EvqUniform)
         addUniform(*base);
         addUniform(*base);
 
 
-    if (intermediate.getStage() == EShLangVertex && base->getQualifier().isPipeInput())
-        addAttribute(*base);
+    if ((intermediate.getStage() == reflection.firstStage && base->getQualifier().isPipeInput()) ||
+        (intermediate.getStage() == reflection.lastStage && base->getQualifier().isPipeOutput()))
+        addPipeIOVariable(*base);
+}
+
+//
+// Implement TObjectReflection methods.
+//
+
+TObjectReflection::TObjectReflection(const std::string &pName, const TType &pType, int pOffset, int pGLDefineType,
+                                     int pSize, int pIndex)
+    : name(pName), offset(pOffset), glDefineType(pGLDefineType), size(pSize), index(pIndex), counterIndex(-1),
+      numMembers(-1), arrayStride(0), topLevelArrayStride(0), stages(EShLanguageMask(0)), type(pType.clone())
+{
+}
+
+int TObjectReflection::getBinding() const
+{
+    if (type == nullptr || !type->getQualifier().hasBinding())
+        return -1;
+    return type->getQualifier().layoutBinding;
+}
+
+void TObjectReflection::dump() const
+{
+    printf("%s: offset %d, type %x, size %d, index %d, binding %d, stages %d", name.c_str(), offset, glDefineType, size,
+           index, getBinding(), stages);
+
+    if (counterIndex != -1)
+        printf(", counter %d", counterIndex);
+
+    if (numMembers != -1)
+        printf(", numMembers %d", numMembers);
+
+    if (arrayStride != 0)
+        printf(", arrayStride %d", arrayStride);
+
+    if (topLevelArrayStride != 0)
+        printf(", topLevelArrayStride %d", topLevelArrayStride);
+
+    printf("\n");
 }
 }
 
 
 //
 //
@@ -770,7 +1095,7 @@ void TReflection::buildCounterIndices(const TIntermediate& intermediate)
 {
 {
     // search for ones that have counters
     // search for ones that have counters
     for (int i = 0; i < int(indexToUniformBlock.size()); ++i) {
     for (int i = 0; i < int(indexToUniformBlock.size()); ++i) {
-        const TString counterName(intermediate.addCounterBufferName(indexToUniformBlock[i].name));
+        const TString counterName(intermediate.addCounterBufferName(indexToUniformBlock[i].name).c_str());
         const int index = getIndex(counterName);
         const int index = getIndex(counterName);
 
 
         if (index >= 0)
         if (index >= 0)
@@ -781,9 +1106,17 @@ void TReflection::buildCounterIndices(const TIntermediate& intermediate)
 // build Shader Stages mask for all uniforms
 // build Shader Stages mask for all uniforms
 void TReflection::buildUniformStageMask(const TIntermediate& intermediate)
 void TReflection::buildUniformStageMask(const TIntermediate& intermediate)
 {
 {
+    if (options & EShReflectionAllBlockVariables)
+        return;
+
     for (int i = 0; i < int(indexToUniform.size()); ++i) {
     for (int i = 0; i < int(indexToUniform.size()); ++i) {
         indexToUniform[i].stages = static_cast<EShLanguageMask>(indexToUniform[i].stages | 1 << intermediate.getStage());
         indexToUniform[i].stages = static_cast<EShLanguageMask>(indexToUniform[i].stages | 1 << intermediate.getStage());
     }
     }
+
+    for (int i = 0; i < int(indexToBufferVariable.size()); ++i) {
+        indexToBufferVariable[i].stages =
+            static_cast<EShLanguageMask>(indexToBufferVariable[i].stages | 1 << intermediate.getStage());
+    }
 }
 }
 
 
 // Merge live symbols from 'intermediate' into the existing reflection database.
 // Merge live symbols from 'intermediate' into the existing reflection database.
@@ -828,9 +1161,24 @@ void TReflection::dump()
         indexToUniformBlock[i].dump();
         indexToUniformBlock[i].dump();
     printf("\n");
     printf("\n");
 
 
-    printf("Vertex attribute reflection:\n");
-    for (size_t i = 0; i < indexToAttribute.size(); ++i)
-        indexToAttribute[i].dump();
+    printf("Buffer variable reflection:\n");
+    for (size_t i = 0; i < indexToBufferVariable.size(); ++i)
+      indexToBufferVariable[i].dump();
+    printf("\n");
+
+    printf("Buffer block reflection:\n");
+    for (size_t i = 0; i < indexToBufferBlock.size(); ++i)
+      indexToBufferBlock[i].dump();
+    printf("\n");
+
+    printf("Pipeline input reflection:\n");
+    for (size_t i = 0; i < indexToPipeInput.size(); ++i)
+        indexToPipeInput[i].dump();
+    printf("\n");
+
+    printf("Pipeline output reflection:\n");
+    for (size_t i = 0; i < indexToPipeOutput.size(); ++i)
+        indexToPipeOutput[i].dump();
     printf("\n");
     printf("\n");
 
 
     if (getLocalSize(0) > 1) {
     if (getLocalSize(0) > 1) {

+ 73 - 49
src/libraries/glslang/glslang/MachineIndependent/reflection.h

@@ -52,50 +52,11 @@ class TIntermediate;
 class TIntermAggregate;
 class TIntermAggregate;
 class TReflectionTraverser;
 class TReflectionTraverser;
 
 
-// Data needed for just a single object at the granularity exchanged by the reflection API
-class TObjectReflection {
-public:
-    TObjectReflection(const TString& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex) :
-        name(pName), offset(pOffset),
-        glDefineType(pGLDefineType), size(pSize), index(pIndex), counterIndex(-1), stages(EShLanguageMask(0)), type(pType.clone()) { }
-
-    const TType* getType() const { return type; }
-    int getBinding() const
-    {
-        if (type == nullptr || !type->getQualifier().hasBinding())
-            return -1;
-        return type->getQualifier().layoutBinding;
-    }
-    void dump() const
-    {
-        printf("%s: offset %d, type %x, size %d, index %d, binding %d, stages %d",
-               name.c_str(), offset, glDefineType, size, index, getBinding(), stages );
-
-        if (counterIndex != -1)
-            printf(", counter %d", counterIndex);
-
-        printf("\n");
-    }
-    static TObjectReflection badReflection() { return TObjectReflection(); }
-
-    TString name;
-    int offset;
-    int glDefineType;
-    int size;         // data size in bytes for a block, array size for a (non-block) object that's an array
-    int index;
-    int counterIndex;
-    EShLanguageMask stages;
-
-protected:
-    TObjectReflection() : offset(-1), glDefineType(-1), size(-1), index(-1), type(nullptr) { }
-
-    const TType* type;
-};
-
 // The full reflection database
 // The full reflection database
 class TReflection {
 class TReflection {
 public:
 public:
-    TReflection() : badReflection(TObjectReflection::badReflection())
+    TReflection(EShReflectionOptions opts, EShLanguage first, EShLanguage last)
+        : options(opts), firstStage(first), lastStage(last), badReflection(TObjectReflection::badReflection())
     { 
     { 
         for (int dim=0; dim<3; ++dim)
         for (int dim=0; dim<3; ++dim)
             localSize[dim] = 0;
             localSize[dim] = 0;
@@ -126,17 +87,57 @@ public:
             return badReflection;
             return badReflection;
     }
     }
 
 
-    // for mapping an attribute index to the attribute's description
-    int getNumAttributes() { return (int)indexToAttribute.size(); }
-    const TObjectReflection& getAttribute(int i) const
+    // for mapping an pipeline input index to the input's description
+    int getNumPipeInputs() { return (int)indexToPipeInput.size(); }
+    const TObjectReflection& getPipeInput(int i) const
+    {
+        if (i >= 0 && i < (int)indexToPipeInput.size())
+            return indexToPipeInput[i];
+        else
+            return badReflection;
+    }
+
+    // for mapping an pipeline output index to the output's description
+    int getNumPipeOutputs() { return (int)indexToPipeOutput.size(); }
+    const TObjectReflection& getPipeOutput(int i) const
     {
     {
-        if (i >= 0 && i < (int)indexToAttribute.size())
-            return indexToAttribute[i];
+        if (i >= 0 && i < (int)indexToPipeOutput.size())
+            return indexToPipeOutput[i];
         else
         else
             return badReflection;
             return badReflection;
     }
     }
 
 
-    // for mapping any name to its index (block names, uniform names and attribute names)
+    // for mapping from an atomic counter to the uniform index
+    int getNumAtomicCounters() const { return (int)atomicCounterUniformIndices.size(); }
+    const TObjectReflection& getAtomicCounter(int i) const
+    {
+        if (i >= 0 && i < (int)atomicCounterUniformIndices.size())
+            return getUniform(atomicCounterUniformIndices[i]);
+        else
+            return badReflection;
+    }
+
+    // for mapping a buffer variable index to a buffer variable object's description
+    int getNumBufferVariables() { return (int)indexToBufferVariable.size(); }
+    const TObjectReflection& getBufferVariable(int i) const
+    {
+        if (i >= 0 && i < (int)indexToBufferVariable.size())
+            return indexToBufferVariable[i];
+        else
+            return badReflection;
+    }
+    
+    // for mapping a storage block index to the storage block's description
+    int getNumStorageBuffers() const { return (int)indexToBufferBlock.size(); }
+    const TObjectReflection&  getStorageBufferBlock(int i) const
+    {
+        if (i >= 0 && i < (int)indexToBufferBlock.size())
+            return indexToBufferBlock[i];
+        else
+            return badReflection;
+    }
+
+    // for mapping any name to its index (block names, uniform names and input/output names)
     int getIndex(const char* name) const
     int getIndex(const char* name) const
     {
     {
         TNameToIndex::const_iterator it = nameToIndex.find(name);
         TNameToIndex::const_iterator it = nameToIndex.find(name);
@@ -162,14 +163,37 @@ protected:
     void buildAttributeReflection(EShLanguage, const TIntermediate&);
     void buildAttributeReflection(EShLanguage, const TIntermediate&);
 
 
     // Need a TString hash: typedef std::unordered_map<TString, int> TNameToIndex;
     // Need a TString hash: typedef std::unordered_map<TString, int> TNameToIndex;
-    typedef std::map<TString, int> TNameToIndex;
+    typedef std::map<std::string, int> TNameToIndex;
     typedef std::vector<TObjectReflection> TMapIndexToReflection;
     typedef std::vector<TObjectReflection> TMapIndexToReflection;
+    typedef std::vector<int> TIndices;
+
+    TMapIndexToReflection& GetBlockMapForStorage(TStorageQualifier storage)
+    {
+        if ((options & EShReflectionSeparateBuffers) && storage == EvqBuffer)
+            return indexToBufferBlock;
+        return indexToUniformBlock;
+    }
+    TMapIndexToReflection& GetVariableMapForStorage(TStorageQualifier storage)
+    {
+        if ((options & EShReflectionSeparateBuffers) && storage == EvqBuffer)
+            return indexToBufferVariable;
+        return indexToUniform;
+    }
+
+    EShReflectionOptions options;
+
+    EShLanguage firstStage;
+    EShLanguage lastStage;
 
 
     TObjectReflection badReflection; // return for queries of -1 or generally out of range; has expected descriptions with in it for this
     TObjectReflection badReflection; // return for queries of -1 or generally out of range; has expected descriptions with in it for this
     TNameToIndex nameToIndex;        // maps names to indexes; can hold all types of data: uniform/buffer and which function names have been processed
     TNameToIndex nameToIndex;        // maps names to indexes; can hold all types of data: uniform/buffer and which function names have been processed
     TMapIndexToReflection indexToUniform;
     TMapIndexToReflection indexToUniform;
     TMapIndexToReflection indexToUniformBlock;
     TMapIndexToReflection indexToUniformBlock;
-    TMapIndexToReflection indexToAttribute;
+    TMapIndexToReflection indexToBufferVariable;
+    TMapIndexToReflection indexToBufferBlock;
+    TMapIndexToReflection indexToPipeInput;
+    TMapIndexToReflection indexToPipeOutput;
+    TIndices atomicCounterUniformIndices;
 
 
     unsigned int localSize[3];
     unsigned int localSize[3];
 };
 };

+ 4 - 1
src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp

@@ -45,7 +45,10 @@
 #include <stdint.h>
 #include <stdint.h>
 #include <cstdio>
 #include <cstdio>
 #include <sys/time.h>
 #include <sys/time.h>
+
+#if !defined(__Fuchsia__)
 #include <sys/resource.h>
 #include <sys/resource.h>
+#endif
 
 
 namespace glslang {
 namespace glslang {
 
 
@@ -70,7 +73,7 @@ static void DetachThreadLinux(void *)
 //
 //
 void OS_CleanupThreadData(void)
 void OS_CleanupThreadData(void)
 {
 {
-#ifdef __ANDROID__
+#if defined(__ANDROID__) || defined(__Fuchsia__)
     DetachThreadLinux(NULL);
     DetachThreadLinux(NULL);
 #else
 #else
     int old_cancel_state, old_cancel_type;
     int old_cancel_state, old_cancel_type;

+ 133 - 26
src/libraries/glslang/glslang/Public/ShaderLang.h

@@ -53,9 +53,6 @@
 #define SH_IMPORT_EXPORT
 #define SH_IMPORT_EXPORT
 #else
 #else
 #define SH_IMPORT_EXPORT
 #define SH_IMPORT_EXPORT
-#ifndef __fastcall
-#define __fastcall
-#endif
 #define C_DECL
 #define C_DECL
 #endif
 #endif
 
 
@@ -71,7 +68,7 @@
 // This should always increase, as some paths to do not consume
 // This should always increase, as some paths to do not consume
 // a more major number.
 // a more major number.
 // It should increment by one when new functionality is added.
 // It should increment by one when new functionality is added.
-#define GLSLANG_MINOR_VERSION 11
+#define GLSLANG_MINOR_VERSION 12
 
 
 //
 //
 // Call before doing any other compiler/linker operations.
 // Call before doing any other compiler/linker operations.
@@ -83,7 +80,7 @@ SH_IMPORT_EXPORT int ShInitialize();
 //
 //
 // Call this at process shutdown to clean up memory.
 // Call this at process shutdown to clean up memory.
 //
 //
-SH_IMPORT_EXPORT int __fastcall ShFinalize();
+SH_IMPORT_EXPORT int ShFinalize();
 
 
 //
 //
 // Types of languages the compiler can consume.
 // Types of languages the compiler can consume.
@@ -237,8 +234,22 @@ enum EShMessages {
     EShMsgHlslEnable16BitTypes  = (1 << 11), // enable use of 16-bit types in SPIR-V for HLSL
     EShMsgHlslEnable16BitTypes  = (1 << 11), // enable use of 16-bit types in SPIR-V for HLSL
     EShMsgHlslLegalization  = (1 << 12), // enable HLSL Legalization messages
     EShMsgHlslLegalization  = (1 << 12), // enable HLSL Legalization messages
     EShMsgHlslDX9Compatible = (1 << 13), // enable HLSL DX9 compatible mode (right now only for samplers)
     EShMsgHlslDX9Compatible = (1 << 13), // enable HLSL DX9 compatible mode (right now only for samplers)
+    EShMsgBuiltinSymbolTable = (1 << 14), // print the builtin symbol table
 };
 };
 
 
+//
+// Options for building reflection
+//
+typedef enum {
+    EShReflectionDefault           = 0,        // default is original behaviour before options were added
+    EShReflectionStrictArraySuffix = (1 << 0), // reflection will follow stricter rules for array-of-structs suffixes
+    EShReflectionBasicArraySuffix  = (1 << 1), // arrays of basic types will be appended with [0] as in GL reflection
+    EShReflectionIntermediateIO    = (1 << 2), // reflect inputs and outputs to program, even with no vertex shader
+    EShReflectionSeparateBuffers   = (1 << 3), // buffer variables and buffer blocks are reflected separately
+    EShReflectionAllBlockVariables = (1 << 4), // reflect all variables in blocks, even if they are inactive
+    EShReflectionUnwrapIOBlocks    = (1 << 5), // unwrap input/output blocks the same as with uniform blocks
+} EShReflectionOptions;
+
 //
 //
 // Build a table for bindings.  This can be used for locating
 // Build a table for bindings.  This can be used for locating
 // attributes, uniforms, globals, etc., as needed.
 // attributes, uniforms, globals, etc., as needed.
@@ -599,6 +610,41 @@ private:
     TShader& operator=(TShader&);
     TShader& operator=(TShader&);
 };
 };
 
 
+//
+// A reflection database and its interface, consistent with the OpenGL API reflection queries.
+//
+
+// Data needed for just a single object at the granularity exchanged by the reflection API
+class TObjectReflection {
+public:
+    TObjectReflection(const std::string& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex);
+
+    const TType* getType() const { return type; }
+    int getBinding() const;
+    void dump() const;
+    static TObjectReflection badReflection() { return TObjectReflection(); }
+
+    std::string name;
+    int offset;
+    int glDefineType;
+    int size;                   // data size in bytes for a block, array size for a (non-block) object that's an array
+    int index;
+    int counterIndex;
+    int numMembers;
+    int arrayStride;            // stride of an array variable
+    int topLevelArrayStride;    // stride of the top-level variable in a storage buffer member
+    EShLanguageMask stages;
+
+protected:
+    TObjectReflection()
+        : offset(-1), glDefineType(-1), size(-1), index(-1), counterIndex(-1), numMembers(-1), arrayStride(0),
+          topLevelArrayStride(0), stages(EShLanguageMask(0)), type(nullptr)
+    {
+    }
+
+    const TType* type;
+};
+
 class TReflection;
 class TReflection;
 class TIoMapper;
 class TIoMapper;
 
 
@@ -688,28 +734,89 @@ public:
     TIntermediate* getIntermediate(EShLanguage stage) const { return intermediate[stage]; }
     TIntermediate* getIntermediate(EShLanguage stage) const { return intermediate[stage]; }
 
 
     // Reflection Interface
     // Reflection Interface
-    bool buildReflection();                          // call first, to do liveness analysis, index mapping, etc.; returns false on failure
-    int getNumLiveUniformVariables() const;                // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)
-    int getNumLiveUniformBlocks() const;                   // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS)
-    const char* getUniformName(int index) const;           // can be used for "name" part of glGetActiveUniform()
-    const char* getUniformBlockName(int blockIndex) const; // can be used for glGetActiveUniformBlockName()
-    int getUniformBlockSize(int blockIndex) const;         // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
-    int getUniformIndex(const char* name) const;           // can be used for glGetUniformIndices()
-    int getUniformBinding(int index) const;                // returns the binding number
-    EShLanguageMask getUniformStages(int index) const;     // returns Shaders Stages where a Uniform is present
-    int getUniformBlockBinding(int index) const;           // returns the block binding number
-    int getUniformBlockIndex(int index) const;             // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
-    int getUniformBlockCounterIndex(int index) const;      // returns block index of associated counter.
-    int getUniformType(int index) const;                   // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)
-    int getUniformBufferOffset(int index) const;           // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
-    int getUniformArraySize(int index) const;              // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
-    int getNumLiveAttributes() const;                      // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES)
+
+    // call first, to do liveness analysis, index mapping, etc.; returns false on failure
+    bool buildReflection(int opts = EShReflectionDefault);    
+
     unsigned getLocalSize(int dim) const;                  // return dim'th local size
     unsigned getLocalSize(int dim) const;                  // return dim'th local size
-    const char *getAttributeName(int index) const;         // can be used for glGetActiveAttrib()
-    int getAttributeType(int index) const;                 // can be used for glGetActiveAttrib()
-    const TType* getUniformTType(int index) const;         // returns a TType*
-    const TType* getUniformBlockTType(int index) const;    // returns a TType*
-    const TType* getAttributeTType(int index) const;       // returns a TType*
+    int getReflectionIndex(const char *name) const;
+
+    int getNumUniformVariables() const;
+    const TObjectReflection& getUniform(int index) const;
+    int getNumUniformBlocks() const;
+    const TObjectReflection& getUniformBlock(int index) const;
+    int getNumPipeInputs() const;
+    const TObjectReflection& getPipeInput(int index) const;
+    int getNumPipeOutputs() const;
+    const TObjectReflection& getPipeOutput(int index) const;
+    int getNumBufferVariables() const;
+    const TObjectReflection& getBufferVariable(int index) const;
+    int getNumBufferBlocks() const;
+    const TObjectReflection& getBufferBlock(int index) const;
+    int getNumAtomicCounters() const;
+    const TObjectReflection& getAtomicCounter(int index) const;
+
+    // Legacy Reflection Interface - expressed in terms of above interface
+
+    // can be used for glGetProgramiv(GL_ACTIVE_UNIFORMS)
+    int getNumLiveUniformVariables() const             { return getNumUniformVariables(); }
+
+    // can be used for glGetProgramiv(GL_ACTIVE_UNIFORM_BLOCKS)
+    int getNumLiveUniformBlocks() const                { return getNumUniformBlocks(); }
+
+    // can be used for glGetProgramiv(GL_ACTIVE_ATTRIBUTES)
+    int getNumLiveAttributes() const                   { return getNumPipeInputs(); }
+
+    // can be used for glGetUniformIndices()
+    int getUniformIndex(const char *name) const        { return getReflectionIndex(name); }
+
+    // can be used for "name" part of glGetActiveUniform()
+    const char *getUniformName(int index) const        { return getUniform(index).name.c_str(); }
+
+    // returns the binding number
+    int getUniformBinding(int index) const             { return getUniform(index).getBinding(); }
+
+    // returns Shaders Stages where a Uniform is present
+    EShLanguageMask getUniformStages(int index) const  { return getUniform(index).stages; }
+
+    // can be used for glGetActiveUniformsiv(GL_UNIFORM_BLOCK_INDEX)
+    int getUniformBlockIndex(int index) const          { return getUniform(index).index; }
+
+    // can be used for glGetActiveUniformsiv(GL_UNIFORM_TYPE)
+    int getUniformType(int index) const                { return getUniform(index).glDefineType; }
+
+    // can be used for glGetActiveUniformsiv(GL_UNIFORM_OFFSET)
+    int getUniformBufferOffset(int index) const        { return getUniform(index).offset; }
+
+    // can be used for glGetActiveUniformsiv(GL_UNIFORM_SIZE)
+    int getUniformArraySize(int index) const           { return getUniform(index).size; }
+
+    // returns a TType*
+    const TType *getUniformTType(int index) const      { return getUniform(index).getType(); }
+
+    // can be used for glGetActiveUniformBlockName()
+    const char *getUniformBlockName(int index) const   { return getUniformBlock(index).name.c_str(); }
+
+    // can be used for glGetActiveUniformBlockiv(UNIFORM_BLOCK_DATA_SIZE)
+    int getUniformBlockSize(int index) const           { return getUniformBlock(index).size; }
+
+    // returns the block binding number
+    int getUniformBlockBinding(int index) const        { return getUniformBlock(index).getBinding(); }
+
+    // returns block index of associated counter.
+    int getUniformBlockCounterIndex(int index) const   { return getUniformBlock(index).counterIndex; }
+
+    // returns a TType*
+    const TType *getUniformBlockTType(int index) const { return getUniformBlock(index).getType(); }
+
+    // can be used for glGetActiveAttrib()
+    const char *getAttributeName(int index) const      { return getPipeInput(index).name.c_str(); }
+
+    // can be used for glGetActiveAttrib()
+    int getAttributeType(int index) const              { return getPipeInput(index).glDefineType; }
+
+    // returns a TType*
+    const TType *getAttributeTType(int index) const    { return getPipeInput(index).getType(); }
 
 
     void dumpReflection();
     void dumpReflection();
 
 

Some files were not shown because too many files changed in this diff