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/Context.cpp b/src/libANGLE/Context.cpp
index 15c44e8..4c9d49d 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -1096,6 +1096,7 @@
 {
     VertexArray *vertexArray = checkVertexArrayAllocation(vertexArrayHandle);
     mGLState.setVertexArrayBinding(this, vertexArray);
+    mStateCache.updateActiveAttribsMask(this);
 }
 
 void Context::bindVertexBuffer(GLuint bindingIndex,
@@ -1105,6 +1106,7 @@
 {
     Buffer *buffer = mState.mBuffers->checkBufferAllocation(mImplementation.get(), bufferHandle);
     mGLState.bindVertexBuffer(this, bindingIndex, buffer, offset, stride);
+    mStateCache.updateActiveAttribsMask(this);
 }
 
 void Context::bindSampler(GLuint textureUnit, GLuint samplerHandle)
@@ -1130,6 +1132,7 @@
 void Context::useProgram(GLuint program)
 {
     mGLState.setProgram(this, getProgram(program));
+    mStateCache.updateActiveAttribsMask(this);
 }
 
 void Context::useProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
@@ -2783,6 +2786,7 @@
 void Context::vertexAttribDivisor(GLuint index, GLuint divisor)
 {
     mGLState.setVertexAttribDivisor(this, index, divisor);
+    mStateCache.updateActiveAttribsMask(this);
 }
 
 void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param)
@@ -4389,6 +4393,7 @@
 void Context::disableVertexAttribArray(GLuint index)
 {
     mGLState.setEnableVertexAttribArray(index, false);
+    mStateCache.updateActiveAttribsMask(this);
 }
 
 void Context::enable(GLenum cap)
@@ -4399,6 +4404,7 @@
 void Context::enableVertexAttribArray(GLuint index)
 {
     mGLState.setEnableVertexAttribArray(index, true);
+    mStateCache.updateActiveAttribsMask(this);
 }
 
 void Context::frontFace(GLenum mode)
@@ -4606,6 +4612,7 @@
 {
     mGLState.setVertexAttribPointer(this, index, mGLState.getTargetBuffer(BufferBinding::Array),
                                     size, type, ConvertToBool(normalized), false, stride, ptr);
+    mStateCache.updateActiveAttribsMask(this);
 }
 
 void Context::vertexAttribFormat(GLuint attribIndex,
@@ -4629,6 +4636,7 @@
 void Context::vertexAttribBinding(GLuint attribIndex, GLuint bindingIndex)
 {
     mGLState.setVertexAttribBinding(this, attribIndex, bindingIndex);
+    mStateCache.updateActiveAttribsMask(this);
 }
 
 void Context::vertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
@@ -4649,6 +4657,7 @@
 {
     mGLState.setVertexAttribPointer(this, index, mGLState.getTargetBuffer(BufferBinding::Array),
                                     size, type, false, true, stride, pointer);
+    mStateCache.updateActiveAttribsMask(this);
 }
 
 void Context::vertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
@@ -5534,6 +5543,7 @@
     ASSERT(programObject);
     handleError(programObject->link(this));
     mGLState.onProgramExecutableChange(programObject);
+    mStateCache.updateActiveAttribsMask(this);
 }
 
 void Context::releaseShaderCompiler()
@@ -5741,6 +5751,7 @@
     ASSERT(programObject != nullptr);
 
     handleError(programObject->loadBinary(this, binaryFormat, binary, length));
+    mStateCache.updateActiveAttribsMask(this);
 }
 
 void Context::uniform1ui(GLint location, GLuint v0)
@@ -7536,23 +7547,6 @@
     return mState.getClientVersion() < Version(2, 0);
 }
 
-AttributesMask Context::getActiveBufferedAttribsMask() const
-{
-    // TODO(jmadill): Cache this. http://anglebug.com/1391
-    ASSERT(mGLState.getProgram() || isGLES1());
-
-    const AttributesMask &activeAttribs =
-        isGLES1() ? mGLState.gles1().getVertexArraysAttributeMask()
-                  : mGLState.getProgram()->getActiveAttribLocationsMask();
-
-    const VertexArray *vao = mGLState.getVertexArray();
-    ASSERT(vao);
-
-    const AttributesMask &clientAttribs = vao->getEnabledClientMemoryAttribsMask();
-
-    return (activeAttribs & vao->getEnabledAttributesMask() & ~clientAttribs);
-}
-
 // ErrorSet implementation.
 ErrorSet::ErrorSet(Context *context) : mContext(context)
 {
@@ -7597,4 +7591,39 @@
     mErrors.erase(mErrors.begin());
     return error;
 }
+
+// StateCache implementation.
+StateCache::StateCache() : mCachedHasAnyEnabledClientAttrib(false)
+{
+}
+
+StateCache::~StateCache() = default;
+
+void StateCache::updateActiveAttribsMask(Context *context)
+{
+    bool isGLES1         = context->isGLES1();
+    const State &glState = context->getGLState();
+
+    if (!isGLES1 && !glState.getProgram())
+    {
+        mCachedActiveBufferedAttribsMask = AttributesMask();
+        mCachedActiveClientAttribsMask   = AttributesMask();
+        return;
+    }
+
+    AttributesMask activeAttribs = isGLES1 ? glState.gles1().getVertexArraysAttributeMask()
+                                           : glState.getProgram()->getActiveAttribLocationsMask();
+
+    const VertexArray *vao = glState.getVertexArray();
+    ASSERT(vao);
+
+    const AttributesMask &clientAttribs  = vao->getClientAttribsMask();
+    const AttributesMask &enabledAttribs = vao->getEnabledAttributesMask();
+
+    activeAttribs &= enabledAttribs;
+
+    mCachedActiveClientAttribsMask   = activeAttribs & clientAttribs;
+    mCachedActiveBufferedAttribsMask = activeAttribs & ~clientAttribs;
+    mCachedHasAnyEnabledClientAttrib = (clientAttribs & enabledAttribs).any();
+}
 }  // namespace gl