Context: Cache attributes masks.

This cache is updated in the following locations:

1. GLES1: clientActiveTexture.
2. GLES1: disableClientState/enableClientState.
3. Context: linkProgram/useProgram/programBinary.
4. Context: bindVertexArray.
5. Vertex Array: most state changes.

Improves performance by about 6% in the GL no-op test. Also includes
fixes for keeping the client memory attribs mask in sync. The cache
also includes a boolean if there are any enabled client attributes.

Bug: angleproject:1391
Change-Id: I93b6a2c8492355958fd5483f14b70535729091d6
Reviewed-on: https://chromium-review.googlesource.com/1147437
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/VertexArray.cpp b/src/libANGLE/VertexArray.cpp
index 2cd9b49..604713a 100644
--- a/src/libANGLE/VertexArray.cpp
+++ b/src/libANGLE/VertexArray.cpp
@@ -26,17 +26,15 @@
         mVertexAttributes.emplace_back(static_cast<GLuint>(i));
         mBindingToAttributeMasks[i].set(i);
     }
+
+    // Initially all attributes start as "client" with no buffer bound.
+    mClientMemoryAttribsMask.set();
 }
 
 VertexArrayState::~VertexArrayState()
 {
 }
 
-gl::AttributesMask VertexArrayState::getEnabledClientMemoryAttribsMask() const
-{
-    return (mClientMemoryAttribsMask & mEnabledAttributesMask);
-}
-
 bool VertexArrayState::hasEnabledNullPointerClientArray() const
 {
     return (mNullPointerClientMemoryAttribsMask & mEnabledAttributesMask).any();
@@ -189,6 +187,16 @@
     updateObserverBinding(bindingIndex);
     updateCachedBufferBindingSize(bindingIndex);
     updateCachedTransformFeedbackBindingValidation(bindingIndex, boundBuffer);
+
+    // Update client memory attribute pointers. Affects all bound attributes.
+    if (boundBuffer)
+    {
+        mState.mClientMemoryAttribsMask &= ~mState.mBindingToAttributeMasks[bindingIndex];
+    }
+    else
+    {
+        mState.mClientMemoryAttribsMask |= mState.mBindingToAttributeMasks[bindingIndex];
+    }
 }
 
 void VertexArray::bindVertexBuffer(const Context *context,
@@ -215,6 +223,10 @@
         mState.setAttribBinding(attribIndex, bindingIndex);
 
         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING);
+
+        // Update client attribs mask.
+        bool hasBuffer = mState.mVertexBindings[bindingIndex].getBuffer().get() != nullptr;
+        mState.mClientMemoryAttribsMask.set(attribIndex, !hasBuffer);
     }
 }
 
@@ -307,7 +319,6 @@
 
     setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER);
 
-    mState.mClientMemoryAttribsMask.set(attribIndex, boundBuffer == nullptr);
     mState.mNullPointerClientMemoryAttribsMask.set(attribIndex,
                                                    boundBuffer == nullptr && pointer == nullptr);
 }