SPV: Generalize multiple struct-type instances for interpolation/invariant qualifiers.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index afea3bc..654fe87 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -91,7 +91,7 @@
     spv::Id createSpvVariable(const glslang::TIntermSymbol*);
     spv::Id getSampledType(const glslang::TSampler&);
     spv::Id convertGlslangToSpvType(const glslang::TType& type);
-    spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, glslang::TLayoutMatrix);
+    spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&);
     glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const;
     int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
     int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
@@ -299,30 +299,30 @@
 // Translate glslang type to SPIR-V interpolation decorations.
 // Returns spv::Decoration(spv::BadValue) when no decoration
 // should be applied.
-spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)
+spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier)
 {
-    if (type.getQualifier().smooth) {
+    if (qualifier.smooth) {
         // Smooth decoration doesn't exist in SPIR-V 1.0
         return (spv::Decoration)spv::BadValue;
     }
-    if (type.getQualifier().nopersp)
+    if (qualifier.nopersp)
         return spv::DecorationNoPerspective;
-    else if (type.getQualifier().patch)
+    else if (qualifier.patch)
         return spv::DecorationPatch;
-    else if (type.getQualifier().flat)
+    else if (qualifier.flat)
         return spv::DecorationFlat;
-    else if (type.getQualifier().centroid)
+    else if (qualifier.centroid)
         return spv::DecorationCentroid;
-    else if (type.getQualifier().sample)
+    else if (qualifier.sample)
         return spv::DecorationSample;
     else
         return (spv::Decoration)spv::BadValue;
 }
 
 // If glslang type is invaraiant, return SPIR-V invariant decoration.
-spv::Decoration TranslateInvariantDecoration(const glslang::TType& type)
+spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifier)
 {
-    if (type.getQualifier().invariant)
+    if (qualifier.invariant)
         return spv::DecorationInvariant;
     else
         return (spv::Decoration)spv::BadValue;
@@ -420,6 +420,34 @@
     }
 }
 
+void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& parent)
+{
+    if (child.layoutMatrix == glslang::ElmNone)
+        child.layoutMatrix = parent.layoutMatrix;
+
+    if (parent.invariant)
+        child.invariant = true;
+    if (parent.nopersp)
+        child.nopersp = true;
+    if (parent.flat)
+        child.flat = true;
+    if (parent.centroid)
+        child.centroid = true;
+    if (parent.patch)
+        child.patch = true;
+    if (parent.sample)
+        child.sample = true;
+}
+
+bool HasNonLayoutQualifiers(const glslang::TQualifier& qualifier)
+{
+    // This should list qualifiers that simultaneous satisify:
+    // - struct members can inherit from a struct declaration
+    // - effect decorations on the struct members (note smooth does not, and expecting something like volatile to effect the whole object)
+    // - are not part of the offset/st430/etc or row/column-major layout
+    return qualifier.invariant || qualifier.nopersp || qualifier.flat || qualifier.centroid || qualifier.patch || qualifier.sample;
+}
+
 //
 // Implement the TGlslangToSpvTraverser class.
 //
@@ -1467,14 +1495,14 @@
 // layout state rooted from the top-level type.
 spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)
 {
-    return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier().layoutMatrix);
+    return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier());
 }
 
 // Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
 // explicitLayout can be kept the same throughout the heirarchical recursive walk.
-spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
+spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier)
 {
-    spv::Id spvType = 0;
+    spv::Id spvType = spv::NoResult;
 
     switch (type.getBasicType()) {
     case glslang::EbtVoid:
@@ -1503,13 +1531,13 @@
     case glslang::EbtSampler:
         {
             const glslang::TSampler& sampler = type.getSampler();
-                // an image is present, make its type
-                spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
-                                                sampler.image ? 2 : 1, TranslateImageFormat(type));
+            // an image is present, make its type
+            spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
+                                            sampler.image ? 2 : 1, TranslateImageFormat(type));
             if (! sampler.image) {
-                    spvType = builder.makeSampledImageType(spvType);
-                }
+                spvType = builder.makeSampledImageType(spvType);
             }
+        }
         break;
     case glslang::EbtStruct:
     case glslang::EbtBlock:
@@ -1517,8 +1545,12 @@
             // If we've seen this struct type, return it
             const glslang::TTypeList* glslangStruct = type.getStruct();
             std::vector<spv::Id> structFields;
-            spvType = structMap[explicitLayout][matrixLayout][glslangStruct];
-            if (spvType)
+
+            // Try to share structs for different layouts, but not yet for other
+            // kinds of qualification (primarily not yet including interpolant qualification).
+            if (! HasNonLayoutQualifiers(qualifier))
+                spvType = structMap[explicitLayout][qualifier.layoutMatrix][glslangStruct];
+            if (spvType != spv::NoResult)
                 break;
 
             // else, we haven't seen it...
@@ -1536,16 +1568,17 @@
                 } else {
                     if (type.getBasicType() == glslang::EbtBlock)
                         memberRemapper[glslangStruct][i] = i - memberDelta;
-                    // modify just the children's view of matrix layout, if there is one for this member
-                    glslang::TLayoutMatrix subMatrixLayout = glslangType.getQualifier().layoutMatrix;
-                    structFields.push_back(convertGlslangToSpvType(glslangType, explicitLayout,
-                                           subMatrixLayout != glslang::ElmNone ? subMatrixLayout : matrixLayout));
+                    // modify just this child's view of the qualifier
+                    glslang::TQualifier subQualifier = glslangType.getQualifier();
+                    InheritQualifiers(subQualifier, qualifier);
+                    structFields.push_back(convertGlslangToSpvType(glslangType, explicitLayout, subQualifier));
                 }
             }
 
             // Make the SPIR-V type
             spvType = builder.makeStructType(structFields, type.getTypeName().c_str());
-            structMap[explicitLayout][matrixLayout][glslangStruct] = spvType;
+            if (! HasNonLayoutQualifiers(qualifier))
+                structMap[explicitLayout][qualifier.layoutMatrix][glslangStruct] = spvType;
 
             // Name and decorate the non-hidden members
             int offset = -1;
@@ -1555,18 +1588,17 @@
                 if (type.getBasicType() == glslang::EbtBlock)
                     member = memberRemapper[glslangStruct][i];
 
-                // modify just the children's view of matrix layout, if there is one for this member
-                glslang::TLayoutMatrix subMatrixLayout = glslangType.getQualifier().layoutMatrix;
-                if (subMatrixLayout == glslang::ElmNone)
-                    subMatrixLayout = matrixLayout;
+                // modify just this child's view of the qualifier
+                glslang::TQualifier subQualifier = glslangType.getQualifier();
+                InheritQualifiers(subQualifier, qualifier);
 
                 // using -1 above to indicate a hidden member
                 if (member >= 0) {
                     builder.addMemberName(spvType, member, glslangType.getFieldName().c_str());
-                    addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangType, subMatrixLayout));
+                    addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangType, subQualifier.layoutMatrix));
                     addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangType));
-                    addMemberDecoration(spvType, member, TranslateInterpolationDecoration(glslangType));
-                    addMemberDecoration(spvType, member, TranslateInvariantDecoration(glslangType));
+                    addMemberDecoration(spvType, member, TranslateInterpolationDecoration(subQualifier));
+                    addMemberDecoration(spvType, member, TranslateInvariantDecoration(subQualifier));
                     if (glslangType.getQualifier().hasLocation())
                         builder.addMemberDecoration(spvType, member, spv::DecorationLocation, glslangType.getQualifier().layoutLocation);
                     if (glslangType.getQualifier().hasComponent())
@@ -1576,14 +1608,14 @@
                     else if (explicitLayout != glslang::ElpNone) {
                         // figure out what to do with offset, which is accumulating
                         int nextOffset;
-                        updateMemberOffset(type, glslangType, offset, nextOffset, explicitLayout, subMatrixLayout);
+                        updateMemberOffset(type, glslangType, offset, nextOffset, explicitLayout, subQualifier.layoutMatrix);
                         if (offset >= 0)
                             builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset);
                         offset = nextOffset;
                     }
 
                     if (glslangType.isMatrix() && explicitLayout != glslang::ElpNone)
-                        builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, getMatrixStride(glslangType, explicitLayout, subMatrixLayout));
+                        builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, getMatrixStride(glslangType, explicitLayout, subQualifier.layoutMatrix));
 
                     // built-in variable decorations
                     spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn);
@@ -1593,7 +1625,7 @@
             }
 
             // Decorate the structure
-            addDecoration(spvType, TranslateLayoutDecoration(type, matrixLayout));
+            addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix));
             addDecoration(spvType, TranslateBlockDecoration(type));
             if (type.getQualifier().hasStream())
                 builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);
@@ -1641,7 +1673,7 @@
         // except for the very top if it is an array of blocks; that array is
         // not laid out in memory in a way needing a stride.
         if (explicitLayout && type.getBasicType() != glslang::EbtBlock)
-            builder.addDecoration(spvType, spv::DecorationArrayStride, getArrayStride(type, explicitLayout, matrixLayout));
+            builder.addDecoration(spvType, spv::DecorationArrayStride, getArrayStride(type, explicitLayout, qualifier.layoutMatrix));
     }
 
     return spvType;
@@ -3146,7 +3178,7 @@
 
     if (! symbol->getType().isStruct()) {
         addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));
-        addDecoration(id, TranslateInterpolationDecoration(symbol->getType()));
+        addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier()));
         if (symbol->getQualifier().hasLocation())
             builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);
         if (symbol->getQualifier().hasIndex())
@@ -3163,7 +3195,7 @@
         }
     }
 
-    addDecoration(id, TranslateInvariantDecoration(symbol->getType()));
+    addDecoration(id, TranslateInvariantDecoration(symbol->getType().getQualifier()));
     if (symbol->getQualifier().hasStream())
         builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);
     if (symbol->getQualifier().hasSet())
diff --git a/Test/baseResults/spv.layoutNested.vert.out b/Test/baseResults/spv.layoutNested.vert.out
index 98e4ae6..54ed9b7 100644
--- a/Test/baseResults/spv.layoutNested.vert.out
+++ b/Test/baseResults/spv.layoutNested.vert.out
@@ -7,12 +7,12 @@
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 63
+// Id's are bound by 69
 
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint Vertex 4  "main" 61 62
+                              EntryPoint Vertex 4  "main" 62 65 67 68
                               Source GLSL 450
                               Name 4  "main"
                               Name 14  "S"
@@ -82,8 +82,18 @@
                               MemberName 57(bBt3) 0  "ntcol"
                               MemberName 57(bBt3) 1  "ntrow"
                               Name 59  "bBtn3"
-                              Name 61  "gl_VertexID"
-                              Name 62  "gl_InstanceID"
+                              Name 60  "S"
+                              MemberName 60(S) 0  "a"
+                              MemberName 60(S) 1  "b"
+                              MemberName 60(S) 2  "c"
+                              Name 62  "sout"
+                              Name 63  "S"
+                              MemberName 63(S) 0  "a"
+                              MemberName 63(S) 1  "b"
+                              MemberName 63(S) 2  "c"
+                              Name 65  "soutinv"
+                              Name 67  "gl_VertexID"
+                              Name 68  "gl_InstanceID"
                               Decorate 13 ArrayStride 32
                               MemberDecorate 14(S) 0 Offset 0
                               MemberDecorate 14(S) 1 ColMajor
@@ -156,8 +166,15 @@
                               Decorate 57(bBt3) BufferBlock
                               Decorate 59(bBtn3) DescriptorSet 1
                               Decorate 59(bBtn3) Binding 0
-                              Decorate 61(gl_VertexID) BuiltIn VertexId
-                              Decorate 62(gl_InstanceID) BuiltIn InstanceId
+                              MemberDecorate 60(S) 0 Flat
+                              MemberDecorate 60(S) 1 Flat
+                              MemberDecorate 60(S) 2 Flat
+                              MemberDecorate 63(S) 0 Invariant
+                              MemberDecorate 63(S) 1 Invariant
+                              MemberDecorate 63(S) 2 Invariant
+                              Decorate 65(soutinv) Invariant
+                              Decorate 67(gl_VertexID) BuiltIn VertexId
+                              Decorate 68(gl_InstanceID) BuiltIn InstanceId
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeInt 32 1
@@ -214,9 +231,15 @@
         57(bBt3):             TypeStruct 48(Nestor) 53(Nestor)
               58:             TypePointer Uniform 57(bBt3)
        59(bBtn3):     58(ptr) Variable Uniform
-              60:             TypePointer Input 6(int)
- 61(gl_VertexID):     60(ptr) Variable Input
-62(gl_InstanceID):     60(ptr) Variable Input
+           60(S):             TypeStruct 8(ivec3) 13 7(int)
+              61:             TypePointer Output 60(S)
+        62(sout):     61(ptr) Variable Output
+           63(S):             TypeStruct 8(ivec3) 13 7(int)
+              64:             TypePointer Output 63(S)
+     65(soutinv):     64(ptr) Variable Output
+              66:             TypePointer Input 6(int)
+ 67(gl_VertexID):     66(ptr) Variable Input
+68(gl_InstanceID):     66(ptr) Variable Input
          4(main):           2 Function None 3
                5:             Label
                               Return
diff --git a/Test/spv.layoutNested.vert b/Test/spv.layoutNested.vert
index ac44cbe..f0dc389 100644
--- a/Test/spv.layoutNested.vert
+++ b/Test/spv.layoutNested.vert
@@ -1,6 +1,6 @@
 #version 450

 

-// should get 3 SPV types for S: no layout, 140, and 430

+// should get 3 SPV types for S: no layout, 140, and 430, plus extras for interpolation or invariant differences

 struct S

 {

 	highp uvec3 a;

@@ -71,3 +71,6 @@
 void main()

 {

 }

+

+flat out S sout;

+invariant out S soutinv;

diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h
index 582685c..b14b74a 100644
--- a/glslang/Include/revision.h
+++ b/glslang/Include/revision.h
@@ -2,5 +2,5 @@
 // For the version, it uses the latest git tag followed by the number of commits.
 // For the date, it uses the current date (when then script is run).
 
-#define GLSLANG_REVISION "SPIRV99.865"
-#define GLSLANG_DATE "22-Dec-2015"
+#define GLSLANG_REVISION "SPIRV99.866"
+#define GLSLANG_DATE "24-Dec-2015"