Fix row-major layout tracking in interface blocks.

Some block field types, such as nested structs, were bugged. This
only affects our "CollectVariables" path, not our current HLSL
UBO path.

BUG=angle:466

Change-Id: I2b8daf58aa7ec1ad06a80d38f57e76087eacccdc
Reviewed-on: https://chromium-review.googlesource.com/213503
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Nicolas Capens <capn@chromium.org>
diff --git a/src/common/blocklayout.cpp b/src/common/blocklayout.cpp
index 2aa776f..e3b2d43 100644
--- a/src/common/blocklayout.cpp
+++ b/src/common/blocklayout.cpp
@@ -15,62 +15,11 @@
 {
 
 BlockLayoutEncoder::BlockLayoutEncoder()
-    : mCurrentOffset(0),
-      mInRowMajorField(false)
+    : mCurrentOffset(0)
 {
 }
 
-template <typename VarT>
-void BlockLayoutEncoder::encodeVariables(const std::vector<VarT> &fields)
-{
-    for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
-    {
-        const VarT &variable = fields[fieldIndex];
-
-        if (variable.fields.size() > 0)
-        {
-            const unsigned int elementCount = std::max(1u, variable.arraySize);
-
-            for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
-            {
-                enterAggregateType();
-                encodeVariables(variable.fields);
-                exitAggregateType();
-            }
-        }
-        else
-        {
-            encodeVariable(variable);
-        }
-    }
-}
-
-// 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, mInRowMajorField, &arrayStride, &matrixStride);
-
-    const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, mInRowMajorField);
-
-    advanceOffset(field.type, field.arraySize, mInRowMajorField, arrayStride, matrixStride);
-
-    return memberInfo;
-}
-
-void BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix)
+BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix)
 {
     int arrayStride;
     int matrixStride;
@@ -80,6 +29,8 @@
     const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, isRowMajorMatrix);
 
     advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride);
+
+    return memberInfo;
 }
 
 void BlockLayoutEncoder::nextRegister()
diff --git a/src/common/blocklayout.h b/src/common/blocklayout.h
index e8824fd..d46ac6e 100644
--- a/src/common/blocklayout.h
+++ b/src/common/blocklayout.h
@@ -49,13 +49,7 @@
   public:
     BlockLayoutEncoder();
 
-    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);
+    BlockMemberInfo encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix);
 
     size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; }
     size_t getCurrentRegister() const { return mCurrentOffset / ComponentsPerRegister; }
@@ -69,7 +63,6 @@
 
   protected:
     size_t mCurrentOffset;
-    bool mInRowMajorField;
 
     void nextRegister();
 
diff --git a/src/compiler/translator/ShaderVars.cpp b/src/compiler/translator/ShaderVars.cpp
index 90f3bd0..822c558 100644
--- a/src/compiler/translator/ShaderVars.cpp
+++ b/src/compiler/translator/ShaderVars.cpp
@@ -89,7 +89,7 @@
 }
 
 InterfaceBlockField::InterfaceBlockField()
-    : isRowMajorMatrix(false)
+    : isRowMajorLayout(false)
 {}
 
 InterfaceBlockField::~InterfaceBlockField()
@@ -97,13 +97,13 @@
 
 InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other)
     : ShaderVariable(other),
-      isRowMajorMatrix(other.isRowMajorMatrix)
+      isRowMajorLayout(other.isRowMajorLayout)
 {}
 
 InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other)
 {
     ShaderVariable::operator=(other);
-    isRowMajorMatrix = other.isRowMajorMatrix;
+    isRowMajorLayout = other.isRowMajorLayout;
     return *this;
 }
 
diff --git a/src/compiler/translator/VariableInfo.cpp b/src/compiler/translator/VariableInfo.cpp
index 9d0c4c8..b023c29 100644
--- a/src/compiler/translator/VariableInfo.cpp
+++ b/src/compiler/translator/VariableInfo.cpp
@@ -272,6 +272,7 @@
     interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
     interfaceBlock.layout = sh::GetBlockLayoutType(blockType->blockStorage());
 
+    // Gather field information
     sh::GetInterfaceBlockFields(*blockType, &interfaceBlock.fields);
 
     infoList->push_back(interfaceBlock);
@@ -356,13 +357,14 @@
 {
     if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
     {
-        TIntermSymbol *symbol = binaryNode->getLeft()->getAsSymbolNode();
-        ASSERT(symbol);
+        // NOTE: we do not determine static use for individual blocks of an array
+        TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
+        ASSERT(blockNode);
 
         TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
         ASSERT(constantUnion);
 
-        const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
+        const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
         sh::InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
         ASSERT(namedBlock);
         namedBlock->staticUse = true;
diff --git a/src/compiler/translator/util.cpp b/src/compiler/translator/util.cpp
index 8684a13..40c90d8 100644
--- a/src/compiler/translator/util.cpp
+++ b/src/compiler/translator/util.cpp
@@ -356,7 +356,7 @@
         GetVariableTraverser traverser;
         traverser.traverse(fieldType, fullFieldName, fieldsOut);
 
-        fieldsOut->back().isRowMajorMatrix = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
+        fieldsOut->back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
     }
 }
 
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index 06d0265..bffdcb0 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -110,6 +110,16 @@
     }
 }
 
+bool IsRowMajorLayout(const sh::InterfaceBlockField &var)
+{
+    return var.isRowMajorLayout;
+}
+
+bool IsRowMajorLayout(const sh::ShaderVariable &var)
+{
+    return false;
+}
+
 }
 
 VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
@@ -1879,7 +1889,7 @@
         return false;
     }
 
-    if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix)
+    if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
     {
         infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
         return false;
@@ -2273,7 +2283,8 @@
 
 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)
+                                              sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes,
+                                              bool inRowMajorLayout)
 {
     for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
     {
@@ -2282,19 +2293,23 @@
 
         if (field.isStruct())
         {
+            bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
+
             for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
             {
                 encoder->enterAggregateType();
 
                 const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
-                defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes);
+                defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes, rowMajorLayout);
 
                 encoder->exitAggregateType();
             }
         }
         else
         {
-            sh::BlockMemberInfo memberInfo = encoder->encodeVariable(field);
+            bool isRowMajorMatrix = (IsMatrixType(field.type) && inRowMajorLayout);
+
+            sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix);
 
             LinkedUniform *newUniform = new LinkedUniform(field.type, field.precision, fieldName, field.arraySize,
                                                           blockIndex, memberInfo);
@@ -2329,7 +2344,7 @@
         }
         ASSERT(encoder);
 
-        defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes);
+        defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes, interfaceBlock.isRowMajorLayout);
 
         size_t dataSize = encoder->getBlockSize();
 
diff --git a/src/libGLESv2/ProgramBinary.h b/src/libGLESv2/ProgramBinary.h
index 770ce41..c3c55c2 100644
--- a/src/libGLESv2/ProgramBinary.h
+++ b/src/libGLESv2/ProgramBinary.h
@@ -221,7 +221,8 @@
                                                std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings) const;
     template <typename VarT>
     void defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
-                                   sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes);
+                                   sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes,
+                                   bool inRowMajorLayout);
     bool defineUniformBlock(InfoLog &infoLog, const Shader &shader, const sh::InterfaceBlock &interfaceBlock);
     bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex);
     void defineOutputVariables(FragmentShader *fragmentShader);