Add support for specifying locations of vertex inputs using layout qualifiers, for GLSL ES 3.00.

TRAC #23269

Signed-off-by: Geoff Lang
Signed-off-by: Nicolas Capens
Authored-by: Jamie Madill
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index 34cec04..2f91591 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -2074,18 +2074,11 @@
     for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
     {
         const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
-        const int location = attributeBindings.getAttributeBinding(attribute.name);
+        const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
 
-        if (location != -1)   // Set by glBindAttribLocation
+        if (location != -1)   // Set by glBindAttribLocation or by location layout qualifier
         {
-            if (!mLinkedAttribute[location].name.empty())
-            {
-                // Multiple active attributes bound to the same location; not an error
-            }
-
-            mLinkedAttribute[location] = attribute;
-
-            int rows = AttributeRegisterCount(attribute.type);
+            const int rows = AttributeRegisterCount(attribute.type);
 
             if (rows + location > MAX_VERTEX_ATTRIBS)
             {
@@ -2094,9 +2087,24 @@
                 return false;
             }
 
-            for (int i = 0; i < rows; i++)
+            for (int row = 0; row < rows; row++)
             {
-                usedLocations |= 1 << (location + i);
+                const int rowLocation = location + row;
+                sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
+
+                // In GLSL 3.00, attribute aliasing produces a link error
+                // In GLSL 1.00, attribute aliasing is allowed
+                if (mShaderVersion >= 300)
+                {
+                    if (!linkedAttribute.name.empty())
+                    {
+                        infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
+                        return false;
+                    }
+                }
+
+                linkedAttribute = attribute;
+                usedLocations |= 1 << rowLocation;
             }
         }
     }
@@ -2105,9 +2113,9 @@
     for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
     {
         const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
-        int location = attributeBindings.getAttributeBinding(attribute.name);
+        const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
 
-        if (location == -1)   // Not set by glBindAttribLocation
+        if (location == -1)   // Not set by glBindAttribLocation or by location layout qualifier
         {
             int rows = AttributeRegisterCount(attribute.type);
             int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);