Use Observer pattern for Buffers in front-end.

This will allow us to react to state change notifications for validation
caching. It also cleans up some of the logic in the D3D11 State Manager.

Bug: angleproject:2747
Change-Id: I85ed6404206c2b9bf504d552cf5751be56e62146
Reviewed-on: https://chromium-review.googlesource.com/1172086
Reviewed-by: Frank Henigman <fjhenigman@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 59f0e13..4cb2d41 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -41,6 +41,7 @@
 #include "libANGLE/formatutils.h"
 #include "libANGLE/queryconversions.h"
 #include "libANGLE/queryutils.h"
+#include "libANGLE/renderer/BufferImpl.h"
 #include "libANGLE/renderer/ContextImpl.h"
 #include "libANGLE/renderer/EGLImplFactory.h"
 #include "libANGLE/renderer/Format.h"
@@ -298,11 +299,17 @@
 static_assert(static_cast<gl::PrimitiveMode>(11) == gl::PrimitiveMode::EnumCount,
               "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
 
-constexpr angle::SubjectIndex kVertexArraySubjectIndex = gl::IMPLEMENTATION_MAX_ACTIVE_TEXTURES + 0;
-constexpr angle::SubjectIndex kReadFramebufferSubjectIndex =
-    gl::IMPLEMENTATION_MAX_ACTIVE_TEXTURES + 1;
-constexpr angle::SubjectIndex kDrawFramebufferSubjectIndex =
-    gl::IMPLEMENTATION_MAX_ACTIVE_TEXTURES + 2;
+enum SubjectIndexes : angle::SubjectIndex
+{
+    kTexture0SubjectIndex       = 0,
+    kTextureMaxSubjectIndex     = kTexture0SubjectIndex + gl::IMPLEMENTATION_MAX_ACTIVE_TEXTURES,
+    kUniformBuffer0SubjectIndex = kTextureMaxSubjectIndex,
+    kUniformBufferMaxSubjectIndex =
+        kUniformBuffer0SubjectIndex + gl::IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS,
+    kVertexArraySubjectIndex = kUniformBufferMaxSubjectIndex,
+    kReadFramebufferSubjectIndex,
+    kDrawFramebufferSubjectIndex
+};
 }  // anonymous namespace
 
 namespace gl
@@ -362,6 +369,12 @@
     // Needed to solve a Clang warning of unused variables.
     ANGLE_UNUSED_VARIABLE(mSavedArgsType);
     ANGLE_UNUSED_VARIABLE(mParamsBuffer);
+
+    for (angle::SubjectIndex uboIndex = kUniformBuffer0SubjectIndex;
+         uboIndex < kUniformBufferMaxSubjectIndex; ++uboIndex)
+    {
+        mUniformBufferObserverBindings.emplace_back(this, uboIndex);
+    }
 }
 
 void Context::initialize()
@@ -3233,6 +3246,8 @@
 
     LimitCap(&mCaps.maxShaderUniformBlocks[ShaderType::Vertex],
              IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS);
+    LimitCap(&mCaps.maxUniformBufferBindings, IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS);
+
     LimitCap(&mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
     LimitCap(&mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
 
@@ -4937,8 +4952,12 @@
                               GLintptr offset,
                               GLsizeiptr size)
 {
-    Buffer *bufferObject = mState.mBuffers->checkBufferAllocation(mImplementation.get(), buffer);
-    mGLState.setIndexedBufferBinding(this, target, index, bufferObject, offset, size);
+    Buffer *object = mState.mBuffers->checkBufferAllocation(mImplementation.get(), buffer);
+    mGLState.setIndexedBufferBinding(this, target, index, object, offset, size);
+    if (target == BufferBinding::Uniform)
+    {
+        mUniformBufferObserverBindings[index].bind(object ? object->getImplementation() : nullptr);
+    }
 }
 
 void Context::bindFramebuffer(GLenum target, GLuint framebuffer)
@@ -7633,8 +7652,15 @@
             break;
 
         default:
-            ASSERT(index < mGLState.getActiveTexturesCache().size());
-            mGLState.onActiveTextureStateChange(index);
+            if (index < kTextureMaxSubjectIndex)
+            {
+                mGLState.onActiveTextureStateChange(index);
+            }
+            else
+            {
+                ASSERT(index < kUniformBufferMaxSubjectIndex);
+                mGLState.onUniformBufferStateChange(index - kUniformBuffer0SubjectIndex);
+            }
             break;
     }
 }