Fix arrays-of-struct and nested struct uniforms.

Our computation of register offsets had a few errors that
messed up nested structs and arrays of structs.

This fixes a WebGL test, as well as several dEQP tests.

BUG=angle:505
TEST=WebGL CTS 1.0.3, dEQP-GELS3.functional.uniform-api

Change-Id: Id5a0f39481e079fe5ef5ef856943dc1f91ee3639
Reviewed-on: https://chromium-review.googlesource.com/200045
Reviewed-by: Nicolas Capens <nicolascapens@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index cecb94d..cf76407 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -24,6 +24,7 @@
 #include "libGLESv2/Context.h"
 #include "libGLESv2/Buffer.h"
 #include "libGLESv2/DynamicHLSL.h"
+#include "common/blocklayout.h"
 
 #undef near
 #undef far
@@ -1810,25 +1811,6 @@
     return true;
 }
 
-int totalRegisterCount(const gl::Uniform &uniform)
-{
-    int registerCount = 0;
-
-    if (!uniform.fields.empty())
-    {
-        for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
-        {
-            registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
-        }
-    }
-    else
-    {
-        registerCount = 1;
-    }
-
-    return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
-}
-
 TextureType ProgramBinary::getTextureType(GLenum samplerType, InfoLog &infoLog)
 {
     switch(samplerType)
@@ -1865,23 +1847,25 @@
     {
         if (constant.arraySize > 0)
         {
-            unsigned int elementRegisterIndex = constant.registerIndex;
+            const unsigned int elementRegisterCount = HLSLVariableRegisterCount(constant) / constant.arraySize;
 
             for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
             {
+                const unsigned int elementRegisterOffset = elementRegisterCount * elementIndex;
+
                 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
                 {
                     const gl::Uniform &field = constant.fields[fieldIndex];
                     const std::string &uniformName = constant.name + ArrayString(elementIndex) + "." + field.name;
+                    const unsigned int fieldRegisterIndex = field.registerIndex + elementRegisterOffset;
                     gl::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize,
-                                             elementRegisterIndex, field.elementIndex);
+                                             fieldRegisterIndex, field.elementIndex);
 
                     fieldUniform.fields = field.fields;
                     if (!defineUniform(shader, fieldUniform, infoLog))
                     {
                         return false;
                     }
-                    elementRegisterIndex += totalRegisterCount(field);
                 }
             }
         }