Add gl::Program::syncState and dirty bits.

Currently this handles uniform block bindings. Cleans up some logic in D3D.

Bug: angleproject:2747
Change-Id: I8c2989738d50a77d6f6d90a9ff11dceab6d3129c
Reviewed-on: https://chromium-review.googlesource.com/1172085
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 fbf9bfe..59f0e13 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -461,6 +461,7 @@
     mDrawDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER);
     mDrawDirtyObjects.set(State::DIRTY_OBJECT_VERTEX_ARRAY);
     mDrawDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_TEXTURES);
+    mDrawDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM);
 
     mPathOperationDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER);
     mPathOperationDirtyObjects.set(State::DIRTY_OBJECT_VERTEX_ARRAY);
@@ -506,6 +507,7 @@
     mComputeDirtyBits.set(State::DIRTY_BIT_SAMPLER_BINDINGS);
     mComputeDirtyBits.set(State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING);
     mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_TEXTURES);
+    mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM);
 
     mImplementation->setErrorSet(&mErrors);
 
@@ -5797,6 +5799,10 @@
 
     handleError(programObject->loadBinary(this, binaryFormat, binary, length));
     mStateCache.onProgramExecutableChange(this);
+    if (programObject->isInUse())
+    {
+        mGLState.setObjectDirty(GL_PROGRAM);
+    }
 }
 
 void Context::uniform1ui(GLint location, GLuint v0)
@@ -6166,6 +6172,11 @@
 {
     Program *programObject = getProgram(program);
     programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding);
+
+    if (programObject->isInUse())
+    {
+        mGLState.setObjectDirty(GL_PROGRAM);
+    }
 }
 
 GLsync Context::fenceSync(GLenum condition, GLbitfield flags)
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 168b994..1bdcf45 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -1420,6 +1420,12 @@
     // Currently we require the full shader text to compute the program hash.
     // TODO(jmadill): Store the binary in the internal program cache.
 
+    for (size_t uniformBlockIndex = 0; uniformBlockIndex < mState.mUniformBlocks.size();
+         ++uniformBlockIndex)
+    {
+        mDirtyBits.set(uniformBlockIndex);
+    }
+
     return NoError();
 #endif  // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
 }
@@ -2437,7 +2443,7 @@
     resolveLink();
     mState.mUniformBlocks[uniformBlockIndex].binding = uniformBlockBinding;
     mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlockBinding != 0);
-    mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
+    mDirtyBits.set(DIRTY_BIT_UNIFORM_BLOCK_BINDING_0 + uniformBlockIndex);
 }
 
 GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
@@ -3921,4 +3927,15 @@
     return false;
 }
 
+Error Program::syncState(const Context *context)
+{
+    if (mDirtyBits.any())
+    {
+        resolveLink();
+        ANGLE_TRY(mProgram->syncState(context, mDirtyBits));
+        mDirtyBits.reset();
+    }
+
+    return NoError();
+}
 }  // namespace gl
diff --git a/src/libANGLE/Program.h b/src/libANGLE/Program.h
index a66823a..83c4082 100644
--- a/src/libANGLE/Program.h
+++ b/src/libANGLE/Program.h
@@ -741,6 +741,20 @@
         return mState.mActiveSamplerTypes;
     }
 
+    // Program dirty bits.
+    enum DirtyBitType
+    {
+        DIRTY_BIT_UNIFORM_BLOCK_BINDING_0,
+        DIRTY_BIT_UNIFORM_BLOCK_BINDING_MAX =
+            DIRTY_BIT_UNIFORM_BLOCK_BINDING_0 + IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS,
+
+        DIRTY_BIT_COUNT = DIRTY_BIT_UNIFORM_BLOCK_BINDING_MAX,
+    };
+
+    using DirtyBits = angle::BitSet<DIRTY_BIT_COUNT>;
+
+    Error syncState(const Context *context);
+
   private:
     struct LinkingState;
 
@@ -875,6 +889,8 @@
 
     // Cache for sampler validation
     Optional<bool> mCachedValidateSamplersResult;
+
+    DirtyBits mDirtyBits;
 };
 }  // namespace gl
 
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index ce840f1..3208c3a 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -1351,6 +1351,7 @@
         }
         mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE);
         mDirtyBits.set(DIRTY_BIT_PROGRAM_BINDING);
+        mDirtyObjects.set(DIRTY_OBJECT_PROGRAM);
     }
 }
 
@@ -2675,6 +2676,9 @@
             case DIRTY_OBJECT_PROGRAM_TEXTURES:
                 ANGLE_TRY(syncProgramTextures(context));
                 break;
+            case DIRTY_OBJECT_PROGRAM:
+                ANGLE_TRY(mProgram->syncState(context));
+                break;
 
             default:
                 UNREACHABLE();
@@ -2781,8 +2785,11 @@
             break;
         case GL_TEXTURE:
         case GL_SAMPLER:
+            localSet.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
+            break;
         case GL_PROGRAM:
             localSet.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
+            localSet.set(DIRTY_OBJECT_PROGRAM);
             break;
     }
 
@@ -2808,8 +2815,12 @@
             break;
         case GL_TEXTURE:
         case GL_SAMPLER:
+            mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
+            mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
+            break;
         case GL_PROGRAM:
             mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
+            mDirtyObjects.set(DIRTY_OBJECT_PROGRAM);
             mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
             break;
     }
@@ -2825,6 +2836,7 @@
     {
         mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE);
         mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
+        mDirtyObjects.set(DIRTY_OBJECT_PROGRAM);
     }
 }
 
diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h
index fbd208c..37f17a9 100644
--- a/src/libANGLE/State.h
+++ b/src/libANGLE/State.h
@@ -438,6 +438,7 @@
         // Use a very coarse bit for any program or texture change.
         // TODO(jmadill): Fine-grained dirty bits for each texture/sampler.
         DIRTY_OBJECT_PROGRAM_TEXTURES,
+        DIRTY_OBJECT_PROGRAM,
         DIRTY_OBJECT_UNKNOWN,
         DIRTY_OBJECT_MAX = DIRTY_OBJECT_UNKNOWN,
     };
diff --git a/src/libANGLE/renderer/ProgramImpl.h b/src/libANGLE/renderer/ProgramImpl.h
index 713e2f4..927c139 100644
--- a/src/libANGLE/renderer/ProgramImpl.h
+++ b/src/libANGLE/renderer/ProgramImpl.h
@@ -109,9 +109,6 @@
                                GLint location,
                                GLuint *params) const = 0;
 
-    // TODO: synchronize in syncState when dirty bits exist.
-    virtual void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) = 0;
-
     // CHROMIUM_path_rendering
     // Set parameters to control fragment shader input variable interpolation
     virtual void setPathFragmentInputGen(const std::string &inputName,
@@ -129,10 +126,19 @@
 
     const gl::ProgramState &getState() const { return mState; }
 
+    virtual gl::Error syncState(const gl::Context *context,
+                                const gl::Program::DirtyBits &dirtyBits);
+
   protected:
     const gl::ProgramState &mState;
 };
 
+inline gl::Error ProgramImpl::syncState(const gl::Context *context,
+                                        const gl::Program::DirtyBits &dirtyBits)
+{
+    return gl::NoError();
+}
+
 }  // namespace rx
 
 #endif // LIBANGLE_RENDERER_PROGRAMIMPL_H_
diff --git a/src/libANGLE/renderer/ProgramImpl_mock.h b/src/libANGLE/renderer/ProgramImpl_mock.h
index 4717ab8..d2369f8 100644
--- a/src/libANGLE/renderer/ProgramImpl_mock.h
+++ b/src/libANGLE/renderer/ProgramImpl_mock.h
@@ -62,7 +62,6 @@
     MOCK_CONST_METHOD3(getUniformiv, void(const gl::Context *, GLint, GLint *));
     MOCK_CONST_METHOD3(getUniformuiv, void(const gl::Context *, GLint, GLuint *));
 
-    MOCK_METHOD2(setUniformBlockBinding, void(GLuint, GLuint));
     MOCK_METHOD4(setPathFragmentInputGen,
                  void(const std::string &, GLenum, GLint, const GLfloat *));
 
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index 0f179ae..25104e6 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -1984,11 +1984,6 @@
     setUniformInternal(location, count, v, GL_UNSIGNED_INT_VEC4);
 }
 
-void ProgramD3D::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint /*uniformBlockBinding*/)
-{
-    mRenderer->onDirtyUniformBlockBinding(uniformBlockIndex);
-}
-
 void ProgramD3D::defineUniformsAndAssignRegisters()
 {
     D3DUniformMap uniformMap;
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/libANGLE/renderer/d3d/ProgramD3D.h
index 326d710..c62deab 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -265,8 +265,6 @@
     void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
     void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
 
-    void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
-
     UniformStorageD3D *getShaderUniformStorage(gl::ShaderType shaderType) const
     {
         return mShaderUniformStorages[shaderType].get();
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/libANGLE/renderer/d3d/RendererD3D.cpp
index 78e184a..6b4e9a1 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.cpp
+++ b/src/libANGLE/renderer/d3d/RendererD3D.cpp
@@ -187,11 +187,6 @@
     return clearRenderTarget(context, renderTarget, gl::ColorF(0, 0, 0, 0), 1, 0);
 }
 
-void RendererD3D::onDirtyUniformBlockBinding(GLuint /*uniformBlockIndex*/)
-{
-    // No-op by default. Only implemented in D3D11.
-}
-
 unsigned int GetBlendSampleMask(const gl::State &glState, int samples)
 {
     unsigned int mask = 0;
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.h b/src/libANGLE/renderer/d3d/RendererD3D.h
index d4c64c4..c779dab 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.h
+++ b/src/libANGLE/renderer/d3d/RendererD3D.h
@@ -391,9 +391,6 @@
 
     virtual bool canSelectViewInVertexShader() const = 0;
 
-    // Should really be handled by Program dirty bits, but that requires splitting Program9/11.
-    virtual void onDirtyUniformBlockBinding(GLuint uniformBlockIndex);
-
   protected:
     virtual bool getLUID(LUID *adapterLuid) const                    = 0;
     virtual void generateCaps(gl::Caps *outCaps,
diff --git a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
index bccdb74..c9d6b3f 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
@@ -13,7 +13,6 @@
 #include "libANGLE/Context.h"
 #include "libANGLE/MemoryProgramCache.h"
 #include "libANGLE/renderer/d3d/CompilerD3D.h"
-#include "libANGLE/renderer/d3d/ProgramD3D.h"
 #include "libANGLE/renderer/d3d/RenderbufferD3D.h"
 #include "libANGLE/renderer/d3d/SamplerD3D.h"
 #include "libANGLE/renderer/d3d/ShaderD3D.h"
@@ -22,6 +21,7 @@
 #include "libANGLE/renderer/d3d/d3d11/Fence11.h"
 #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h"
 #include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h"
+#include "libANGLE/renderer/d3d/d3d11/Program11.h"
 #include "libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h"
 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
 #include "libANGLE/renderer/d3d/d3d11/StateManager11.h"
@@ -145,7 +145,7 @@
 
 ProgramImpl *Context11::createProgram(const gl::ProgramState &data)
 {
-    return new ProgramD3D(data, mRenderer);
+    return new Program11(data, mRenderer);
 }
 
 FramebufferImpl *Context11::createFramebuffer(const gl::FramebufferState &data)
diff --git a/src/libANGLE/renderer/d3d/d3d11/Program11.cpp b/src/libANGLE/renderer/d3d/d3d11/Program11.cpp
new file mode 100644
index 0000000..9060424
--- /dev/null
+++ b/src/libANGLE/renderer/d3d/d3d11/Program11.cpp
@@ -0,0 +1,34 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Program11: D3D11 implementation of an OpenGL Program.
+
+#include "libANGLE/renderer/d3d/d3d11/Program11.h"
+
+#include "libANGLE/Context.h"
+#include "libANGLE/renderer/d3d/d3d11/Context11.h"
+#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
+#include "libANGLE/renderer/d3d/d3d11/StateManager11.h"
+
+namespace rx
+{
+Program11::Program11(const gl::ProgramState &programState, Renderer11 *renderer)
+    : ProgramD3D(programState, renderer)
+{
+}
+
+Program11::~Program11() = default;
+
+gl::Error Program11::syncState(const gl::Context *context, const gl::Program::DirtyBits &dirtyBits)
+{
+    Renderer11 *renderer11       = GetImplAs<Context11>(context)->getRenderer();
+    StateManager11 *stateManager = renderer11->getStateManager();
+
+    // This single flag should be replace by individual dirtyness.
+    stateManager->invalidateProgramUniformBuffers();
+
+    return gl::NoError();
+}
+}  // namespace rx
diff --git a/src/libANGLE/renderer/d3d/d3d11/Program11.h b/src/libANGLE/renderer/d3d/d3d11/Program11.h
new file mode 100644
index 0000000..b2f9fff
--- /dev/null
+++ b/src/libANGLE/renderer/d3d/d3d11/Program11.h
@@ -0,0 +1,28 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Program11: D3D11 implementation of an OpenGL Program.
+
+#ifndef LIBANGLE_RENDERER_D3D_D3D11_PROGRAM11_H_
+#define LIBANGLE_RENDERER_D3D_D3D11_PROGRAM11_H_
+
+#include "libANGLE/renderer/d3d/ProgramD3D.h"
+
+namespace rx
+{
+class Renderer11;
+
+class Program11 : public ProgramD3D
+{
+  public:
+    Program11(const gl::ProgramState &programState, Renderer11 *renderer11);
+    ~Program11() override;
+
+    gl::Error syncState(const gl::Context *context,
+                        const gl::Program::DirtyBits &dirtyBits) override;
+};
+}  // namespace rx
+
+#endif  // LIBANGLE_RENDERER_D3D_D3D11_PROGRAM11_H_
\ No newline at end of file
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index b99a36c..9ad8f3d 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -29,7 +29,6 @@
 #include "libANGLE/renderer/d3d/DisplayD3D.h"
 #include "libANGLE/renderer/d3d/FramebufferD3D.h"
 #include "libANGLE/renderer/d3d/IndexDataManager.h"
-#include "libANGLE/renderer/d3d/ProgramD3D.h"
 #include "libANGLE/renderer/d3d/RenderbufferD3D.h"
 #include "libANGLE/renderer/d3d/ShaderD3D.h"
 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
@@ -44,6 +43,7 @@
 #include "libANGLE/renderer/d3d/d3d11/Image11.h"
 #include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h"
 #include "libANGLE/renderer/d3d/d3d11/PixelTransfer11.h"
+#include "libANGLE/renderer/d3d/d3d11/Program11.h"
 #include "libANGLE/renderer/d3d/d3d11/Query11.h"
 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
 #include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h"
@@ -3861,11 +3861,6 @@
     return angle::Result::Continue();
 }
 
-void Renderer11::onDirtyUniformBlockBinding(GLuint /*uniformBlockIndex*/)
-{
-    mStateManager.invalidateProgramUniformBuffers();
-}
-
 angle::Result Renderer11::getIncompleteTexture(const gl::Context *context,
                                                gl::TextureType type,
                                                gl::Texture **textureOut)
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
index 565c7e5..34789fb 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -471,8 +471,6 @@
 
     bool canSelectViewInVertexShader() const override;
 
-    void onDirtyUniformBlockBinding(GLuint uniformBlockIndex) override;
-
     angle::Result mapResource(const gl::Context *context,
                               ID3D11Resource *resource,
                               UINT subResource,
diff --git a/src/libANGLE/renderer/gl/ProgramGL.cpp b/src/libANGLE/renderer/gl/ProgramGL.cpp
index e3789c3..915a5d0 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.cpp
+++ b/src/libANGLE/renderer/gl/ProgramGL.cpp
@@ -942,4 +942,13 @@
     resources.atomicCounterBufferLinker.link(sizeMap);
 }
 
+gl::Error ProgramGL::syncState(const gl::Context *context, const gl::Program::DirtyBits &dirtyBits)
+{
+    for (size_t dirtyBit : dirtyBits)
+    {
+        ASSERT(dirtyBit <= gl::Program::DIRTY_BIT_UNIFORM_BLOCK_BINDING_MAX);
+        setUniformBlockBinding(dirtyBit, mState.getUniformBlockBinding(dirtyBit));
+    }
+    return gl::NoError();
+}
 }  // namespace rx
diff --git a/src/libANGLE/renderer/gl/ProgramGL.h b/src/libANGLE/renderer/gl/ProgramGL.h
index 3a39bc5..1f49e0f 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.h
+++ b/src/libANGLE/renderer/gl/ProgramGL.h
@@ -69,8 +69,6 @@
     void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
     void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
 
-    void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
-
     void setPathFragmentInputGen(const std::string &inputName,
                                  GLenum genMode,
                                  GLint components,
@@ -84,6 +82,9 @@
     void enableSideBySideRenderingPath() const;
     void enableLayeredRenderingPath(int baseViewIndex) const;
 
+    gl::Error syncState(const gl::Context *context,
+                        const gl::Program::DirtyBits &dirtyBits) override;
+
   private:
     void preLink();
     bool checkLinkStatus(gl::InfoLog &infoLog);
@@ -109,6 +110,7 @@
     void getAtomicCounterBufferSizeMap(std::map<int, unsigned int> *sizeMapOut) const;
 
     void linkResources(const gl::ProgramLinkedResources &resources);
+    void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding);
 
     // Helper function, makes it simpler to type.
     GLint uniLoc(GLint glLocation) const { return mUniformRealLocationMap[glLocation]; }
diff --git a/src/libANGLE/renderer/null/ProgramNULL.cpp b/src/libANGLE/renderer/null/ProgramNULL.cpp
index 31331be..c477fbb 100644
--- a/src/libANGLE/renderer/null/ProgramNULL.cpp
+++ b/src/libANGLE/renderer/null/ProgramNULL.cpp
@@ -179,10 +179,6 @@
     // TODO(jmadill): Write some values.
 }
 
-void ProgramNULL::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
-{
-}
-
 void ProgramNULL::setPathFragmentInputGen(const std::string &inputName,
                                           GLenum genMode,
                                           GLint components,
diff --git a/src/libANGLE/renderer/null/ProgramNULL.h b/src/libANGLE/renderer/null/ProgramNULL.h
index 745331a..5dd4804 100644
--- a/src/libANGLE/renderer/null/ProgramNULL.h
+++ b/src/libANGLE/renderer/null/ProgramNULL.h
@@ -86,9 +86,6 @@
     void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
     void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
 
-    // TODO: synchronize in syncState when dirty bits exist.
-    void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
-
     // CHROMIUM_path_rendering
     // Set parameters to control fragment shader input variable interpolation
     void setPathFragmentInputGen(const std::string &inputName,
diff --git a/src/libANGLE/renderer/vulkan/ProgramVk.cpp b/src/libANGLE/renderer/vulkan/ProgramVk.cpp
index f27e92d..2d140ee 100644
--- a/src/libANGLE/renderer/vulkan/ProgramVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ProgramVk.cpp
@@ -723,11 +723,6 @@
     setUniformMatrixfv<4, 3>(location, count, transpose, value);
 }
 
-void ProgramVk::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
-{
-    UNIMPLEMENTED();
-}
-
 void ProgramVk::setPathFragmentInputGen(const std::string &inputName,
                                         GLenum genMode,
                                         GLint components,
diff --git a/src/libANGLE/renderer/vulkan/ProgramVk.h b/src/libANGLE/renderer/vulkan/ProgramVk.h
index 4f9e58d..63985aa 100644
--- a/src/libANGLE/renderer/vulkan/ProgramVk.h
+++ b/src/libANGLE/renderer/vulkan/ProgramVk.h
@@ -90,9 +90,6 @@
     void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
     void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
 
-    // TODO: synchronize in syncState when dirty bits exist.
-    void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
-
     void setPathFragmentInputGen(const std::string &inputName,
                                  GLenum genMode,
                                  GLint components,
diff --git a/src/libGLESv2.gypi b/src/libGLESv2.gypi
index 2f26e22..46abe9f 100644
--- a/src/libGLESv2.gypi
+++ b/src/libGLESv2.gypi
@@ -455,6 +455,8 @@
             'libANGLE/renderer/d3d/d3d11/NativeWindow11.h',
             'libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp',
             'libANGLE/renderer/d3d/d3d11/PixelTransfer11.h',
+            'libANGLE/renderer/d3d/d3d11/Program11.cpp',
+            'libANGLE/renderer/d3d/d3d11/Program11.h',
             'libANGLE/renderer/d3d/d3d11/ProgramPipeline11.cpp',
             'libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h',
             'libANGLE/renderer/d3d/d3d11/Query11.cpp',
diff --git a/src/tests/gl_tests/ProgramBinaryTest.cpp b/src/tests/gl_tests/ProgramBinaryTest.cpp
index b6de1e9..e1a7aa5 100644
--- a/src/tests/gl_tests/ProgramBinaryTest.cpp
+++ b/src/tests/gl_tests/ProgramBinaryTest.cpp
@@ -349,10 +349,6 @@
 // http://anglebug.com/1637
 TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
 {
-    // TODO(jmadill): Investigate Intel failure.
-    // http://anglebug.com/1637
-    ANGLE_SKIP_TEST_IF(IsWindows() && IsOpenGL() && IsIntel());
-
     testBinaryAndUBOBlockIndexes(false);
 }