Add a Program::Data shared state structure.

Similar to the Framebuffer and other classes, this gives the Impl
class a read-only view of the object's state.

BUG=angleproject:1123

Change-Id: I580eaebe2de236adf8131d6e3f54633cecce8c25
Reviewed-on: https://chromium-review.googlesource.com/293760
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index cecb777..38ade23 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -141,13 +141,31 @@
 {
 }
 
-Program::Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle)
-    : mProgram(impl),
-      mValidated(false),
-      mFragmentShader(nullptr),
-      mVertexShader(nullptr),
+Program::Data::Data()
+    : mAttachedFragmentShader(nullptr),
+      mAttachedVertexShader(nullptr),
       mTransformFeedbackVaryings(),
-      mTransformFeedbackBufferMode(GL_NONE),
+      mTransformFeedbackBufferMode(GL_NONE)
+{
+}
+
+Program::Data::~Data()
+{
+    if (mAttachedVertexShader != nullptr)
+    {
+        mAttachedVertexShader->release();
+    }
+
+    if (mAttachedFragmentShader != nullptr)
+    {
+        mAttachedFragmentShader->release();
+    }
+}
+
+Program::Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle)
+    : mProgram(factory->createProgram(mData)),
+      mLinkedAttributes(gl::MAX_VERTEX_ATTRIBS),
+      mValidated(false),
       mLinked(false),
       mDeleteStatus(false),
       mRefCount(0),
@@ -164,16 +182,6 @@
 {
     unlink(true);
 
-    if (mVertexShader != nullptr)
-    {
-        mVertexShader->release();
-    }
-
-    if (mFragmentShader != nullptr)
-    {
-        mFragmentShader->release();
-    }
-
     SafeDelete(mProgram);
 }
 
@@ -181,23 +189,23 @@
 {
     if (shader->getType() == GL_VERTEX_SHADER)
     {
-        if (mVertexShader)
+        if (mData.mAttachedVertexShader)
         {
             return false;
         }
 
-        mVertexShader = shader;
-        mVertexShader->addRef();
+        mData.mAttachedVertexShader = shader;
+        mData.mAttachedVertexShader->addRef();
     }
     else if (shader->getType() == GL_FRAGMENT_SHADER)
     {
-        if (mFragmentShader)
+        if (mData.mAttachedFragmentShader)
         {
             return false;
         }
 
-        mFragmentShader = shader;
-        mFragmentShader->addRef();
+        mData.mAttachedFragmentShader = shader;
+        mData.mAttachedFragmentShader->addRef();
     }
     else UNREACHABLE();
 
@@ -208,23 +216,23 @@
 {
     if (shader->getType() == GL_VERTEX_SHADER)
     {
-        if (mVertexShader != shader)
+        if (mData.mAttachedVertexShader != shader)
         {
             return false;
         }
 
-        mVertexShader->release();
-        mVertexShader = nullptr;
+        shader->release();
+        mData.mAttachedVertexShader = nullptr;
     }
     else if (shader->getType() == GL_FRAGMENT_SHADER)
     {
-        if (mFragmentShader != shader)
+        if (mData.mAttachedFragmentShader != shader)
         {
             return false;
         }
 
-        mFragmentShader->release();
-        mFragmentShader = nullptr;
+        shader->release();
+        mData.mAttachedFragmentShader = nullptr;
     }
     else UNREACHABLE();
 
@@ -233,7 +241,7 @@
 
 int Program::getAttachedShadersCount() const
 {
-    return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
+    return (mData.mAttachedVertexShader ? 1 : 0) + (mData.mAttachedFragmentShader ? 1 : 0);
 }
 
 void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
@@ -258,58 +266,64 @@
 // Links the HLSL code of the vertex and pixel shader by matching up their varyings,
 // compiling them into binaries, determining the attribute mappings, and collecting
 // a list of uniforms
-Error Program::link(const Data &data)
+Error Program::link(const gl::Data &data)
 {
     unlink(false);
 
     mInfoLog.reset();
     resetUniformBlockBindings();
 
-    if (!mFragmentShader || !mFragmentShader->isCompiled())
+    if (!mData.mAttachedFragmentShader || !mData.mAttachedFragmentShader->isCompiled())
     {
         return Error(GL_NO_ERROR);
     }
-    ASSERT(mFragmentShader->getType() == GL_FRAGMENT_SHADER);
+    ASSERT(mData.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER);
 
-    if (!mVertexShader || !mVertexShader->isCompiled())
+    if (!mData.mAttachedVertexShader || !mData.mAttachedVertexShader->isCompiled())
     {
         return Error(GL_NO_ERROR);
     }
-    ASSERT(mVertexShader->getType() == GL_VERTEX_SHADER);
+    ASSERT(mData.mAttachedVertexShader->getType() == GL_VERTEX_SHADER);
 
-    if (!linkAttributes(data, mInfoLog, mAttributeBindings, mVertexShader))
+    if (!linkAttributes(data, mInfoLog, mAttributeBindings, mData.mAttachedVertexShader))
     {
         return Error(GL_NO_ERROR);
     }
 
     int registers;
     std::vector<LinkedVarying> linkedVaryings;
-    rx::LinkResult result = mProgram->link(data, mInfoLog, mFragmentShader, mVertexShader, mTransformFeedbackVaryings, mTransformFeedbackBufferMode,
-                                           &registers, &linkedVaryings, &mOutputVariables);
+    rx::LinkResult result =
+        mProgram->link(data, mInfoLog, mData.mAttachedFragmentShader, mData.mAttachedVertexShader,
+                       mData.mTransformFeedbackVaryings, mData.mTransformFeedbackBufferMode,
+                       &registers, &linkedVaryings, &mOutputVariables);
     if (result.error.isError() || !result.linkSuccess)
     {
         return result.error;
     }
 
-    if (!mProgram->linkUniforms(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
+    if (!mProgram->linkUniforms(mInfoLog, *mData.mAttachedVertexShader,
+                                *mData.mAttachedFragmentShader, *data.caps))
     {
         return Error(GL_NO_ERROR);
     }
 
-    if (!linkUniformBlocks(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
+    if (!linkUniformBlocks(mInfoLog, *mData.mAttachedVertexShader, *mData.mAttachedFragmentShader,
+                           *data.caps))
     {
         return Error(GL_NO_ERROR);
     }
 
-    if (!gatherTransformFeedbackLinkedVaryings(mInfoLog, linkedVaryings, mTransformFeedbackVaryings,
-                                               mTransformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps))
+    if (!gatherTransformFeedbackLinkedVaryings(
+            mInfoLog, linkedVaryings, mData.mTransformFeedbackVaryings,
+            mData.mTransformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(),
+            *data.caps))
     {
         return Error(GL_NO_ERROR);
     }
 
     // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called,
     // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling.
-    result = mProgram->compileProgramExecutables(mInfoLog, mFragmentShader, mVertexShader, registers);
+    result = mProgram->compileProgramExecutables(mInfoLog, registers);
     if (result.error.isError() || !result.linkSuccess)
     {
         mInfoLog << "Failed to create D3D shaders.";
@@ -339,20 +353,20 @@
 {
     if (destroy)   // Object being destructed
     {
-        if (mFragmentShader)
+        if (mData.mAttachedFragmentShader)
         {
-            mFragmentShader->release();
-            mFragmentShader = nullptr;
+            mData.mAttachedFragmentShader->release();
+            mData.mAttachedFragmentShader = nullptr;
         }
 
-        if (mVertexShader)
+        if (mData.mAttachedVertexShader)
         {
-            mVertexShader->release();
-            mVertexShader = nullptr;
+            mData.mAttachedVertexShader->release();
+            mData.mAttachedVertexShader = nullptr;
         }
     }
 
-    std::fill(mLinkedAttribute, mLinkedAttribute + ArraySize(mLinkedAttribute), sh::Attribute());
+    mLinkedAttributes.assign(mLinkedAttributes.size(), sh::Attribute());
     mOutputVariables.clear();
 
     mProgram->reset();
@@ -404,8 +418,8 @@
     // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
     for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
     {
-        stream.readInt(&mLinkedAttribute[i].type);
-        stream.readString(&mLinkedAttribute[i].name);
+        stream.readInt(&mLinkedAttributes[i].type);
+        stream.readString(&mLinkedAttributes[i].name);
         stream.readInt(&mProgram->getSemanticIndexes()[i]);
     }
 
@@ -448,8 +462,8 @@
     // TODO(jmadill): replace MAX_VERTEX_ATTRIBS
     for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
     {
-        stream.writeInt(mLinkedAttribute[i].type);
-        stream.writeString(mLinkedAttribute[i].name);
+        stream.writeInt(mLinkedAttributes[i].type);
+        stream.writeString(mLinkedAttributes[i].name);
         stream.writeInt(mProgram->getSemanticIndexes()[i]);
     }
 
@@ -550,21 +564,21 @@
 {
     int total = 0;
 
-    if (mVertexShader)
+    if (mData.mAttachedVertexShader)
     {
         if (total < maxCount)
         {
-            shaders[total] = mVertexShader->getHandle();
+            shaders[total] = mData.mAttachedVertexShader->getHandle();
         }
 
         total++;
     }
 
-    if (mFragmentShader)
+    if (mData.mAttachedFragmentShader)
     {
         if (total < maxCount)
         {
-            shaders[total] = mFragmentShader->getHandle();
+            shaders[total] = mData.mAttachedFragmentShader->getHandle();
         }
 
         total++;
@@ -578,11 +592,11 @@
 
 GLuint Program::getAttributeLocation(const std::string &name)
 {
-    for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+    for (size_t index = 0; index < mLinkedAttributes.size(); index++)
     {
-        if (mLinkedAttribute[index].name == name)
+        if (mLinkedAttributes[index].name == name)
         {
-            return index;
+            return static_cast<GLuint>(index);
         }
     }
 
@@ -608,9 +622,10 @@
         // Skip over inactive attributes
         unsigned int activeAttribute = 0;
         unsigned int attribute;
-        for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
+        for (attribute = 0; attribute < static_cast<unsigned int>(mLinkedAttributes.size());
+             attribute++)
         {
-            if (mLinkedAttribute[attribute].name.empty())
+            if (mLinkedAttributes[attribute].name.empty())
             {
                 continue;
             }
@@ -625,7 +640,7 @@
 
         if (bufsize > 0)
         {
-            const char *string = mLinkedAttribute[attribute].name.c_str();
+            const char *string = mLinkedAttributes[attribute].name.c_str();
 
             strncpy(name, string, bufsize);
             name[bufsize - 1] = '\0';
@@ -638,7 +653,7 @@
 
         *size = 1;   // Always a single 'type' instance
 
-        *type = mLinkedAttribute[attribute].type;
+        *type = mLinkedAttributes[attribute].type;
     }
     else
     {
@@ -665,7 +680,7 @@
     {
         for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
         {
-            if (!mLinkedAttribute[attributeIndex].name.empty())
+            if (!mLinkedAttributes[attributeIndex].name.empty())
             {
                 count++;
             }
@@ -677,15 +692,17 @@
 
 GLint Program::getActiveAttributeMaxLength()
 {
-    int maxLength = 0;
+    GLint maxLength = 0;
 
     if (mLinked)
     {
         for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
         {
-            if (!mLinkedAttribute[attributeIndex].name.empty())
+            if (!mLinkedAttributes[attributeIndex].name.empty())
             {
-                maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
+                maxLength = std::max(
+                    static_cast<GLint>(mLinkedAttributes[attributeIndex].name.length() + 1),
+                    maxLength);
             }
         }
     }
@@ -718,12 +735,12 @@
 {
     std::string baseName(name);
     unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
-    for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
+    for (auto outputPair : mOutputVariables)
     {
-        const VariableLocation &outputVariable = locationIt->second;
+        const VariableLocation &outputVariable = outputPair.second;
         if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
         {
-            return static_cast<GLint>(locationIt->first);
+            return static_cast<GLint>(outputPair.first);
         }
     }
     return -1;
@@ -1149,13 +1166,13 @@
 
 void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
 {
-    mTransformFeedbackVaryings.resize(count);
+    mData.mTransformFeedbackVaryings.resize(count);
     for (GLsizei i = 0; i < count; i++)
     {
-        mTransformFeedbackVaryings[i] = varyings[i];
+        mData.mTransformFeedbackVaryings[i] = varyings[i];
     }
 
-    mTransformFeedbackBufferMode = bufferMode;
+    mData.mTransformFeedbackBufferMode = bufferMode;
 }
 
 void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
@@ -1218,7 +1235,7 @@
 
 GLenum Program::getTransformFeedbackBufferMode() const
 {
-    return mTransformFeedbackBufferMode;
+    return mData.mTransformFeedbackBufferMode;
 }
 
 bool Program::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader)
@@ -1283,7 +1300,7 @@
 }
 
 // Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
-bool Program::linkAttributes(const Data &data,
+bool Program::linkAttributes(const gl::Data &data,
                              InfoLog &infoLog,
                              const AttributeBindings &attributeBindings,
                              const Shader *vertexShader)
@@ -1325,23 +1342,22 @@
             for (int row = 0; row < rows; row++)
             {
                 const int rowLocation = location + row;
-                sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
+                sh::ShaderVariable *linkedAttribute = &mLinkedAttributes[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.name.empty())
+                    if (!linkedAttribute->name.empty())
                     {
-                        infoLog << "Attribute '" << attribute.name
-                                << "' aliases attribute '" << linkedAttribute.name
-                                << "' at location " << rowLocation;
+                        infoLog << "Attribute '" << attribute.name << "' aliases attribute '"
+                                << linkedAttribute->name << "' at location " << rowLocation;
                         return false;
                     }
                 }
 
-                linkedAttribute = attribute;
+                *linkedAttribute = attribute;
                 usedLocations |= 1 << rowLocation;
             }
         }
@@ -1367,14 +1383,14 @@
                 return false;   // Fail to link
             }
 
-            mLinkedAttribute[availableIndex] = attribute;
+            mLinkedAttributes[availableIndex] = attribute;
         }
     }
 
     for (GLuint attributeIndex = 0; attributeIndex < maxAttribs;)
     {
-        int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
-        int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
+        int index = vertexShader->getSemanticIndex(mLinkedAttributes[attributeIndex].name);
+        int rows  = VariableRegisterCount(mLinkedAttributes[attributeIndex].type);
 
         for (int r = 0; r < rows; r++)
         {