Move Buffer Subject/Observer to front end.

This makes BufferImpl into an Observer Subject. It also refactors
the Vertex Array updates for the D3D11 backend use more of a dirty
bit coding style.

This change makes it so Buffer contents changes trigger front-end
dirty bits from the back-end, which may be undesirable.

Bug: angleproject:2389
Change-Id: Iac8ce1171284a86851c18cd1373ddf24fcefe40b
Reviewed-on: https://chromium-review.googlesource.com/979812
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/VertexArray.cpp b/src/libANGLE/VertexArray.cpp
index 19fedee..0735c2a 100644
--- a/src/libANGLE/VertexArray.cpp
+++ b/src/libANGLE/VertexArray.cpp
@@ -9,6 +9,7 @@
 #include "libANGLE/VertexArray.h"
 #include "libANGLE/Buffer.h"
 #include "libANGLE/Context.h"
+#include "libANGLE/renderer/BufferImpl.h"
 #include "libANGLE/renderer/GLImplFactory.h"
 #include "libANGLE/renderer/VertexArrayImpl.h"
 
@@ -36,8 +37,13 @@
                          size_t maxAttribBindings)
     : mId(id),
       mState(maxAttribs, maxAttribBindings),
-      mVertexArray(factory->createVertexArray(mState))
+      mVertexArray(factory->createVertexArray(mState)),
+      mElementArrayBufferObserverBinding(this, maxAttribBindings)
 {
+    for (size_t attribIndex = 0; attribIndex < maxAttribBindings; ++attribIndex)
+    {
+        mArrayBufferObserverBindings.emplace_back(this, attribIndex);
+    }
 }
 
 void VertexArray::onDestroy(const Context *context)
@@ -140,6 +146,8 @@
     binding->setBuffer(context, boundBuffer, isBound);
     binding->setOffset(offset);
     binding->setStride(stride);
+
+    updateObserverBinding(bindingIndex);
 }
 
 void VertexArray::bindVertexBuffer(const Context *context,
@@ -267,6 +275,7 @@
     mState.mElementArrayBuffer.set(context, buffer);
     if (isBound && mState.mElementArrayBuffer.get())
         mState.mElementArrayBuffer->onBindingChanged(true, BufferBinding::ElementArray);
+    mElementArrayBufferObserverBinding.bind(buffer ? buffer->getImplementation() : nullptr);
     mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
 }
 
@@ -274,9 +283,11 @@
 {
     if (mDirtyBits.any())
     {
+        mDirtyBitsGuard = mDirtyBits;
         ANGLE_TRY(
             mVertexArray->syncState(context, mDirtyBits, mDirtyAttribBits, mDirtyBindingBits));
         mDirtyBits.reset();
+        mDirtyBitsGuard.reset();
 
         // This is a bit of an implementation hack - but since we know the implementation
         // details of the dirty bit class it should always have the same effect as iterating
@@ -298,4 +309,39 @@
     }
 }
 
+VertexArray::DirtyBitType VertexArray::getDirtyBitFromIndex(bool contentsChanged,
+                                                            angle::SubjectIndex index) const
+{
+    if (index == mArrayBufferObserverBindings.size())
+    {
+        return contentsChanged ? DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA
+                               : DIRTY_BIT_ELEMENT_ARRAY_BUFFER;
+    }
+    else
+    {
+        // Note: this currently just gets the top-level dirty bit.
+        ASSERT(index < mArrayBufferObserverBindings.size());
+        return static_cast<DirtyBitType>(
+            (contentsChanged ? DIRTY_BIT_BUFFER_DATA_0 : DIRTY_BIT_BINDING_0) + index);
+    }
+}
+
+void VertexArray::onSubjectStateChange(const gl::Context *context,
+                                       angle::SubjectIndex index,
+                                       angle::SubjectMessage message)
+{
+    bool contentsChanged  = (message == angle::SubjectMessage::CONTENTS_CHANGED);
+    DirtyBitType dirtyBit = getDirtyBitFromIndex(contentsChanged, index);
+    ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(dirtyBit));
+    mDirtyBits.set(dirtyBit);
+    context->getGLState().setVertexArrayDirty(this);
+}
+
+void VertexArray::updateObserverBinding(size_t bindingIndex)
+{
+    Buffer *boundBuffer = mState.mVertexBindings[bindingIndex].getBuffer().get();
+    mArrayBufferObserverBindings[bindingIndex].bind(boundBuffer ? boundBuffer->getImplementation()
+                                                                : nullptr);
+}
+
 }  // namespace gl