Fix bug in updating vertex attribs with client memory pointers

In DEBUG version, when using OpenGL back-ends, ANGLE may meet an
INVALID_OPERATION error from driver when attemping to update an
attribute which is disabled and using a client memory pointer.

This patch fixes this bug by skipping such vertex attributes when
updating them to driver. With this patch the process to update
vertex attributes should be:
(1) For enabled attributes using client memory pointer:
    update by streaming mode in streamAttributes()
(2) For disabled attributes using client memory pointer:
    just label them dirty and skip them
(3) For attributes using buffer objects:
    update with vertexAttrib*Pointer

BUG=angleproject:1942

Change-Id: I57043e5904eb4a342fa22d449d98a957010170d6
Reviewed-on: https://chromium-review.googlesource.com/456747
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/libANGLE/renderer/gl/VertexArrayGL.cpp b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
index be4bb84..b0552c9 100644
--- a/src/libANGLE/renderer/gl/VertexArrayGL.cpp
+++ b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
@@ -467,32 +467,30 @@
         return;
     }
 
-    mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
+    // Skip the attribute that is disabled and uses a client memory pointer.
     const Buffer *arrayBuffer = binding.buffer.get();
-    if (arrayBuffer != nullptr)
+    if (arrayBuffer == nullptr)
     {
-        const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
-        mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
-    }
-    else
-    {
-        mStateManager->bindBuffer(GL_ARRAY_BUFFER, 0);
+        ASSERT(!attrib.enabled);
+
+        // Mark the applied attribute as dirty by setting an invalid size so that if it doesn't
+        // use a client memory pointer later, there is no chance that the caching will skip it.
+        mAppliedAttributes[attribIndex].size = static_cast<GLuint>(-1);
+        return;
     }
 
-    mAppliedBindings[bindingIndex].buffer = binding.buffer;
+    mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
 
-    const GLvoid *inputPointer = nullptr;
-    if (arrayBuffer != nullptr)
-    {
-        inputPointer = static_cast<const GLvoid *>(
-            reinterpret_cast<const uint8_t *>(binding.offset + attrib.relativeOffset));
-    }
-    else
-    {
-        // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
-        // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding
-        inputPointer = attrib.pointer;
-    }
+    // Since ANGLE always uses a non-zero VAO, we cannot use a client memory pointer on it:
+    // [OpenGL ES 3.0.2] Section 2.8 page 24:
+    // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
+    // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
+    // is not NULL.
+    ASSERT(arrayBuffer != nullptr);
+    const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
+    mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
+    const GLvoid *inputPointer =
+        reinterpret_cast<const uint8_t *>(binding.offset + attrib.relativeOffset);
 
     if (attrib.pureInteger)
     {
@@ -514,6 +512,7 @@
 
     mAppliedBindings[bindingIndex].stride = binding.stride;
     mAppliedBindings[bindingIndex].offset = binding.offset;
+    mAppliedBindings[bindingIndex].buffer = binding.buffer;
 }
 
 void VertexArrayGL::updateAttribDivisor(size_t attribIndex)