Use the block encoder class to store uniform offsets.

This will allow us to use the same code path for assigning register
information in all places. Because of this it fixes some long-broken
dEQP struct uniform tests.

BUG=angle:466
BUG=angle:505

Change-Id: I4161a388503aa09bbe2d21ff47bfb3352ec93881
Reviewed-on: https://chromium-review.googlesource.com/207255
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Nicolas Capens <capn@chromium.org>
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index a57cabd..50bae23 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -1648,7 +1648,7 @@
         success = false;
     }
 
-    if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
+    if (!linkUniforms(infoLog, *vertexShader, *fragmentShader))
     {
         success = false;
     }
@@ -1900,8 +1900,11 @@
     return true;
 }
 
-bool ProgramBinary::linkUniforms(InfoLog &infoLog, const std::vector<sh::Uniform> &vertexUniforms, const std::vector<sh::Uniform> &fragmentUniforms)
+bool ProgramBinary::linkUniforms(InfoLog &infoLog, const VertexShader &vertexShader, const FragmentShader &fragmentShader)
 {
+    const std::vector<sh::Uniform> &vertexUniforms = vertexShader.getUniforms();
+    const std::vector<sh::Uniform> &fragmentUniforms = fragmentShader.getUniforms();
+
     // Check that uniforms defined in the vertex and fragment shaders are identical
     typedef std::map<std::string, const sh::Uniform*> UniformMap;
     UniformMap linkedUniforms;
@@ -1929,12 +1932,14 @@
 
     for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
     {
-        defineUniformBase(GL_VERTEX_SHADER, vertexUniforms[uniformIndex]);
+        const sh::Uniform &uniform = vertexUniforms[uniformIndex];
+        defineUniformBase(GL_VERTEX_SHADER, uniform, vertexShader.getUniformRegister(uniform.name));
     }
 
     for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
     {
-        defineUniformBase(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex]);
+        const sh::Uniform &uniform = fragmentUniforms[uniformIndex];
+        defineUniformBase(GL_FRAGMENT_SHADER, uniform, fragmentShader.getUniformRegister(uniform.name));
     }
 
     if (!indexUniforms(infoLog))
@@ -1947,46 +1952,45 @@
     return true;
 }
 
-void ProgramBinary::defineUniformBase(GLenum shader, const sh::Uniform &uniform)
+void ProgramBinary::defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister)
 {
-    defineUniform(shader, uniform, uniform.name, uniform.registerIndex);
+    ShShaderOutput outputType = Shader::getCompilerOutputType(shader);
+    sh::HLSLBlockEncoder encoder(outputType);
+    encoder.skipRegisters(uniformRegister);
+
+    defineUniform(shader, uniform, uniform.name, &encoder);
 }
 
 void ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &uniform,
-                                  const std::string &fullName, unsigned int baseRegisterIndex)
+                                  const std::string &fullName, sh::HLSLBlockEncoder *encoder)
 {
     if (uniform.isStruct())
     {
-        if (uniform.arraySize > 0)
+        for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
         {
-            ShShaderOutput outputType = Shader::getCompilerOutputType(shader);
-            const unsigned int elementRegisterCount = HLSLVariableRegisterCount(uniform, outputType) / uniform.arraySize;
+            const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
 
-            for (unsigned int elementIndex = 0; elementIndex < uniform.arraySize; elementIndex++)
-            {
-                const unsigned int elementRegisterOffset = elementRegisterCount * elementIndex;
+            encoder->enterAggregateType();
 
-                for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
-                {
-                    const sh::Uniform &field = uniform.fields[fieldIndex];
-                    const std::string &fieldFullName = fullName + ArrayString(elementIndex) + "." + field.name;
-                    const unsigned int fieldRegisterIndex = field.registerIndex + elementRegisterOffset;
-                    defineUniform(shader, field, fieldFullName, fieldRegisterIndex);
-                }
-            }
-        }
-        else
-        {
             for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
             {
                 const sh::Uniform &field = uniform.fields[fieldIndex];
-                const std::string &fieldFullName = fullName + "." + field.name;
-                defineUniform(shader, field, fieldFullName, field.registerIndex);
+                const std::string &fieldFullName = (fullName + elementString + "." + field.name);
+
+                defineUniform(shader, field, fieldFullName, encoder);
             }
+
+            encoder->exitAggregateType();
         }
     }
     else // Not a struct
     {
+        // Arrays are treated as aggregate types
+        if (uniform.isArray())
+        {
+            encoder->enterAggregateType();
+        }
+
         LinkedUniform *linkedUniform = getUniformByName(fullName);
 
         if (!linkedUniform)
@@ -1994,19 +1998,30 @@
             linkedUniform = new LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
                                               -1, sh::BlockMemberInfo::getDefaultBlockInfo());
             ASSERT(linkedUniform);
-            linkedUniform->registerElement = uniform.elementIndex;
+            linkedUniform->registerElement = encoder->getCurrentElement();
             mUniforms.push_back(linkedUniform);
         }
 
+        ASSERT(linkedUniform->registerElement == encoder->getCurrentElement());
+
         if (shader == GL_FRAGMENT_SHADER)
         {
-            linkedUniform->psRegisterIndex = baseRegisterIndex;
+            linkedUniform->psRegisterIndex = encoder->getCurrentRegister();
         }
         else if (shader == GL_VERTEX_SHADER)
         {
-            linkedUniform->vsRegisterIndex = baseRegisterIndex;
+            linkedUniform->vsRegisterIndex = encoder->getCurrentRegister();
         }
         else UNREACHABLE();
+
+        // Advance the uniform offset, to track registers allocation for structs
+        encoder->encodeType(uniform.type, uniform.arraySize, false);
+
+        // Arrays are treated as aggregate types
+        if (uniform.isArray())
+        {
+            encoder->exitAggregateType();
+        }
     }
 }