Store shader interface variables as per query spec

GLES 3.1 section 7.3.1.1 specifies how active variable entries should
be generated and how active variables are named. The specs for program
interface variable queries are built on top of this section.

ANGLE has already followed this spec for the most part for generating
variable lists in ProgramState, but now we also follow the naming spec
for arrays and include [0] at the end of the stored name.

This will make implementing arrays of arrays more straightforward.
Most logic for variable queries will just keep working as is when
arrays of arrays are added instead of needing more complex logic for
handling array indexing.

BUG=angleproject:2125
TEST=angle_end2end_tests

Change-Id: I3acd14253153e10bc312114b0303065da2efb506
Reviewed-on: https://chromium-review.googlesource.com/739826
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/libANGLE/UniformLinker.cpp b/src/libANGLE/UniformLinker.cpp
index 0cf2e7e..a14ac53 100644
--- a/src/libANGLE/UniformLinker.cpp
+++ b/src/libANGLE/UniformLinker.cpp
@@ -10,6 +10,7 @@
 
 #include "libANGLE/UniformLinker.h"
 
+#include "common/string_utils.h"
 #include "common/utilities.h"
 #include "libANGLE/Caps.h"
 #include "libANGLE/Context.h"
@@ -33,7 +34,21 @@
     return nullptr;
 }
 
-}  // anonymouse namespace
+int GetUniformLocationBinding(const Program::Bindings &uniformLocationBindings,
+                              const sh::Uniform &uniform)
+{
+    int binding = uniformLocationBindings.getBinding(uniform.name);
+    if (uniform.isArray() && binding == -1)
+    {
+        // Bindings for array uniforms can be set either with or without [0] in the end.
+        ASSERT(angle::EndsWith(uniform.name, "[0]"));
+        std::string nameWithoutIndex = uniform.name.substr(0u, uniform.name.length() - 3u);
+        return uniformLocationBindings.getBinding(nameWithoutIndex);
+    }
+    return binding;
+}
+
+}  // anonymous namespace
 
 UniformLinker::UniformLinker(const ProgramState &state) : mState(state)
 {
@@ -191,7 +206,7 @@
             continue;
         }
 
-        int preSetLocation = uniformLocationBindings.getBinding(uniform.name);
+        int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
         int shaderLocation = uniform.location;
 
         if (shaderLocation != -1)
@@ -264,7 +279,7 @@
             continue;
         }
 
-        int apiBoundLocation = uniformLocationBindings.getBinding(uniform.name);
+        int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
         int shaderLocation   = uniform.location;
 
         if (shaderLocation != -1)
@@ -518,7 +533,19 @@
     {
         uniformList = atomicCounterUniforms;
     }
-    LinkedUniform *existingUniform = FindUniform(*uniformList, fullName);
+
+    std::string fullNameWithArrayIndex(fullName);
+    std::string fullMappedNameWithArrayIndex(fullMappedName);
+
+    if (uniform.isArray())
+    {
+        // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
+        // and including [0] at the end of array variable names.
+        fullNameWithArrayIndex += "[0]";
+        fullMappedNameWithArrayIndex += "[0]";
+    }
+
+    LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
     if (existingUniform)
     {
         if (binding != -1)
@@ -541,10 +568,10 @@
     }
     else
     {
-        LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
-                                    binding, offset, *location, -1,
+        LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
+                                    uniform.arraySize, binding, offset, *location, -1,
                                     sh::BlockMemberInfo::getDefaultBlockInfo());
-        linkedUniform.mappedName = fullMappedName;
+        linkedUniform.mappedName = fullMappedNameWithArrayIndex;
         linkedUniform.staticUse = markStaticUse;
         if (markStaticUse)
         {