Refactor ShaderVariables to store fields in the base.

Instead of only storing structure information in Varyings, Uniforms
and Interface Block Fields, store it in the base class. Also only
store base variable information for struct fields, instead of fully
typed information. This works because stuff like interpolation type,
invariance, and other properties are for the entire variable, not
individual fields.

Also add new fields for interface block instance name, varying
invariance and structure name for all struct types.

BUG=angle:466

Change-Id: If03fc071e6becb7aad6dea5093989bba7daee69e
Reviewed-on: https://chromium-review.googlesource.com/213501
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Nicolas Capens <capn@chromium.org>
diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h
index a61fcb4..b7989f5 100644
--- a/include/GLSLANG/ShaderLang.h
+++ b/include/GLSLANG/ShaderLang.h
@@ -39,6 +39,7 @@
 }
 
 // Must be included after GLenum proxy typedef
+// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
 #include "ShaderVars.h"
 
 #ifdef __cplusplus
@@ -47,7 +48,7 @@
 
 // Version number for shader translation API.
 // It is incremented every time the API changes.
-#define ANGLE_SH_VERSION 129
+#define ANGLE_SH_VERSION 130
 
 typedef enum {
   SH_GLES2_SPEC = 0x8B40,
diff --git a/include/GLSLANG/ShaderVars.h b/include/GLSLANG/ShaderVars.h
index 74f2b34..26e00c6 100644
--- a/include/GLSLANG/ShaderVars.h
+++ b/include/GLSLANG/ShaderVars.h
@@ -15,6 +15,7 @@
 #include <algorithm>
 
 // Assume ShaderLang.h is included before ShaderVars.h, for sh::GLenum
+// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
 
 namespace sh
 {
@@ -49,6 +50,7 @@
 
     bool isArray() const { return arraySize > 0; }
     unsigned int elementCount() const { return std::max(1u, arraySize); }
+    bool isStruct() const { return !fields.empty(); }
 
     GLenum type;
     GLenum precision;
@@ -56,6 +58,8 @@
     std::string mappedName;
     unsigned int arraySize;
     bool staticUse;
+    std::vector<ShaderVariable> fields;
+    std::string structName;
 };
 
 struct COMPILER_EXPORT Uniform : public ShaderVariable
@@ -64,10 +68,6 @@
     ~Uniform();
     Uniform(const Uniform &other);
     Uniform &operator=(const Uniform &other);
-
-    bool isStruct() const { return !fields.empty(); }
-
-    std::vector<Uniform> fields;
 };
 
 struct COMPILER_EXPORT Attribute : public ShaderVariable
@@ -87,10 +87,7 @@
     InterfaceBlockField(const InterfaceBlockField &other);
     InterfaceBlockField &operator=(const InterfaceBlockField &other);
 
-    bool isStruct() const { return !fields.empty(); }
-
     bool isRowMajorMatrix;
-    std::vector<InterfaceBlockField> fields;
 };
 
 struct COMPILER_EXPORT Varying : public ShaderVariable
@@ -100,11 +97,8 @@
     Varying(const Varying &other);
     Varying &operator=(const Varying &other);
 
-    bool isStruct() const { return !fields.empty(); }
-
     InterpolationType interpolation;
-    std::vector<Varying> fields;
-    std::string structName;
+    bool isInvariant;
 };
 
 struct COMPILER_EXPORT InterfaceBlock
@@ -116,6 +110,7 @@
 
     std::string name;
     std::string mappedName;
+    std::string instanceName;
     unsigned int arraySize;
     BlockLayoutType layout;
     bool isRowMajorLayout;
diff --git a/src/common/blocklayout.cpp b/src/common/blocklayout.cpp
index c1f0c3a..2aa776f 100644
--- a/src/common/blocklayout.cpp
+++ b/src/common/blocklayout.cpp
@@ -15,15 +15,17 @@
 {
 
 BlockLayoutEncoder::BlockLayoutEncoder()
-    : mCurrentOffset(0)
+    : mCurrentOffset(0),
+      mInRowMajorField(false)
 {
 }
 
-void BlockLayoutEncoder::encodeInterfaceBlockFields(const std::vector<InterfaceBlockField> &fields)
+template <typename VarT>
+void BlockLayoutEncoder::encodeVariables(const std::vector<VarT> &fields)
 {
     for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
     {
-        const InterfaceBlockField &variable = fields[fieldIndex];
+        const VarT &variable = fields[fieldIndex];
 
         if (variable.fields.size() > 0)
         {
@@ -32,28 +34,38 @@
             for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
             {
                 enterAggregateType();
-                encodeInterfaceBlockFields(variable.fields);
+                encodeVariables(variable.fields);
                 exitAggregateType();
             }
         }
         else
         {
-            encodeInterfaceBlockField(variable);
+            encodeVariable(variable);
         }
     }
 }
 
-BlockMemberInfo BlockLayoutEncoder::encodeInterfaceBlockField(const InterfaceBlockField &field)
+// Only defined for interface block fields, and shader variable base
+template void BlockLayoutEncoder::encodeVariables(const std::vector<ShaderVariable> &);
+template void BlockLayoutEncoder::encodeVariables(const std::vector<InterfaceBlockField> &);
+
+BlockMemberInfo BlockLayoutEncoder::encodeVariable(const InterfaceBlockField &field)
+{
+    mInRowMajorField = field.isRowMajorMatrix;
+    return encodeVariable(static_cast<ShaderVariable>(field));
+}
+
+BlockMemberInfo BlockLayoutEncoder::encodeVariable(const sh::ShaderVariable &field)
 {
     int arrayStride;
     int matrixStride;
 
     ASSERT(field.fields.empty());
-    getBlockLayoutInfo(field.type, field.arraySize, field.isRowMajorMatrix, &arrayStride, &matrixStride);
+    getBlockLayoutInfo(field.type, field.arraySize, mInRowMajorField, &arrayStride, &matrixStride);
 
-    const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, field.isRowMajorMatrix);
+    const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, mInRowMajorField);
 
-    advanceOffset(field.type, field.arraySize, field.isRowMajorMatrix, arrayStride, matrixStride);
+    advanceOffset(field.type, field.arraySize, mInRowMajorField, arrayStride, matrixStride);
 
     return memberInfo;
 }
diff --git a/src/common/blocklayout.h b/src/common/blocklayout.h
index bed99c4..e8824fd 100644
--- a/src/common/blocklayout.h
+++ b/src/common/blocklayout.h
@@ -49,8 +49,12 @@
   public:
     BlockLayoutEncoder();
 
-    void encodeInterfaceBlockFields(const std::vector<InterfaceBlockField> &fields);
-    BlockMemberInfo encodeInterfaceBlockField(const InterfaceBlockField &field);
+    template <typename VarT>
+    void encodeVariables(const std::vector<VarT> &fields);
+
+    BlockMemberInfo encodeVariable(const sh::ShaderVariable &field);
+    BlockMemberInfo encodeVariable(const InterfaceBlockField &field);
+
     void encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix);
 
     size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; }
@@ -65,6 +69,7 @@
 
   protected:
     size_t mCurrentOffset;
+    bool mInRowMajorField;
 
     void nextRegister();
 
diff --git a/src/compiler/translator/Compiler.h b/src/compiler/translator/Compiler.h
index 5eac2d8..6bef5c1 100644
--- a/src/compiler/translator/Compiler.h
+++ b/src/compiler/translator/Compiler.h
@@ -71,9 +71,9 @@
     const std::vector<sh::Attribute> &getAttributes() const { return attributes; }
     const std::vector<sh::Attribute> &getOutputVariables() const { return outputVariables; }
     const std::vector<sh::Uniform> &getUniforms() const { return uniforms; }
-    const std::vector<sh::Uniform> &getExpandedUniforms() const { return expandedUniforms; }
+    const std::vector<sh::ShaderVariable> &getExpandedUniforms() const { return expandedUniforms; }
     const std::vector<sh::Varying> &getVaryings() const { return varyings; }
-    const std::vector<sh::Varying> &getExpandedVaryings() const { return expandedVaryings; }
+    const std::vector<sh::ShaderVariable> &getExpandedVaryings() const { return expandedVaryings; }
     const std::vector<sh::InterfaceBlock> &getInterfaceBlocks() const { return interfaceBlocks; }
 
     ShHashFunction64 getHashFunction() const { return hashFunction; }
@@ -138,9 +138,9 @@
     std::vector<sh::Attribute> attributes;
     std::vector<sh::Attribute> outputVariables;
     std::vector<sh::Uniform> uniforms;
-    std::vector<sh::Uniform> expandedUniforms;
+    std::vector<sh::ShaderVariable> expandedUniforms;
     std::vector<sh::Varying> varyings;
-    std::vector<sh::Varying> expandedVaryings;
+    std::vector<sh::ShaderVariable> expandedVaryings;
     std::vector<sh::InterfaceBlock> interfaceBlocks;
 
   private:
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index e0a90ec..defb34a 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -2922,29 +2922,12 @@
     return constUnion;
 }
 
-class DeclareVaryingTraverser : public GetVariableTraverser<Varying>
-{
-  public:
-    DeclareVaryingTraverser(std::vector<Varying> *output,
-                            InterpolationType interpolation)
-        : GetVariableTraverser(output),
-          mInterpolation(interpolation)
-    {}
-
-  private:
-    void visitVariable(Varying *varying)
-    {
-        varying->interpolation = mInterpolation;
-    }
-
-    InterpolationType mInterpolation;
-};
-
 void OutputHLSL::declareVaryingToList(const TType &type, TQualifier baseTypeQualifier,
                                       const TString &name, std::vector<Varying> &fieldsOut)
 {
-    DeclareVaryingTraverser traverser(&fieldsOut, GetInterpolationType(baseTypeQualifier));
-    traverser.traverse(type, name);
+    GetVariableTraverser traverser;
+    traverser.traverse(type, name, &fieldsOut);
+    fieldsOut.back().interpolation = GetInterpolationType(baseTypeQualifier);
 }
 
 }
diff --git a/src/compiler/translator/ShaderVars.cpp b/src/compiler/translator/ShaderVars.cpp
index 164eaa6..90f3bd0 100644
--- a/src/compiler/translator/ShaderVars.cpp
+++ b/src/compiler/translator/ShaderVars.cpp
@@ -35,7 +35,9 @@
       name(other.name),
       mappedName(other.mappedName),
       arraySize(other.arraySize),
-      staticUse(other.staticUse)
+      staticUse(other.staticUse),
+      fields(other.fields),
+      structName(other.structName)
 {}
 
 ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
@@ -46,6 +48,8 @@
     mappedName = other.mappedName;
     arraySize = other.arraySize;
     staticUse = other.staticUse;
+    fields = other.fields;
+    structName = other.structName;
     return *this;
 }
 
@@ -56,14 +60,12 @@
 {}
 
 Uniform::Uniform(const Uniform &other)
-    : ShaderVariable(other),
-      fields(other.fields)
+    : ShaderVariable(other)
 {}
 
 Uniform &Uniform::operator=(const Uniform &other)
 {
     ShaderVariable::operator=(other);
-    fields = other.fields;
     return *this;
 }
 
@@ -95,20 +97,19 @@
 
 InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other)
     : ShaderVariable(other),
-      isRowMajorMatrix(other.isRowMajorMatrix),
-      fields(other.fields)
+      isRowMajorMatrix(other.isRowMajorMatrix)
 {}
 
 InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other)
 {
     ShaderVariable::operator=(other);
     isRowMajorMatrix = other.isRowMajorMatrix;
-    fields = other.fields;
     return *this;
 }
 
 Varying::Varying()
-    : interpolation(INTERPOLATION_SMOOTH)
+    : interpolation(INTERPOLATION_SMOOTH),
+      isInvariant(false)
 {}
 
 Varying::~Varying()
@@ -117,16 +118,14 @@
 Varying::Varying(const Varying &other)
     : ShaderVariable(other),
       interpolation(other.interpolation),
-      fields(other.fields),
-      structName(other.structName)
+      isInvariant(other.isInvariant)
 {}
 
 Varying &Varying::operator=(const Varying &other)
 {
     ShaderVariable::operator=(other);
     interpolation = other.interpolation;
-    fields = other.fields;
-    structName = other.structName;
+    isInvariant = other.isInvariant;
     return *this;
 }
 
@@ -143,6 +142,7 @@
 InterfaceBlock::InterfaceBlock(const InterfaceBlock &other)
     : name(other.name),
       mappedName(other.mappedName),
+      instanceName(other.instanceName),
       arraySize(other.arraySize),
       layout(other.layout),
       isRowMajorLayout(other.isRowMajorLayout),
@@ -154,6 +154,7 @@
 {
     name = other.name;
     mappedName = other.mappedName;
+    instanceName = other.instanceName;
     arraySize = other.arraySize;
     layout = other.layout;
     isRowMajorLayout = other.isRowMajorLayout;
diff --git a/src/compiler/translator/UniformHLSL.cpp b/src/compiler/translator/UniformHLSL.cpp
index e24da6a..2c99a90 100644
--- a/src/compiler/translator/UniformHLSL.cpp
+++ b/src/compiler/translator/UniformHLSL.cpp
@@ -30,18 +30,6 @@
     }
 }
 
-static TString InterfaceBlockFieldName(const TInterfaceBlock &interfaceBlock, const TField &field)
-{
-    if (interfaceBlock.hasInstanceName())
-    {
-        return interfaceBlock.name() + "." + field.name();
-    }
-    else
-    {
-        return field.name();
-    }
-}
-
 static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage)
 {
     const TType &fieldType = *field.type();
@@ -94,8 +82,8 @@
 {
     unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister);
 
-    GetVariableTraverser<Uniform> traverser(&mActiveUniforms);
-    traverser.traverse(type, name);
+    GetVariableTraverser traverser;
+    traverser.traverse(type, name, &mActiveUniforms);
 
     const sh::Uniform &activeUniform = mActiveUniforms.back();
     mUniformRegisterMap[activeUniform.name] = registerIndex;
@@ -162,7 +150,6 @@
     {
         const TType &nodeType = interfaceBlockIt->second->getType();
         const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock();
-        const TFieldList &fieldList = interfaceBlock.fields();
 
         unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize());
         unsigned int activeRegister = mInterfaceBlockRegister;
@@ -171,15 +158,7 @@
         activeBlock.name = interfaceBlock.name().c_str();
         activeBlock.arraySize = arraySize;
 
-        for (unsigned int typeIndex = 0; typeIndex < fieldList.size(); typeIndex++)
-        {
-            const TField &field = *fieldList[typeIndex];
-            const TString &fullFieldName = InterfaceBlockFieldName(interfaceBlock, field);
-
-            bool isRowMajor = (field.type()->getLayoutQualifier().matrixPacking == EmpRowMajor);
-            GetInterfaceBlockFieldTraverser traverser(&activeBlock.fields, isRowMajor);
-            traverser.traverse(*field.type(), fullFieldName);
-        }
+        GetInterfaceBlockFields(interfaceBlock, &activeBlock.fields);
 
         mInterfaceBlockRegisterMap[activeBlock.name] = activeRegister;
         mInterfaceBlockRegister += std::max(1u, arraySize);
diff --git a/src/compiler/translator/VariableInfo.cpp b/src/compiler/translator/VariableInfo.cpp
index 54129d4..b331581 100644
--- a/src/compiler/translator/VariableInfo.cpp
+++ b/src/compiler/translator/VariableInfo.cpp
@@ -9,20 +9,17 @@
 #include "compiler/translator/util.h"
 #include "common/utilities.h"
 
-template <typename VarT>
-static void ExpandUserDefinedVariable(const VarT &variable,
+static void ExpandUserDefinedVariable(const sh::ShaderVariable &variable,
                                       const std::string &name,
                                       const std::string &mappedName,
                                       bool markStaticUse,
-                                      std::vector<VarT> *expanded);
+                                      std::vector<sh::ShaderVariable> *expanded);
 
-// Returns info for an attribute, uniform, or varying.
-template <typename VarT>
-static void ExpandVariable(const VarT &variable,
+static void ExpandVariable(const sh::ShaderVariable &variable,
                            const std::string &name,
                            const std::string &mappedName,
                            bool markStaticUse,
-                           std::vector<VarT> *expanded)
+                           std::vector<sh::ShaderVariable> *expanded)
 {
     if (variable.isStruct())
     {
@@ -42,7 +39,7 @@
     }
     else
     {
-        VarT expandedVar = variable;
+        sh::ShaderVariable expandedVar = variable;
 
         expandedVar.name = name;
         expandedVar.mappedName = mappedName;
@@ -63,20 +60,19 @@
     }
 }
 
-template <class VarT>
-static void ExpandUserDefinedVariable(const VarT &variable,
+static void ExpandUserDefinedVariable(const sh::ShaderVariable &variable,
                                       const std::string &name,
                                       const std::string &mappedName,
                                       bool markStaticUse,
-                                      std::vector<VarT> *expanded)
+                                      std::vector<sh::ShaderVariable> *expanded)
 {
     ASSERT(variable.isStruct());
 
-    const std::vector<VarT> &fields = variable.fields;
+    const std::vector<sh::ShaderVariable> &fields = variable.fields;
 
     for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
     {
-        const VarT &field = fields[fieldIndex];
+        const sh::ShaderVariable &field = fields[fieldIndex];
         ExpandVariable(field,
                        name + "." + field.name,
                        mappedName + "." + field.mappedName,
@@ -216,17 +212,17 @@
     }
 }
 
-template <typename VarT>
-class NameHashingTraverser : public sh::GetVariableTraverser<VarT>
+class NameHashingTraverser : public sh::GetVariableTraverser
 {
   public:
-    NameHashingTraverser(std::vector<VarT> *output, ShHashFunction64 hashFunction)
-        : sh::GetVariableTraverser<VarT>(output),
-          mHashFunction(hashFunction)
+    NameHashingTraverser(ShHashFunction64 hashFunction)
+        : mHashFunction(hashFunction)
     {}
 
   private:
-    void visitVariable(VarT *variable)
+    DISALLOW_COPY_AND_ASSIGN(NameHashingTraverser);
+
+    virtual void visitVariable(sh::ShaderVariable *variable)
     {
         TString stringName = TString(variable->name.c_str());
         variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str();
@@ -262,26 +258,16 @@
 {
     sh::InterfaceBlock interfaceBlock;
     const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock();
-
-    bool isRowMajor = (blockType->matrixPacking() == EmpRowMajor);
+    ASSERT(blockType);
 
     interfaceBlock.name = blockType->name().c_str();
     interfaceBlock.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
+    interfaceBlock.instanceName = (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
     interfaceBlock.arraySize = variable->getArraySize();
-    interfaceBlock.isRowMajorLayout = isRowMajor;
+    interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
     interfaceBlock.layout = sh::GetBlockLayoutType(blockType->blockStorage());
 
-    ASSERT(blockType);
-    const TFieldList &blockFields = blockType->fields();
-
-    for (size_t fieldIndex = 0; fieldIndex < blockFields.size(); fieldIndex++)
-    {
-        const TField *field = blockFields[fieldIndex];
-        ASSERT(field);
-
-        sh::GetInterfaceBlockFieldTraverser traverser(&interfaceBlock.fields, isRowMajor);
-        traverser.traverse(*field->type(), field->name());
-    }
+    sh::GetInterfaceBlockFields(*blockType, &interfaceBlock.fields);
 
     infoList->push_back(interfaceBlock);
 }
@@ -290,8 +276,8 @@
 void CollectVariables::visitVariable(const TIntermSymbol *variable,
                                      std::vector<VarT> *infoList) const
 {
-    NameHashingTraverser<VarT> traverser(infoList, mHashFunction);
-    traverser.traverse(variable->getType(), variable->getSymbol());
+    NameHashingTraverser traverser(mHashFunction);
+    traverser.traverse(variable->getType(), variable->getSymbol(), infoList);
 }
 
 template <typename VarT>
@@ -361,14 +347,15 @@
 }
 
 template <typename VarT>
-void ExpandVariables(const std::vector<VarT> &compact, std::vector<VarT> *expanded)
+void ExpandVariables(const std::vector<VarT> &compact,
+                     std::vector<sh::ShaderVariable> *expanded)
 {
     for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++)
     {
-        const VarT &variable = compact[variableIndex];
+        const sh::ShaderVariable &variable = compact[variableIndex];
         ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);
     }
 }
 
-template void ExpandVariables(const std::vector<sh::Uniform> &, std::vector<sh::Uniform> *);
-template void ExpandVariables(const std::vector<sh::Varying> &, std::vector<sh::Varying> *);
+template void ExpandVariables(const std::vector<sh::Uniform> &, std::vector<sh::ShaderVariable> *);
+template void ExpandVariables(const std::vector<sh::Varying> &, std::vector<sh::ShaderVariable> *);
diff --git a/src/compiler/translator/VariableInfo.h b/src/compiler/translator/VariableInfo.h
index 03f7d62..d39bb21 100644
--- a/src/compiler/translator/VariableInfo.h
+++ b/src/compiler/translator/VariableInfo.h
@@ -48,8 +48,8 @@
 };
 
 // Expand struct variables to flattened lists of split variables
-// Implemented for sh::Varying and sh::Uniform.
 template <typename VarT>
-void ExpandVariables(const std::vector<VarT> &compact, std::vector<VarT> *expanded);
+void ExpandVariables(const std::vector<VarT> &compact,
+                     std::vector<sh::ShaderVariable> *expanded);
 
 #endif  // COMPILER_VARIABLE_INFO_H_
diff --git a/src/compiler/translator/util.cpp b/src/compiler/translator/util.cpp
index 46ce99c..8684a13 100644
--- a/src/compiler/translator/util.cpp
+++ b/src/compiler/translator/util.cpp
@@ -282,7 +282,7 @@
 }
 
 template <typename VarT>
-void GetVariableTraverser<VarT>::traverse(const TType &type, const TString &name)
+void GetVariableTraverser::traverse(const TType &type, const TString &name, std::vector<VarT> *output)
 {
     const TStructure *structure = type.getStruct();
 
@@ -297,51 +297,28 @@
     }
     else
     {
+        // Note: this enum value is not exposed outside ANGLE
         variable.type = GL_STRUCT_ANGLEX;
-
-        mOutputStack.push(&variable.fields);
+        variable.structName = structure->name().c_str();
 
         const TFieldList &fields = structure->fields();
 
         for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
         {
             TField *field = fields[fieldIndex];
-            traverse(*field->type(), field->name());
+            traverse(*field->type(), field->name(), &variable.fields);
         }
-
-        mOutputStack.pop();
     }
 
     visitVariable(&variable);
 
-    ASSERT(!mOutputStack.empty());
-    mOutputStack.top()->push_back(variable);
-}
-
-template <typename VarT>
-GetVariableTraverser<VarT>::GetVariableTraverser(std::vector<VarT> *output)
-{
     ASSERT(output);
-    mOutputStack.push(output);
+    output->push_back(variable);
 }
 
-template class GetVariableTraverser<Uniform>;
-template class GetVariableTraverser<Varying>;
-template class GetVariableTraverser<InterfaceBlockField>;
-
-GetInterfaceBlockFieldTraverser::GetInterfaceBlockFieldTraverser(std::vector<InterfaceBlockField> *output, bool isRowMajorMatrix)
-    : GetVariableTraverser(output),
-      mIsRowMajorMatrix(isRowMajorMatrix)
-{
-}
-
-void GetInterfaceBlockFieldTraverser::visitVariable(InterfaceBlockField *newField)
-{
-    if (gl::IsMatrixType(newField->type))
-    {
-        newField->isRowMajorMatrix = mIsRowMajorMatrix;
-    }
-}
+template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Uniform> *);
+template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Varying> *);
+template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<InterfaceBlockField> *);
 
 BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
 {
@@ -354,4 +331,33 @@
     }
 }
 
+static TString InterfaceBlockFieldName(const TInterfaceBlock &interfaceBlock, const TField &field)
+{
+    if (interfaceBlock.hasInstanceName())
+    {
+        return interfaceBlock.name() + "." + field.name();
+    }
+    else
+    {
+        return field.name();
+    }
+}
+
+void GetInterfaceBlockFields(const TInterfaceBlock &interfaceBlock, std::vector<InterfaceBlockField> *fieldsOut)
+{
+    const TFieldList &fieldList = interfaceBlock.fields();
+
+    for (size_t fieldIndex = 0; fieldIndex < fieldList.size(); ++fieldIndex)
+    {
+        const TField &field = *fieldList[fieldIndex];
+        const TString &fullFieldName = InterfaceBlockFieldName(interfaceBlock, field);
+        const TType &fieldType = *field.type();
+
+        GetVariableTraverser traverser;
+        traverser.traverse(fieldType, fullFieldName, fieldsOut);
+
+        fieldsOut->back().isRowMajorMatrix = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
+    }
+}
+
 }
diff --git a/src/compiler/translator/util.h b/src/compiler/translator/util.h
index 2c16a1d..6a39d56 100644
--- a/src/compiler/translator/util.h
+++ b/src/compiler/translator/util.h
@@ -36,31 +36,23 @@
 BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage);
 TString ArrayString(const TType &type);
 
-template <typename VarT>
 class GetVariableTraverser
 {
   public:
-    GetVariableTraverser(std::vector<VarT> *output);
-    void traverse(const TType &type, const TString &name);
+    GetVariableTraverser() {}
+
+    template <typename VarT>
+    void traverse(const TType &type, const TString &name, std::vector<VarT> *output);
 
   protected:
     // May be overloaded
-    virtual void visitVariable(VarT *newVar) {}
+    virtual void visitVariable(ShaderVariable *newVar) {}
 
   private:
-    std::stack<std::vector<VarT> *> mOutputStack;
+    DISALLOW_COPY_AND_ASSIGN(GetVariableTraverser);
 };
 
-struct GetInterfaceBlockFieldTraverser : public GetVariableTraverser<InterfaceBlockField>
-{
-  public:
-    GetInterfaceBlockFieldTraverser(std::vector<InterfaceBlockField> *output, bool isRowMajorMatrix);
-
-  private:
-    virtual void visitVariable(InterfaceBlockField *newField);
-
-    bool mIsRowMajorMatrix;
-};
+void GetInterfaceBlockFields(const TInterfaceBlock &interfaceBlock, std::vector<InterfaceBlockField> *fieldsOut);
 
 }
 
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index 4ec3f6c..5a667e8 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -1077,7 +1077,7 @@
             PackedVarying *output = &vertexVaryings[vertVaryingIndex];
             if (output->name == input->name)
             {
-                if (!linkValidateVariables(infoLog, output->name, *input, *output))
+                if (!linkValidateVaryings(infoLog, output->name, *input, *output))
                 {
                     return false;
                 }
@@ -1818,32 +1818,29 @@
         return false;
     }
 
-    return true;
-}
-
-template <class ShaderVarType>
-bool ProgramBinary::linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar)
-{
-    if (vertexVar.fields.size() != fragmentVar.fields.size())
+    if (vertexVariable.fields.size() != fragmentVariable.fields.size())
     {
-        infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", varName.c_str());
+        infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str());
         return false;
     }
-    const unsigned int numMembers = vertexVar.fields.size();
+    const unsigned int numMembers = vertexVariable.fields.size();
     for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
     {
-        const ShaderVarType &vertexMember = vertexVar.fields[memberIndex];
-        const ShaderVarType &fragmentMember = fragmentVar.fields[memberIndex];
+        const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
+        const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
 
         if (vertexMember.name != fragmentMember.name)
         {
             infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
-                           memberIndex, varName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
+                           memberIndex, variableName.c_str(),
+                           vertexMember.name.c_str(), fragmentMember.name.c_str());
             return false;
         }
 
-        const std::string memberName = varName.substr(0, varName.length()-1) + "." + vertexVar.name + "'";
-        if (!linkValidateVariables(infoLog, memberName, vertexMember, fragmentMember))
+        const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
+                                       vertexMember.name + "'";
+
+        if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
         {
             return false;
         }
@@ -1852,22 +1849,17 @@
     return true;
 }
 
-bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
+bool ProgramBinary::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
 {
     if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
     {
         return false;
     }
 
-    if (!linkValidateFields<sh::Uniform>(infoLog, uniformName, vertexUniform, fragmentUniform))
-    {
-        return false;
-    }
-
     return true;
 }
 
-bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
+bool ProgramBinary::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
 {
     if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
     {
@@ -1880,15 +1872,10 @@
         return false;
     }
 
-    if (!linkValidateFields<sh::Varying>(infoLog, varyingName, vertexVarying, fragmentVarying))
-    {
-        return false;
-    }
-
     return true;
 }
 
-bool ProgramBinary::linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
+bool ProgramBinary::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
 {
     if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
     {
@@ -1901,11 +1888,6 @@
         return false;
     }
 
-    if (!linkValidateFields<sh::InterfaceBlockField>(infoLog, uniformName, vertexUniform, fragmentUniform))
-    {
-        return false;
-    }
-
     return true;
 }
 
@@ -1932,7 +1914,7 @@
         {
             const sh::Uniform &vertexUniform = *entry->second;
             const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
-            if (!linkValidateVariables(infoLog, uniformName, vertexUniform, fragmentUniform))
+            if (!linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
             {
                 return false;
             }
@@ -1970,7 +1952,7 @@
     defineUniform(shader, uniform, uniform.name, &encoder);
 }
 
-void ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &uniform,
+void ProgramBinary::defineUniform(GLenum shader, const sh::ShaderVariable &uniform,
                                   const std::string &fullName, sh::HLSLBlockEncoder *encoder)
 {
     if (uniform.isStruct())
@@ -1983,7 +1965,7 @@
 
             for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
             {
-                const sh::Uniform &field = uniform.fields[fieldIndex];
+                const sh::ShaderVariable &field = uniform.fields[fieldIndex];
                 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
 
                 defineUniform(shader, field, fieldFullName, encoder);
@@ -2169,8 +2151,8 @@
             return false;
         }
 
-        std::string uniformName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
-        if (!linkValidateVariables(infoLog, uniformName, vertexMember, fragmentMember))
+        std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
+        if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
         {
             return false;
         }
@@ -2286,12 +2268,13 @@
     return true;
 }
 
-void ProgramBinary::defineUniformBlockMembers(const std::vector<sh::InterfaceBlockField> &fields, const std::string &prefix, int blockIndex,
+template <typename VarT>
+void ProgramBinary::defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
                                               sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes)
 {
     for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
     {
-        const sh::InterfaceBlockField &field = fields[uniformIndex];
+        const VarT &field = fields[uniformIndex];
         const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
 
         if (field.isStruct())
@@ -2308,7 +2291,7 @@
         }
         else
         {
-            sh::BlockMemberInfo memberInfo = encoder->encodeInterfaceBlockField(field);
+            sh::BlockMemberInfo memberInfo = encoder->encodeVariable(field);
 
             LinkedUniform *newUniform = new LinkedUniform(field.type, field.precision, fieldName, field.arraySize,
                                                           blockIndex, memberInfo);
diff --git a/src/libGLESv2/ProgramBinary.h b/src/libGLESv2/ProgramBinary.h
index ac46687..023b193 100644
--- a/src/libGLESv2/ProgramBinary.h
+++ b/src/libGLESv2/ProgramBinary.h
@@ -197,16 +197,18 @@
     bool linkVaryings(InfoLog &infoLog, FragmentShader *fragmentShader, VertexShader *vertexShader);
     bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader);
 
-    template <class ShaderVarType>
-    bool linkValidateFields(InfoLog &infoLog, const std::string &varName, const ShaderVarType &vertexVar, const ShaderVarType &fragmentVar);
-    bool linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, const sh::ShaderVariable &fragmentVariable, bool validatePrecision);
+    bool linkValidateVariablesBase(InfoLog &infoLog,
+                                   const std::string &variableName,
+                                   const sh::ShaderVariable &vertexVariable,
+                                   const sh::ShaderVariable &fragmentVariable,
+                                   bool validatePrecision);
 
-    bool linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform);
-    bool linkValidateVariables(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying);
-    bool linkValidateVariables(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform);
+    bool linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform);
+    bool linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying);
+    bool linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform);
     bool linkUniforms(InfoLog &infoLog, const VertexShader &vertexShader, const FragmentShader &fragmentShader);
     void defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister);
-    void defineUniform(GLenum shader, const sh::Uniform &uniform, const std::string &fullName, sh::HLSLBlockEncoder *encoder);
+    void defineUniform(GLenum shader, const sh::ShaderVariable &uniform, const std::string &fullName, sh::HLSLBlockEncoder *encoder);
     bool indexSamplerUniform(const LinkedUniform &uniform, InfoLog &infoLog);
     bool indexUniforms(InfoLog &infoLog);
     static bool assignSamplers(unsigned int startSamplerIndex, GLenum samplerType, unsigned int samplerCount,
@@ -217,7 +219,8 @@
                                                const std::vector<std::string> &transformFeedbackVaryingNames,
                                                GLenum transformFeedbackBufferMode,
                                                std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings) const;
-    void defineUniformBlockMembers(const std::vector<sh::InterfaceBlockField> &fields, const std::string &prefix, int blockIndex,
+    template <typename VarT>
+    void defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
                                    sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes);
     bool defineUniformBlock(InfoLog &infoLog, const Shader &shader, const sh::InterfaceBlock &interfaceBlock);
     bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex);