Implement dirty bits for Framebuffer.

The dirty bits set the stage for performance improvements in D3D, but
don't actually reduce any of the redundant work just yet.

BUG=angleproject:1260

Change-Id: Ib84e6a9b7aa40c37c41790f492361b22faaf4742
Reviewed-on: https://chromium-review.googlesource.com/318730
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tryjob-Request: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index b9c9f4b..7302a51 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -835,22 +835,44 @@
 
 void State::setReadFramebufferBinding(Framebuffer *framebuffer)
 {
+    if (mReadFramebuffer == framebuffer)
+        return;
+
     mReadFramebuffer = framebuffer;
+    mDirtyBits.set(DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
+
+    if (mReadFramebuffer && mReadFramebuffer->hasAnyDirtyBit())
+    {
+        mDirtyObjects.set(DIRTY_OBJECT_READ_FRAMEBUFFER);
+    }
 }
 
 void State::setDrawFramebufferBinding(Framebuffer *framebuffer)
 {
+    if (mDrawFramebuffer == framebuffer)
+        return;
+
     mDrawFramebuffer = framebuffer;
+    mDirtyBits.set(DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING);
+
+    if (mDrawFramebuffer && mDrawFramebuffer->hasAnyDirtyBit())
+    {
+        mDirtyObjects.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER);
+    }
 }
 
 Framebuffer *State::getTargetFramebuffer(GLenum target) const
 {
     switch (target)
     {
-    case GL_READ_FRAMEBUFFER_ANGLE:  return mReadFramebuffer;
-    case GL_DRAW_FRAMEBUFFER_ANGLE:
-    case GL_FRAMEBUFFER:             return mDrawFramebuffer;
-    default:                         UNREACHABLE(); return NULL;
+        case GL_READ_FRAMEBUFFER_ANGLE:
+            return mReadFramebuffer;
+        case GL_DRAW_FRAMEBUFFER_ANGLE:
+        case GL_FRAMEBUFFER:
+            return mDrawFramebuffer;
+        default:
+            UNREACHABLE();
+            return NULL;
     }
 }
 
@@ -879,7 +901,7 @@
     if (mReadFramebuffer != nullptr &&
         mReadFramebuffer->id() == framebuffer)
     {
-        mReadFramebuffer = NULL;
+        setReadFramebufferBinding(nullptr);
         return true;
     }
 
@@ -891,7 +913,7 @@
     if (mReadFramebuffer != nullptr &&
         mDrawFramebuffer->id() == framebuffer)
     {
-        mDrawFramebuffer = NULL;
+        setDrawFramebufferBinding(nullptr);
         return true;
     }
 
@@ -1720,17 +1742,25 @@
     if (!mDirtyObjects.any())
         return;
 
-    for (auto dirtyObject : angle::IterateBitSet(mDirtyObjects))
+    syncDirtyObjects(mDirtyObjects);
+}
+
+void State::syncDirtyObjects(const DirtyObjects &bitset)
+{
+    for (auto dirtyObject : angle::IterateBitSet(bitset))
     {
         switch (dirtyObject)
         {
             case DIRTY_OBJECT_READ_FRAMEBUFFER:
-                // TODO(jmadill): implement this
+                ASSERT(mReadFramebuffer);
+                mReadFramebuffer->syncState();
                 break;
             case DIRTY_OBJECT_DRAW_FRAMEBUFFER:
-                // TODO(jmadill): implement this
+                ASSERT(mDrawFramebuffer);
+                mDrawFramebuffer->syncState();
                 break;
             case DIRTY_OBJECT_VERTEX_ARRAY:
+                ASSERT(mVertexArray);
                 mVertexArray->syncImplState();
                 break;
             case DIRTY_OBJECT_PROGRAM:
@@ -1742,7 +1772,57 @@
         }
     }
 
-    mDirtyObjects.reset();
+    mDirtyObjects &= ~bitset;
+}
+
+void State::syncDirtyObject(GLenum target)
+{
+    DirtyObjects localSet;
+
+    switch (target)
+    {
+        case GL_READ_FRAMEBUFFER:
+            localSet.set(DIRTY_OBJECT_READ_FRAMEBUFFER);
+            break;
+        case GL_DRAW_FRAMEBUFFER:
+            localSet.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER);
+            break;
+        case GL_FRAMEBUFFER:
+            localSet.set(DIRTY_OBJECT_READ_FRAMEBUFFER);
+            localSet.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER);
+            break;
+        case GL_VERTEX_ARRAY:
+            localSet.set(DIRTY_OBJECT_VERTEX_ARRAY);
+            break;
+        case GL_PROGRAM:
+            localSet.set(DIRTY_OBJECT_PROGRAM);
+            break;
+    }
+
+    syncDirtyObjects(localSet);
+}
+
+void State::setObjectDirty(GLenum target)
+{
+    switch (target)
+    {
+        case GL_READ_FRAMEBUFFER:
+            mDirtyObjects.set(DIRTY_OBJECT_READ_FRAMEBUFFER);
+            break;
+        case GL_DRAW_FRAMEBUFFER:
+            mDirtyObjects.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER);
+            break;
+        case GL_FRAMEBUFFER:
+            mDirtyObjects.set(DIRTY_OBJECT_READ_FRAMEBUFFER);
+            mDirtyObjects.set(DIRTY_OBJECT_DRAW_FRAMEBUFFER);
+            break;
+        case GL_VERTEX_ARRAY:
+            mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
+            break;
+        case GL_PROGRAM:
+            mDirtyObjects.set(DIRTY_OBJECT_PROGRAM);
+            break;
+    }
 }
 
 }  // namespace gl