Share data between VertexArray and Impl.

Using the same design as for the Framebuffer::Data helper, we can
use a struct to share between the object and the Impl. This also
gives the Impl access to the maxEnabledAttrib, and saves some
duplicated storage.

BUG=angleproject:1040
TEST=WebGL CTS, end2end_tests, unittests

Change-Id: I55c91e8a5f3dcae302cab441182320aafd5375ef
Reviewed-on: https://chromium-review.googlesource.com/283930
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/gl/VertexArrayGL.cpp b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
index ba5521c..c7b6ace 100644
--- a/src/libANGLE/renderer/gl/VertexArrayGL.cpp
+++ b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
@@ -21,15 +21,12 @@
 namespace rx
 {
 
-VertexArrayGL::VertexArrayGL(const FunctionsGL *functions, StateManagerGL *stateManager)
-    : VertexArrayImpl(),
+VertexArrayGL::VertexArrayGL(const gl::VertexArray::Data &data, const FunctionsGL *functions, StateManagerGL *stateManager)
+    : VertexArrayImpl(data),
       mFunctions(functions),
       mStateManager(stateManager),
       mVertexArrayID(0),
-      mElementArrayBuffer(),
-      mAttributes(),
       mAppliedElementArrayBuffer(0),
-      mAppliedAttributes(),
       mStreamingElementArrayBufferSize(0),
       mStreamingElementArrayBuffer(0),
       mStreamingArrayBufferSize(0),
@@ -42,7 +39,6 @@
     // Set the cached vertex attribute array size
     GLint maxVertexAttribs;
     mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
-    mAttributes.resize(maxVertexAttribs);
     mAppliedAttributes.resize(maxVertexAttribs);
 }
 
@@ -59,22 +55,14 @@
     mStreamingArrayBufferSize = 0;
     mStreamingArrayBuffer = 0;
 
-    mElementArrayBuffer.set(nullptr);
-    for (size_t idx = 0; idx < mAttributes.size(); idx++)
-    {
-        mAttributes[idx].buffer.set(NULL);
-    }
-
     for (size_t idx = 0; idx < mAppliedAttributes.size(); idx++)
     {
-        mAppliedAttributes[idx].buffer.set(NULL);
+        mAppliedAttributes[idx].buffer.set(nullptr);
     }
 }
 
 void VertexArrayGL::setElementArrayBuffer(const gl::Buffer *buffer)
 {
-    mElementArrayBuffer.set(buffer);
-
     // If the buffer is being unbound/deleted, reset the currently applied buffer ID
     // so that even if a new buffer is generated with the same ID, it will be re-bound.
     if (buffer == nullptr && mAppliedElementArrayBuffer != mStreamingElementArrayBuffer)
@@ -85,17 +73,14 @@
 
 void VertexArrayGL::setAttribute(size_t idx, const gl::VertexAttribute &attr)
 {
-    mAttributes[idx] = attr;
 }
 
 void VertexArrayGL::setAttributeDivisor(size_t idx, GLuint divisor)
 {
-    mAttributes[idx].divisor = divisor;
 }
 
 void VertexArrayGL::enableAttribute(size_t idx, bool enabledState)
 {
-    mAttributes[idx].enabled = enabledState;
 }
 
 gl::Error VertexArrayGL::syncDrawArraysState(GLint first, GLsizei count) const
@@ -158,9 +143,10 @@
 bool VertexArrayGL::doAttributesNeedStreaming() const
 {
     // TODO: if GLES, nothing needs to be streamed
-    for (size_t idx = 0; idx < mAttributes.size(); idx++)
+    const auto &attribs = mData.getVertexAttributes();
+    for (size_t idx = 0; idx < attribs.size(); idx++)
     {
-        if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
+        if (attribs[idx].enabled && attribs[idx].buffer.get() == nullptr)
         {
             return true;
         }
@@ -175,13 +161,16 @@
     *outStreamingDataSize = 0;
     *outMaxAttributeDataSize = 0;
 
-    for (size_t idx = 0; idx < mAttributes.size(); idx++)
+    const auto &attribs = mData.getVertexAttributes();
+    for (size_t idx = 0; idx < attribs.size(); idx++)
     {
+        const auto &attrib = attribs[idx];
+
         // Always sync the enabled and divisor state, they are required for both streaming and buffered
         // attributes
-        if (mAppliedAttributes[idx].enabled != mAttributes[idx].enabled)
+        if (mAppliedAttributes[idx].enabled != attrib.enabled)
         {
-            if (mAttributes[idx].enabled)
+            if (attrib.enabled)
             {
                 mFunctions->enableVertexAttribArray(idx);
             }
@@ -189,15 +178,15 @@
             {
                 mFunctions->disableVertexAttribArray(idx);
             }
-            mAppliedAttributes[idx].enabled = mAttributes[idx].enabled;
+            mAppliedAttributes[idx].enabled = attrib.enabled;
         }
-        if (mAppliedAttributes[idx].divisor != mAttributes[idx].divisor)
+        if (mAppliedAttributes[idx].divisor != attrib.divisor)
         {
-            mFunctions->vertexAttribDivisor(idx, mAttributes[idx].divisor);
-            mAppliedAttributes[idx].divisor = mAttributes[idx].divisor;
+            mFunctions->vertexAttribDivisor(idx, attrib.divisor);
+            mAppliedAttributes[idx].divisor = attrib.divisor;
         }
 
-        if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
+        if (attribs[idx].enabled && attrib.buffer.get() == nullptr)
         {
             ASSERT(attributesNeedStreaming);
 
@@ -206,16 +195,16 @@
             // If streaming is going to be required, compute the size of the required buffer
             // and how much slack space at the beginning of the buffer will be required by determining
             // the attribute with the largest data size.
-            size_t typeSize = ComputeVertexAttributeTypeSize(mAttributes[idx]);
+            size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
             *outStreamingDataSize += typeSize * streamedVertexCount;
             *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
         }
         else
         {
             // Sync the attribute with no translation
-            if (mAppliedAttributes[idx] != mAttributes[idx])
+            if (mAppliedAttributes[idx] != attrib)
             {
-                const gl::Buffer *arrayBuffer = mAttributes[idx].buffer.get();
+                const gl::Buffer *arrayBuffer = attrib.buffer.get();
                 if (arrayBuffer != nullptr)
                 {
                     const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
@@ -226,19 +215,19 @@
                     mStateManager->bindBuffer(GL_ARRAY_BUFFER, 0);
                 }
 
-                if (mAttributes[idx].pureInteger)
+                if (attrib.pureInteger)
                 {
-                    mFunctions->vertexAttribIPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
-                                                     mAttributes[idx].stride, mAttributes[idx].pointer);
+                    mFunctions->vertexAttribIPointer(idx, attrib.size, attrib.type,
+                                                     attrib.stride, attrib.pointer);
                 }
                 else
                 {
-                    mFunctions->vertexAttribPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
-                                                    mAttributes[idx].normalized, mAttributes[idx].stride,
-                                                    mAttributes[idx].pointer);
+                    mFunctions->vertexAttribPointer(idx, attrib.size, attrib.type,
+                                                    attrib.normalized, attrib.stride,
+                                                    attrib.pointer);
                 }
 
-                mAppliedAttributes[idx] = mAttributes[idx];
+                mAppliedAttributes[idx] = attrib;
             }
         }
     }
@@ -251,10 +240,12 @@
 {
     ASSERT(outIndices);
 
+    gl::Buffer *elementArrayBuffer = mData.getElementArrayBuffer().get();
+
     // Need to check the range of indices if attributes need to be streamed
-    if (mElementArrayBuffer.get() != nullptr)
+    if (elementArrayBuffer != nullptr)
     {
-        const BufferGL *bufferGL = GetImplAs<BufferGL>(mElementArrayBuffer.get());
+        const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
         GLuint elementArrayBufferID = bufferGL->getBufferID();
         if (elementArrayBufferID != mAppliedElementArrayBuffer)
         {
@@ -266,7 +257,7 @@
         if (attributesNeedStreaming)
         {
             ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
-            gl::Error error = mElementArrayBuffer->getIndexRange(type, static_cast<size_t>(elementArrayBufferOffset), count, outIndexRange);
+            gl::Error error = mData.getElementArrayBuffer()->getIndexRange(type, static_cast<size_t>(elementArrayBufferOffset), count, outIndexRange);
             if (error.isError())
             {
                 return error;
@@ -351,14 +342,17 @@
 
         const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
 
-        for (size_t idx = 0; idx < mAttributes.size(); idx++)
+        const auto &attribs = mData.getVertexAttributes();
+        for (size_t idx = 0; idx < attribs.size(); idx++)
         {
-            if (mAttributes[idx].enabled && mAttributes[idx].buffer.get() == nullptr)
-            {
-                const size_t sourceStride = ComputeVertexAttributeStride(mAttributes[idx]);
-                const size_t destStride = ComputeVertexAttributeTypeSize(mAttributes[idx]);
+            const auto &attrib = attribs[idx];
 
-                const uint8_t *inputPointer = reinterpret_cast<const uint8_t*>(mAttributes[idx].pointer);
+            if (attrib.enabled && attrib.buffer.get() == nullptr)
+            {
+                const size_t sourceStride = ComputeVertexAttributeStride(attrib);
+                const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
+
+                const uint8_t *inputPointer = reinterpret_cast<const uint8_t*>(attrib.pointer);
 
                 // Pack the data when copying it, user could have supplied a very large stride that would
                 // cause the buffer to be much larger than needed.
@@ -383,8 +377,8 @@
                 // Compute where the 0-index vertex would be.
                 const size_t vertexStartOffset = curBufferOffset - (indexRange.start * destStride);
 
-                mFunctions->vertexAttribPointer(idx, mAttributes[idx].size, mAttributes[idx].type,
-                                                mAttributes[idx].normalized, destStride,
+                mFunctions->vertexAttribPointer(idx, attrib.size, attrib.type,
+                                                attrib.normalized, destStride,
                                                 reinterpret_cast<const GLvoid*>(vertexStartOffset));
 
                 curBufferOffset += destStride * streamedVertexCount;