Sync dirty objects at the GL layer.

The dirty bit system currently puts dirty objects in line with the
rest of the dirty state. This means at the Renderer level, the sync
manager code would call back to the GL layer to sync the specific
objects that are dirty. This is a bit of a layering violation (impl
layer mutating top-level objects) and also a bit of repeated boiler-
plate code.

Fix this by treating dirty objects in a separate dirty bit set, called
the dirty objects. This also has the benefit of allowing us to re-
implement the dirty object set at a later date, if we want to store
them in a list, or other structure.

Also don't skip the state sync at the GL level if there are no GL
dirty bits. The Impl might have some dirty bits locally, and it's
better to call syncState and do the no-op check in the Impl than it
is to also sync local state at every sync point (draw call, read, etc)
in each Impl.

BUG=angleproject:1260

Change-Id: Id5d4beb2a1c4e3ad351edf54e3f32e828d5f5da3
Reviewed-on: https://chromium-review.googlesource.com/318790
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index 015382d..b9c9f4b 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -8,6 +8,7 @@
 
 #include "libANGLE/State.h"
 
+#include "common/BitSetIterator.h"
 #include "libANGLE/Context.h"
 #include "libANGLE/Caps.h"
 #include "libANGLE/Debug.h"
@@ -901,7 +902,11 @@
 {
     mVertexArray = vertexArray;
     mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_BINDING);
-    mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_OBJECT);
+
+    if (mVertexArray && mVertexArray->hasAnyDirtyBit())
+    {
+        mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
+    }
 }
 
 GLuint State::getVertexArrayId() const
@@ -922,7 +927,7 @@
     {
         mVertexArray = NULL;
         mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_BINDING);
-        mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_OBJECT);
+        mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
         return true;
     }
 
@@ -1098,7 +1103,7 @@
 void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled)
 {
     getVertexArray()->enableAttribute(attribNum, enabled);
-    mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_OBJECT);
+    mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
 }
 
 void State::setVertexAttribf(GLuint index, const GLfloat values[4])
@@ -1132,13 +1137,13 @@
                                  const void *pointer)
 {
     getVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer);
-    mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_OBJECT);
+    mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
 }
 
 void State::setVertexAttribDivisor(GLuint index, GLuint divisor)
 {
     getVertexArray()->setVertexAttribDivisor(index, divisor);
-    mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_OBJECT);
+    mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
 }
 
 const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const
@@ -1710,4 +1715,34 @@
     }
 }
 
+void State::syncDirtyObjects()
+{
+    if (!mDirtyObjects.any())
+        return;
+
+    for (auto dirtyObject : angle::IterateBitSet(mDirtyObjects))
+    {
+        switch (dirtyObject)
+        {
+            case DIRTY_OBJECT_READ_FRAMEBUFFER:
+                // TODO(jmadill): implement this
+                break;
+            case DIRTY_OBJECT_DRAW_FRAMEBUFFER:
+                // TODO(jmadill): implement this
+                break;
+            case DIRTY_OBJECT_VERTEX_ARRAY:
+                mVertexArray->syncImplState();
+                break;
+            case DIRTY_OBJECT_PROGRAM:
+                // TODO(jmadill): implement this
+                break;
+            default:
+                UNREACHABLE();
+                break;
+        }
+    }
+
+    mDirtyObjects.reset();
 }
+
+}  // namespace gl