Re-land "Move shader attributes into Program shared data."

Re-land with a fix for a warning in 32-bit Windows.

Making the Program own the attribs, and the Impl only see a read-only
copy cleans up the Impl object. It also allows us to more cleanly
isolate certain coded into D3D.

BUG=angleproject:1123

Change-Id: I73bda4b6d9e675d87d087d44757c598437d607f2
Reviewed-on: https://chromium-review.googlesource.com/295191
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index cea9df1..7c6b8c3 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -163,7 +163,6 @@
 
 Program::Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle)
     : mProgram(factory->createProgram(mData)),
-      mLinkedAttributes(gl::MAX_VERTEX_ATTRIBS),
       mValidated(false),
       mLinked(false),
       mDeleteStatus(false),
@@ -356,7 +355,7 @@
         }
     }
 
-    mLinkedAttributes.assign(mLinkedAttributes.size(), sh::Attribute());
+    mData.mAttributes.clear();
     mData.mTransformFeedbackVaryingVars.clear();
 
     mProgram->reset();
@@ -408,20 +407,21 @@
     // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
     for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
     {
-        stream.readInt(&mLinkedAttributes[i].type);
-        stream.readString(&mLinkedAttributes[i].name);
         stream.readInt(&mProgram->getSemanticIndexes()[i]);
     }
 
     unsigned int attribCount = stream.readInt<unsigned int>();
+    ASSERT(mData.mAttributes.empty());
     for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
     {
-        GLenum type = stream.readInt<GLenum>();
-        GLenum precision = stream.readInt<GLenum>();
-        std::string name = stream.readString();
-        GLint arraySize = stream.readInt<GLint>();
-        int location = stream.readInt<int>();
-        mProgram->setShaderAttribute(attribIndex, type, precision, name, arraySize, location);
+        sh::Attribute attrib;
+        attrib.type      = stream.readInt<GLenum>();
+        attrib.precision = stream.readInt<GLenum>();
+        attrib.name      = stream.readString();
+        attrib.arraySize = stream.readInt<GLint>();
+        attrib.location  = stream.readInt<int>();
+        attrib.staticUse = stream.readBool();
+        mData.mAttributes.push_back(attrib);
     }
 
     stream.readInt(&mData.mTransformFeedbackBufferMode);
@@ -454,20 +454,18 @@
     // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
     for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
     {
-        stream.writeInt(mLinkedAttributes[i].type);
-        stream.writeString(mLinkedAttributes[i].name);
         stream.writeInt(mProgram->getSemanticIndexes()[i]);
     }
 
-    const auto &shaderAttributes = mProgram->getShaderAttributes();
-    stream.writeInt(shaderAttributes.size());
-    for (const auto &attrib : shaderAttributes)
+    stream.writeInt(mData.mAttributes.size());
+    for (const sh::Attribute &attrib : mData.mAttributes)
     {
         stream.writeInt(attrib.type);
         stream.writeInt(attrib.precision);
         stream.writeString(attrib.name);
         stream.writeInt(attrib.arraySize);
         stream.writeInt(attrib.location);
+        stream.writeInt(attrib.staticUse);
     }
 
     stream.writeInt(mData.mTransformFeedbackBufferMode);
@@ -586,11 +584,11 @@
 
 GLuint Program::getAttributeLocation(const std::string &name)
 {
-    for (size_t index = 0; index < mLinkedAttributes.size(); index++)
+    for (const sh::Attribute &attribute : mData.mAttributes)
     {
-        if (mLinkedAttributes[index].name == name)
+        if (attribute.name == name && attribute.staticUse)
         {
-            return static_cast<GLuint>(index);
+            return attribute.location;
         }
     }
 
@@ -611,45 +609,7 @@
 
 void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
 {
-    if (mLinked)
-    {
-        // Skip over inactive attributes
-        unsigned int activeAttribute = 0;
-        unsigned int attribute;
-        for (attribute = 0; attribute < static_cast<unsigned int>(mLinkedAttributes.size());
-             attribute++)
-        {
-            if (mLinkedAttributes[attribute].name.empty())
-            {
-                continue;
-            }
-
-            if (activeAttribute == index)
-            {
-                break;
-            }
-
-            activeAttribute++;
-        }
-
-        if (bufsize > 0)
-        {
-            const char *string = mLinkedAttributes[attribute].name.c_str();
-
-            strncpy(name, string, bufsize);
-            name[bufsize - 1] = '\0';
-
-            if (length)
-            {
-                *length = static_cast<GLsizei>(strlen(name));
-            }
-        }
-
-        *size = 1;   // Always a single 'type' instance
-
-        *type = mLinkedAttributes[attribute].type;
-    }
-    else
+    if (!mLinked)
     {
         if (bufsize > 0)
         {
@@ -663,22 +623,57 @@
 
         *type = GL_NONE;
         *size = 1;
+        return;
     }
+
+    size_t attributeIndex = 0;
+
+    for (const sh::Attribute &attribute : mData.mAttributes)
+    {
+        // Skip over inactive attributes
+        if (attribute.staticUse)
+        {
+            if (static_cast<size_t>(index) == attributeIndex)
+            {
+                break;
+            }
+            attributeIndex++;
+        }
+    }
+
+    ASSERT(index == attributeIndex && attributeIndex < mData.mAttributes.size());
+    const sh::Attribute &attrib = mData.mAttributes[attributeIndex];
+
+    if (bufsize > 0)
+    {
+        const char *string = attrib.name.c_str();
+
+        strncpy(name, string, bufsize);
+        name[bufsize - 1] = '\0';
+
+        if (length)
+        {
+            *length = static_cast<GLsizei>(strlen(name));
+        }
+    }
+
+    // Always a single 'type' instance
+    *size = 1;
+    *type = attrib.type;
 }
 
 GLint Program::getActiveAttributeCount()
 {
-    int count = 0;
-
-    if (mLinked)
+    if (!mLinked)
     {
-        for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
-        {
-            if (!mLinkedAttributes[attributeIndex].name.empty())
-            {
-                count++;
-            }
-        }
+        return 0;
+    }
+
+    GLint count = 0;
+
+    for (const sh::Attribute &attrib : mData.mAttributes)
+    {
+        count += (attrib.staticUse ? 1 : 0);
     }
 
     return count;
@@ -686,22 +681,22 @@
 
 GLint Program::getActiveAttributeMaxLength()
 {
-    GLint maxLength = 0;
-
-    if (mLinked)
+    if (!mLinked)
     {
-        for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+        return 0;
+    }
+
+    size_t maxLength = 0;
+
+    for (const sh::Attribute &attrib : mData.mAttributes)
+    {
+        if (attrib.staticUse)
         {
-            if (!mLinkedAttributes[attributeIndex].name.empty())
-            {
-                maxLength = std::max(
-                    static_cast<GLint>(mLinkedAttributes[attributeIndex].name.length() + 1),
-                    maxLength);
-            }
+            maxLength = std::max(attrib.name.length() + 1, maxLength);
         }
     }
 
-    return maxLength;
+    return static_cast<GLint>(maxLength);
 }
 
 GLint Program::getFragDataLocation(const std::string &name) const
@@ -1292,73 +1287,77 @@
                              const Shader *vertexShader)
 {
     unsigned int usedLocations = 0;
-    const std::vector<sh::Attribute> &shaderAttributes = vertexShader->getActiveAttributes();
+    mData.mAttributes          = vertexShader->getActiveAttributes();
     GLuint maxAttribs = data.caps->maxVertexAttributes;
 
     // TODO(jmadill): handle aliasing robustly
-    if (shaderAttributes.size() > maxAttribs)
+    if (mData.mAttributes.size() > maxAttribs)
     {
         infoLog << "Too many vertex attributes.";
         return false;
     }
 
-    // Link attributes that have a binding location
-    for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
-    {
-        const sh::Attribute &attribute = shaderAttributes[attributeIndex];
+    std::vector<sh::Attribute *> usedAttribMap(data.caps->maxVertexAttributes, nullptr);
 
+    // Link attributes that have a binding location
+    for (sh::Attribute &attribute : mData.mAttributes)
+    {
+        // TODO(jmadill): do staticUse filtering step here, or not at all
         ASSERT(attribute.staticUse);
 
-        const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
-
-        mProgram->setShaderAttribute(attributeIndex, attribute);
-
-        if (location != -1)   // Set by glBindAttribLocation or by location layout qualifier
+        int bindingLocation = attributeBindings.getAttributeBinding(attribute.name);
+        if (attribute.location == -1 && bindingLocation != -1)
         {
+            attribute.location = bindingLocation;
+        }
+
+        if (attribute.location != -1)
+        {
+            // Location is set by glBindAttribLocation or by location layout qualifier
             const int rows = VariableRegisterCount(attribute.type);
 
-            if (static_cast<GLuint>(rows + location) > maxAttribs)
+            if (static_cast<GLuint>(rows + attribute.location) > maxAttribs)
             {
                 infoLog << "Active attribute (" << attribute.name << ") at location "
-                        << location << " is too big to fit";
+                        << attribute.location << " is too big to fit";
 
                 return false;
             }
 
             for (int row = 0; row < rows; row++)
             {
-                const int rowLocation = location + row;
-                sh::ShaderVariable *linkedAttribute = &mLinkedAttributes[rowLocation];
+                const int rowLocation               = attribute.location + row;
+                sh::ShaderVariable *linkedAttribute = usedAttribMap[rowLocation];
 
                 // In GLSL 3.00, attribute aliasing produces a link error
                 // In GLSL 1.00, attribute aliasing is allowed, but ANGLE currently has a bug
-                // TODO(jmadill): fix aliasing on ES2
-                // if (mProgram->getShaderVersion() >= 300)
+                if (linkedAttribute)
                 {
-                    if (!linkedAttribute->name.empty())
+                    // TODO(jmadill): fix aliasing on ES2
+                    // if (mProgram->getShaderVersion() >= 300)
                     {
                         infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
                                 << linkedAttribute->name << "' at location " << rowLocation;
                         return false;
                     }
                 }
+                else
+                {
+                    usedAttribMap[rowLocation] = &attribute;
+                }
 
-                *linkedAttribute = attribute;
                 usedLocations |= 1 << rowLocation;
             }
         }
     }
 
     // Link attributes that don't have a binding location
-    for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
+    for (sh::Attribute &attribute : mData.mAttributes)
     {
-        const sh::Attribute &attribute = shaderAttributes[attributeIndex];
-
         ASSERT(attribute.staticUse);
 
-        const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
-
-        if (location == -1)   // Not set by glBindAttribLocation or by location layout qualifier
+        // Not set by glBindAttribLocation or by location layout qualifier
+        if (attribute.location == -1)
         {
             int rows = VariableRegisterCount(attribute.type);
             int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, maxAttribs);
@@ -1366,17 +1365,21 @@
             if (availableIndex == -1 || static_cast<GLuint>(availableIndex + rows) > maxAttribs)
             {
                 infoLog << "Too many active attributes (" << attribute.name << ")";
-                return false;   // Fail to link
+                return false;
             }
 
-            mLinkedAttributes[availableIndex] = attribute;
+            attribute.location = availableIndex;
         }
     }
 
-    for (GLuint attributeIndex = 0; attributeIndex < maxAttribs;)
+    // TODO(jmadill): make semantic index D3D-only
+    for (const sh::Attribute &attribute : mData.mAttributes)
     {
-        int index = vertexShader->getSemanticIndex(mLinkedAttributes[attributeIndex].name);
-        int rows  = VariableRegisterCount(mLinkedAttributes[attributeIndex].type);
+        ASSERT(attribute.staticUse);
+
+        unsigned int attributeIndex = attribute.location;
+        int index                   = vertexShader->getSemanticIndex(attribute.name);
+        int rows                    = VariableRegisterCount(attribute.type);
 
         for (int r = 0; r < rows; r++)
         {