Бранимир Караџић 7 лет назад
Родитель
Сommit
eae8dd2d23

+ 32 - 1
3rdparty/glslang/BUILD.gn

@@ -141,13 +141,44 @@ source_set("glslang_sources") {
 
   if (is_clang) {
     cflags_cc = [
-      "-Wno-implicit-fallthrough",
       "-Wno-ignored-qualifiers",
+      "-Wno-implicit-fallthrough",
+      "-Wno-inconsistent-missing-override",
+      "-Wno-sign-compare",
       "-Wno-unused-variable",
     ]
   }
+  if (is_win && !is_clang) {
+    cflags = [
+      "/wd4018", # signed/unsigned mismatch
+    ]
+  }
 
   deps = [
     "${spirv_tools_dir}:spvtools_opt",
   ]
 }
+
+source_set("glslang_default_resource_limits_sources") {
+  sources = [
+    "StandAlone/ResourceLimits.cpp",
+    "StandAlone/ResourceLimits.h",
+  ]
+  deps = [ ":glslang_sources" ]
+  public_configs = [ ":glslang_public" ]
+}
+
+source_set("glslang_validator") {
+  sources = [
+    "StandAlone/DirStackFileIncluder.h",
+    "StandAlone/StandAlone.cpp",
+  ]
+  if (!is_win) {
+    cflags = [ "-Woverflow" ]
+  }
+  defines = [ "ENABLE_OPT=0" ]
+  deps = [
+    ":glslang_default_resource_limits_sources",
+    ":glslang_sources",
+  ]
+}

+ 1 - 1
3rdparty/glslang/CMakeLists.txt

@@ -73,7 +73,7 @@ if(ENABLE_HLSL)
 endif(ENABLE_HLSL)
 
 if(WIN32)
-    set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Adds a postfix for debug-built libraries.")
+    set(CMAKE_DEBUG_POSTFIX "d")
     if(MSVC)
         include(ChooseMSVCCRT.cmake)
     endif(MSVC)

+ 1 - 3
3rdparty/glslang/Test/baseResults/spv.bufferhandle13.frag.out

@@ -4,13 +4,11 @@ spv.bufferhandle13.frag
 // Id's are bound by 58
 
                               Capability Shader
-                              Capability CapabilityVulkanMemoryModelKHR
                               Capability CapabilityPhysicalStorageBufferAddressesEXT
                               Extension  "SPV_EXT_physical_storage_buffer"
                               Extension  "SPV_KHR_storage_buffer_storage_class"
-                              Extension  "SPV_KHR_vulkan_memory_model"
                1:             ExtInstImport  "GLSL.std.450"
-                              MemoryModel PhysicalStorageBuffer64EXT VulkanKHR
+                              MemoryModel PhysicalStorageBuffer64EXT GLSL450
                               EntryPoint Fragment 4  "main"
                               ExecutionMode 4 OriginUpperLeft
                               Source GLSL 450

+ 5 - 0
3rdparty/glslang/glslang/Include/Types.h

@@ -537,6 +537,11 @@ public:
     {
         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
     {

+ 58 - 20
3rdparty/glslang/glslang/MachineIndependent/Initialize.cpp

@@ -7737,11 +7737,12 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf
 static void SpecialQualifier(const char* name, TStorageQualifier qualifier, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
 {
     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;
 }
 
 //
@@ -7757,7 +7758,7 @@ static void SpecialQualifier(const char* name, TStorageQualifier qualifier, TBui
 static void BuiltInVariable(const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
 {
     TSymbol* symbol = symbolTable.find(name);
-    if (! symbol)
+    if (symbol == nullptr)
         return;
 
     TQualifier& symQualifier = symbol->getWritableType().getQualifier();
@@ -7774,7 +7775,7 @@ static void BuiltInVariable(const char* name, TBuiltInVariable builtIn, TSymbolT
 static void BuiltInVariable(const char* blockName, const char* name, TBuiltInVariable builtIn, TSymbolTable& symbolTable)
 {
     TSymbol* symbol = symbolTable.find(blockName);
-    if (! symbol)
+    if (symbol == nullptr)
         return;
 
     TTypeList& structure = *symbol->getWritableType().getWritableStruct();
@@ -8030,9 +8031,18 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         BuiltInVariable("gl_ViewportMaskPerViewNV",     EbvViewportMaskPerViewNV,   symbolTable);
 
         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_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_SecondaryPositionNV",     EbvSecondaryPositionNV,     symbolTable);
         BuiltInVariable("gl_out", "gl_SecondaryViewportMaskNV", EbvSecondaryViewportMaskNV, symbolTable);
@@ -8076,15 +8086,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.
         // (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) ||
             (profile == EEsProfile && version >= 310)) {
@@ -8683,25 +8694,44 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         break;
     case EShLangMeshNV:
         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_PointSize",    EbvPointSize,    symbolTable);
             BuiltInVariable("gl_MeshVerticesNV", "gl_ClipDistance", EbvClipDistance, 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_ClipDistancePerViewNV", EbvClipDistancePerViewNV, 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_Layer",         EbvLayer,          symbolTable);
             BuiltInVariable("gl_MeshPrimitivesNV", "gl_ViewportIndex", EbvViewportIndex,  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_ViewportMaskPerViewNV", EbvViewportMaskPerViewNV, symbolTable);
 
+            // other builtins
             symbolTable.setVariableExtensions("gl_PrimitiveCountNV",     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);
@@ -8722,11 +8752,13 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
             BuiltInVariable("gl_GlobalInvocationID",   EbvGlobalInvocationId,   symbolTable);
             BuiltInVariable("gl_LocalInvocationIndex", EbvLocalInvocationIndex, symbolTable);
 
+            // builtin constants
             symbolTable.setVariableExtensions("gl_MaxMeshOutputVerticesNV",   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_MaxMeshViewCountNV",        1, &E_GL_NV_mesh_shader);
 
+            // builtin functions
             symbolTable.setFunctionExtensions("barrier",                      1, &E_GL_NV_mesh_shader);
             symbolTable.setFunctionExtensions("memoryBarrierShared",          1, &E_GL_NV_mesh_shader);
             symbolTable.setFunctionExtensions("groupMemoryBarrier",           1, &E_GL_NV_mesh_shader);
@@ -9511,6 +9543,12 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
         BuiltInVariable("gl_in", "gl_BackSecondaryColor",  EbvBackSecondaryColor,  symbolTable);
         BuiltInVariable("gl_in", "gl_TexCoord",            EbvTexCoord,            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;
 
     default:

+ 25 - 12
3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp

@@ -312,9 +312,6 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb
     if (anon) {
         // It was a member of an anonymous container.
 
-        // The "getNumExtensions()" mechanism above doesn't yet work for block members
-        blockMemberExtensionCheck(loc, nullptr, *string);
-
         // Create a subtree for its dereference.
         variable = anon->getAnonContainer().getAsVariable();
         TIntermTyped* container = intermediate.addSymbol(*variable, loc);
@@ -355,7 +352,7 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb
         intermediate.addIoAccessed(*string);
 
     if (variable->getType().getBasicType() == EbtReference &&
-        variable->getType().getQualifier().isMemory()) {
+        variable->getType().getQualifier().bufferReferenceNeedsVulkanMemoryModel()) {
         intermediate.setUseVulkanMemoryModel();
     }
 
@@ -834,7 +831,7 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
             if (base->getType().getQualifier().isFrontEndConstant())
                 result = intermediate.foldDereference(base, member, loc);
             else {
-                blockMemberExtensionCheck(loc, base, field);
+                blockMemberExtensionCheck(loc, base, member, field);
                 TIntermTyped* index = intermediate.addConstantUnion(member, loc);
                 result = intermediate.addIndex(EOpIndexDirectStruct, base, index, loc);
                 result->setType(*(*fields)[member].type);
@@ -857,14 +854,30 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
     return result;
 }
 
-void TParseContext::blockMemberExtensionCheck(const TSourceLoc& loc, const TIntermTyped* /*base*/, const TString& field)
+void TParseContext::blockMemberExtensionCheck(const TSourceLoc& loc, const TIntermTyped* base, int member, const TString& memberName)
 {
-    if (profile == EEsProfile && field == "gl_PointSize") {
-        if (language == EShLangGeometry)
-            requireExtensions(loc, Num_AEP_geometry_point_size, AEP_geometry_point_size, "gl_PointSize");
-        else if (language == EShLangTessControl || language == EShLangTessEvaluation)
-            requireExtensions(loc, Num_AEP_tessellation_point_size, AEP_tessellation_point_size, "gl_PointSize");
-    }
+    // a block that needs extension checking is either 'base', or if arrayed,
+    // one level removed to the left
+    const TIntermSymbol* baseSymbol = nullptr;
+    if (base->getAsBinaryNode() == nullptr)
+        baseSymbol = base->getAsSymbolNode();
+    else
+        baseSymbol = base->getAsBinaryNode()->getLeft()->getAsSymbolNode();
+    if (baseSymbol == nullptr)
+        return;
+    const TSymbol* symbol = symbolTable.find(baseSymbol->getName());
+    if (symbol == nullptr)
+        return;
+    const TVariable* variable = symbol->getAsVariable();
+    if (variable == nullptr)
+        return;
+    if (!variable->hasMemberExtensions())
+        return;
+
+    // We now have a variable that is the base of a dot reference
+    // with members that need extension checking.
+    if (variable->getNumMemberExtensions(member) > 0)
+        requireExtensions(loc, variable->getNumMemberExtensions(member), variable->getMemberExtensions(member), memberName.c_str());
 }
 
 //

+ 1 - 1
3rdparty/glslang/glslang/MachineIndependent/ParseHelper.h

@@ -306,7 +306,7 @@ public:
     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* 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);
     TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
     TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);

+ 18 - 13
3rdparty/glslang/glslang/MachineIndependent/SymbolTable.cpp

@@ -287,19 +287,25 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
 {
     type.deepCopy(copyOf.type);
     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 < copyOf.type.getStruct()->size(); ++m) {
+            if (copyOf.getNumMemberExtensions(m) > 0)
+                setMemberExtensions(m, copyOf.getNumMemberExtensions(m), copyOf.getMemberExtensions(m));
+        }
+    }
 
     if (! copyOf.constArray.empty()) {
         assert(! copyOf.type.isStruct());
         TConstUnionArray newArray(copyOf.constArray, 0, copyOf.constArray.size());
         constArray = newArray;
     }
-
-    // don't support specialization-constant subtrees in cloned tables
-    constSubtree = nullptr;
 }
 
 TVariable* TVariable::clone() const
@@ -317,10 +323,9 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
         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);
     mangledName = copyOf.mangledName;
     op = copyOf.op;
@@ -359,12 +364,12 @@ TSymbolTableLevel* TSymbolTableLevel::clone() const
         const TAnonMember* anon = iter->second->getAsAnonMember();
         if (anon) {
             // 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.
             if (! containerCopied[anon->getAnonId()]) {
                 TVariable* container = anon->getAnonContainer().clone();
                 container->changeName(NewPoolTString(""));
-                // insert the whole container
+                // insert the container and all its members
                 symTableLevel->insert(*container, false);
                 containerCopied[anon->getAnonId()] = true;
             }

+ 69 - 24
3rdparty/glslang/glslang/MachineIndependent/SymbolTable.h

@@ -79,10 +79,12 @@ class TVariable;
 class TFunction;
 class TAnonMember;
 
+typedef TVector<const char*> TExtensionList;
+
 class TSymbol {
 public:
     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() { }  // rely on all symbol owned memory coming from the pool
 
@@ -104,17 +106,16 @@ public:
     virtual TType& getWritableType() = 0;
     virtual void setUniqueId(int id) { uniqueId = id; }
     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(num > 0);
-        numExtensions = num;
-        extensions = NewPoolObject(exts[0], num);
-        for (int e = 0; e < num; ++e)
-            extensions[e] = exts[e];
-    }
-    virtual int getNumExtensions() const { return numExtensions; }
-    virtual const char** getExtensions() const { return extensions; }
+        assert(numExts > 0);
+        extensions = NewPoolObject(extensions);
+        for (int e = 0; e < numExts; ++e)
+            extensions->push_back(exts[e]);
+    }
+    virtual int getNumExtensions() const { return extensions == nullptr ? 0 : (int)extensions->size(); }
+    virtual const char** getExtensions() const { return extensions->data(); }
     virtual void dump(TInfoSink &infoSink) const = 0;
 
     virtual bool isReadOnly() const { return ! writable; }
@@ -129,8 +130,7 @@ protected:
 
     // For tracking what extensions must be 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,
@@ -155,7 +155,9 @@ public:
         : TSymbol(name),
           userType(uT),
           constSubtree(nullptr),
-          anonId(-1) { type.shallowCopy(t); }
+          memberExtensions(nullptr),
+          anonId(-1)
+        { type.shallowCopy(t); }
     virtual TVariable* clone() const;
     virtual ~TVariable() { }
 
@@ -172,6 +174,24 @@ public:
     virtual void setAnonId(int i) { anonId = i; }
     virtual int getAnonId() const { return anonId; }
 
+    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) const;
 
 protected:
@@ -180,15 +200,14 @@ protected:
 
     TType type;
     bool userType;
+
     // we are assuming that Pool Allocator will free the memory allocated to unionArray
     // 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
 };
 
 //
@@ -325,7 +344,7 @@ protected:
 //
 class TAnonMember : public TSymbol {
 public:
-    TAnonMember(const TString* n, unsigned int m, const TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
+    TAnonMember(const TString* n, unsigned int m, TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
     virtual TAnonMember* clone() const;
     virtual ~TAnonMember() { }
 
@@ -346,6 +365,13 @@ public:
         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 void dump(TInfoSink &infoSink) const;
 
@@ -353,7 +379,7 @@ protected:
     explicit TAnonMember(const TAnonMember&);
     TAnonMember& operator=(const TAnonMember&);
 
-    const TVariable& anonContainer;
+    TVariable& anonContainer;
     unsigned int memberNumber;
     int anonId;
 };
@@ -789,11 +815,30 @@ public:
             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));
-        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; }

+ 6 - 13
3rdparty/glslang/hlsl/hlslParseHelper.cpp

@@ -654,10 +654,6 @@ TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, const TStr
         return nullptr;
     }
 
-    // Error check for requiring specific extensions present.
-    if (symbol && symbol->getNumExtensions())
-        requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str());
-
     const TVariable* variable = nullptr;
     const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : nullptr;
     TIntermTyped* node = nullptr;
@@ -3256,7 +3252,8 @@ void HlslParseContext::decomposeStructBufferMethods(const TSourceLoc& loc, TInte
     if (argAggregate) {
         if (argAggregate->getSequence().empty())
             return;
-        bufferObj = argAggregate->getSequence()[0]->getAsTyped();
+		if (argAggregate->getSequence()[0])
+	        bufferObj = argAggregate->getSequence()[0]->getAsTyped();
     } else {
         bufferObj = arguments->getAsSymbolNode();
     }
@@ -3755,7 +3752,8 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
             if (arguments->getAsTyped()->getBasicType() != EbtSampler)
                 return;
         } else {
-            if (argAggregate->getSequence().size() == 0 ||
+            if (argAggregate->getSequence().size() == 0 || 
+				argAggregate->getSequence()[0] == nullptr ||
                 argAggregate->getSequence()[0]->getAsTyped()->getBasicType() != EbtSampler)
                 return;
         }
@@ -5294,7 +5292,7 @@ TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunct
 
             TIntermTyped* arg0 = nullptr;
 
-            if (aggregate && aggregate->getSequence().size() > 0)
+            if (aggregate && aggregate->getSequence().size() > 0 && aggregate->getSequence()[0])
                 arg0 = aggregate->getSequence()[0]->getAsTyped();
             else if (arguments->getAsSymbolNode())
                 arg0 = arguments->getAsSymbolNode();
@@ -5322,11 +5320,6 @@ TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunct
             //  - a built-in function not mapped to an operator, or
             //  - a user function.
 
-            // Error check for a function requiring specific extensions present.
-            if (builtIn && fnCandidate->getNumExtensions())
-                requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(),
-                                  fnCandidate->getName().c_str());
-
             // turn an implicit member-function resolution into an explicit call
             TString callerName;
             if (thisDepth == 0)
@@ -5768,7 +5761,7 @@ void HlslParseContext::addStructBuffArguments(const TSourceLoc& loc, TIntermAggr
         std::any_of(aggregate->getSequence().begin(),
                     aggregate->getSequence().end(),
                     [this](const TIntermNode* node) {
-                        return (node->getAsTyped() != nullptr) && hasStructBuffCounter(node->getAsTyped()->getType());
+                        return (node && node->getAsTyped() != nullptr) && hasStructBuffCounter(node->getAsTyped()->getType());
                     });
 
     // Nothing to do, if we didn't find one.

+ 1 - 1
3rdparty/glslang/known_good.json

@@ -5,7 +5,7 @@
       "site" : "github",
       "subrepo" : "KhronosGroup/SPIRV-Tools",
       "subdir" : "External/spirv-tools",
-      "commit" : "df5bd2d05ac1fd3ec3024439f885ec21cc949b22"
+      "commit" : "e2279da7148d19bd21c6d47ffc96ee4176f43dba"
     },
     {
       "name" : "spirv-tools/external/spirv-headers",