Optimize ValidateDrawAttribs: Part 1.

This moves several loop checks outside the loop, and uses more of the
gl::AttributesMask class to do bitset operations instead of using
checks and for loops.

Bug: angleproject:1391
Change-Id: I90a1a7db550390ecd1402cf5a8a6677fd852b7b0
Reviewed-on: https://chromium-review.googlesource.com/1008273
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 6c10585..3fe06a6 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -75,57 +75,54 @@
 
     bool webglCompatibility = context->getExtensions().webglCompatibility;
 
-    const VertexArray *vao     = state.getVertexArray();
+    const VertexArray *vao              = state.getVertexArray();
+    const AttributesMask &clientAttribs = vao->getEnabledClientMemoryAttribsMask();
+
+    if (clientAttribs.any())
+    {
+        if (webglCompatibility || !state.areClientArraysEnabled())
+        {
+            // [WebGL 1.0] Section 6.5 Enabled Vertex Attributes and Range Checking
+            // If a vertex attribute is enabled as an array via enableVertexAttribArray but no
+            // buffer is bound to that attribute via bindBuffer and vertexAttribPointer, then calls
+            // to drawArrays or drawElements will generate an INVALID_OPERATION error.
+            ANGLE_VALIDATION_ERR(context, InvalidOperation(), VertexArrayNoBuffer);
+            return false;
+        }
+        else if (vao->hasEnabledNullPointerClientArray())
+        {
+            // This is an application error that would normally result in a crash, but we catch it
+            // and return an error
+            ANGLE_VALIDATION_ERR(context, InvalidOperation(), VertexArrayNoBufferPointer);
+            return false;
+        }
+    }
+
+    // If we're drawing zero vertices, we have enough data.
+    if (vertexCount <= 0 || primcount <= 0)
+    {
+        return true;
+    }
+
     const auto &vertexAttribs  = vao->getVertexAttributes();
     const auto &vertexBindings = vao->getVertexBindings();
-    for (size_t attributeIndex : vao->getEnabledAttributesMask())
+
+    const AttributesMask &activeAttribs =
+        (program->getActiveAttribLocationsMask() & vao->getEnabledAttributesMask());
+
+    for (size_t attributeIndex : activeAttribs)
     {
         const VertexAttribute &attrib = vertexAttribs[attributeIndex];
+        ASSERT(attrib.enabled);
 
-        // No need to range check for disabled attribs.
-        if (!attrib.enabled)
-        {
-            continue;
-        }
-
-        // If we have no buffer, then we either get an error, or there are no more checks to be
-        // done.
         const VertexBinding &binding = vertexBindings[attrib.bindingIndex];
         gl::Buffer *buffer           = binding.getBuffer().get();
         if (!buffer)
         {
-            if (webglCompatibility || !state.areClientArraysEnabled())
-            {
-                // [WebGL 1.0] Section 6.5 Enabled Vertex Attributes and Range Checking
-                // If a vertex attribute is enabled as an array via enableVertexAttribArray but
-                // no buffer is bound to that attribute via bindBuffer and vertexAttribPointer,
-                // then calls to drawArrays or drawElements will generate an INVALID_OPERATION
-                // error.
-                ANGLE_VALIDATION_ERR(context, InvalidOperation(), VertexArrayNoBuffer);
-                return false;
-            }
-            else if (attrib.pointer == nullptr)
-            {
-                // This is an application error that would normally result in a crash,
-                // but we catch it and return an error
-                ANGLE_VALIDATION_ERR(context, InvalidOperation(), VertexArrayNoBufferPointer);
-                return false;
-            }
             continue;
         }
 
-        // This needs to come after the check for client arrays as even unused attributes cannot use
-        // client-side arrays
-        if (!program->isAttribLocationActive(attributeIndex))
-        {
-            continue;
-        }
-
-        // If we're drawing zero vertices, we have enough data.
-        if (vertexCount <= 0 || primcount <= 0)
-        {
-            continue;
-        }
+        ASSERT(program->isAttribLocationActive(attributeIndex));
 
         GLint maxVertexElement = 0;
         GLuint divisor         = binding.getDivisor();