StateManager11: Cache impl objects.

Also requires putting the Framebuffer ID in the shared state object.

Bug: angleproject:2575
Change-Id: I68e3af839a85798e01050560a67624a165d3ed2c
Reviewed-on: https://chromium-review.googlesource.com/1067119
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index 4bb4837..a50253d 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -252,7 +252,8 @@
 
 // This constructor is only used for default framebuffers.
 FramebufferState::FramebufferState()
-    : mLabel(),
+    : mId(0),
+      mLabel(),
       mColorAttachments(1),
       mDrawBufferStates(1, GL_BACK),
       mReadBufferState(GL_BACK),
@@ -268,8 +269,9 @@
     mEnabledDrawBuffers.set(0);
 }
 
-FramebufferState::FramebufferState(const Caps &caps)
-    : mLabel(),
+FramebufferState::FramebufferState(const Caps &caps, GLuint id)
+    : mId(id),
+      mLabel(),
       mColorAttachments(caps.maxColorAttachments),
       mDrawBufferStates(caps.maxDrawBuffers, GL_NONE),
       mReadBufferState(GL_COLOR_ATTACHMENT0_EXT),
@@ -281,6 +283,7 @@
       mDefaultLayers(0),
       mWebGLDepthStencilConsistent(true)
 {
+    ASSERT(mId != 0);
     ASSERT(mDrawBufferStates.size() > 0);
     mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
 }
@@ -613,14 +616,12 @@
 }
 
 Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
-    : mState(caps),
+    : mState(caps, id),
       mImpl(factory->createFramebuffer(mState)),
-      mId(id),
       mCachedStatus(),
       mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
       mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
 {
-    ASSERT(mId != 0);
     ASSERT(mImpl != nullptr);
     ASSERT(mState.mColorAttachments.size() == static_cast<size_t>(caps.maxColorAttachments));
 
@@ -634,7 +635,6 @@
 Framebuffer::Framebuffer(const egl::Display *display, egl::Surface *surface)
     : mState(),
       mImpl(surface->getImplementation()->createDefaultFramebuffer(mState)),
-      mId(0),
       mCachedStatus(GL_FRAMEBUFFER_COMPLETE),
       mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
       mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
@@ -673,7 +673,6 @@
 Framebuffer::Framebuffer(rx::GLImplFactory *factory)
     : mState(),
       mImpl(factory->createFramebuffer(mState)),
-      mId(0),
       mCachedStatus(GL_FRAMEBUFFER_UNDEFINED_OES),
       mDirtyDepthAttachmentBinding(this, DIRTY_BIT_DEPTH_ATTACHMENT),
       mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
@@ -972,7 +971,7 @@
 
 void Framebuffer::invalidateCompletenessCache()
 {
-    if (mId != 0)
+    if (mState.mId != 0)
     {
         mCachedStatus.reset();
     }
@@ -983,7 +982,7 @@
     // The default framebuffer is always complete except when it is surfaceless in which
     // case it is always unsupported. We return early because the default framebuffer may
     // not be subject to the same rules as application FBOs. ie, it could have 0x0 size.
-    if (mId == 0)
+    if (mState.mId == 0)
     {
         ASSERT(mCachedStatus.valid());
         ASSERT(mCachedStatus.value() == GL_FRAMEBUFFER_COMPLETE ||
@@ -1017,7 +1016,7 @@
 {
     const ContextState &state = context->getContextState();
 
-    ASSERT(mId != 0);
+    ASSERT(mState.mId != 0);
 
     bool hasAttachments = false;
     Optional<unsigned int> colorbufferSize;
@@ -1762,7 +1761,7 @@
 
     // Only reset the cached status if this is not the default framebuffer.  The default framebuffer
     // will still use this channel to mark itself dirty.
-    if (mId != 0)
+    if (mState.mId != 0)
     {
         // TOOD(jmadill): Make this only update individual attachments to do less work.
         mCachedStatus.reset();
@@ -1799,7 +1798,7 @@
     const Program *program = state.getProgram();
 
     // TODO(jmadill): Default framebuffer feedback loops.
-    if (mId == 0)
+    if (mState.mId == 0)
     {
         return false;
     }
@@ -1861,7 +1860,7 @@
                                                GLint copyTextureLevel,
                                                GLint copyTextureLayer) const
 {
-    if (mId == 0)
+    if (mState.mId == 0)
     {
         // It seems impossible to form a texture copying feedback loop with the default FBO.
         return false;
diff --git a/src/libANGLE/Framebuffer.h b/src/libANGLE/Framebuffer.h
index e03bb0d..aa6e1b0 100644
--- a/src/libANGLE/Framebuffer.h
+++ b/src/libANGLE/Framebuffer.h
@@ -53,7 +53,7 @@
 {
   public:
     FramebufferState();
-    explicit FramebufferState(const Caps &caps);
+    explicit FramebufferState(const Caps &caps, GLuint id);
     ~FramebufferState();
 
     const std::string &getLabel();
@@ -99,6 +99,8 @@
     const std::vector<Offset> *getViewportOffsets() const;
     GLint getBaseViewIndex() const;
 
+    GLuint id() const { return mId; }
+
   private:
     const FramebufferAttachment *getWebGLDepthStencilAttachment() const;
     const FramebufferAttachment *getWebGLDepthAttachment() const;
@@ -106,6 +108,7 @@
 
     friend class Framebuffer;
 
+    GLuint mId;
     std::string mLabel;
 
     std::vector<FramebufferAttachment> mColorAttachments;
@@ -152,7 +155,7 @@
 
     rx::FramebufferImpl *getImplementation() const { return mImpl; }
 
-    GLuint id() const { return mId; }
+    GLuint id() const { return mState.mId; }
 
     void setAttachment(const Context *context,
                        GLenum type,
@@ -386,7 +389,6 @@
 
     FramebufferState mState;
     rx::FramebufferImpl *mImpl;
-    GLuint mId;
 
     Optional<GLenum> mCachedStatus;
     std::vector<angle::ObserverBinding> mDirtyColorAttachmentBindings;
diff --git a/src/libANGLE/renderer/ProgramImpl.h b/src/libANGLE/renderer/ProgramImpl.h
index 1580311..09b6f87 100644
--- a/src/libANGLE/renderer/ProgramImpl.h
+++ b/src/libANGLE/renderer/ProgramImpl.h
@@ -98,6 +98,8 @@
     {
     }
 
+    const gl::ProgramState &getState() const { return mState; }
+
   protected:
     const gl::ProgramState &mState;
 };
diff --git a/src/libANGLE/renderer/VertexArrayImpl.h b/src/libANGLE/renderer/VertexArrayImpl.h
index c15e816..6491ba1 100644
--- a/src/libANGLE/renderer/VertexArrayImpl.h
+++ b/src/libANGLE/renderer/VertexArrayImpl.h
@@ -43,6 +43,8 @@
     virtual void destroy(const gl::Context *context) {}
     virtual ~VertexArrayImpl() {}
 
+    const gl::VertexArrayState &getState() const { return mState; }
+
   protected:
     const gl::VertexArrayState &mState;
 };
diff --git a/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp b/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp
index 5b85196..f5b08d8 100644
--- a/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp
@@ -44,11 +44,10 @@
 
 // static
 d3d11::BlendStateKey RenderStateCache::GetBlendStateKey(const gl::Context *context,
-                                                        const gl::Framebuffer *framebuffer,
+                                                        FramebufferD3D *framebufferD3D,
                                                         const gl::BlendState &blendState)
 {
     d3d11::BlendStateKey key;
-    FramebufferD3D *framebufferD3D         = GetImplAs<FramebufferD3D>(framebuffer);
     const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(context);
     const UINT8 blendStateMask =
         gl_d3d11::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen,
diff --git a/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h b/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h
index 7501e83..9f686df 100644
--- a/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h
+++ b/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h
@@ -61,6 +61,7 @@
 
 namespace rx
 {
+class FramebufferD3D;
 class Renderer11;
 
 class RenderStateCache : angle::NonCopyable
@@ -72,7 +73,7 @@
     void clear();
 
     static d3d11::BlendStateKey GetBlendStateKey(const gl::Context *context,
-                                                 const gl::Framebuffer *framebuffer,
+                                                 FramebufferD3D *framebufferD3D,
                                                  const gl::BlendState &blendState);
     gl::Error getBlendState(Renderer11 *renderer,
                             const d3d11::BlendStateKey &key,
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
index 155a3b7..fce15f9 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
@@ -139,7 +139,7 @@
     return Optional<size_t>::Invalid();
 }
 
-void SortAttributesByLayout(const gl::Program *program,
+void SortAttributesByLayout(const ProgramD3D &programD3D,
                             const std::vector<TranslatedAttribute> &vertexArrayAttribs,
                             const std::vector<TranslatedAttribute> &currentValueAttribs,
                             AttribIndexArray *sortedD3DSemanticsOut,
@@ -147,10 +147,9 @@
 {
     sortedAttributesOut->clear();
 
-    const auto &locationToSemantic =
-        GetImplAs<ProgramD3D>(program)->getAttribLocationToD3DSemantics();
+    const AttribIndexArray &locationToSemantic = programD3D.getAttribLocationToD3DSemantics();
 
-    for (auto locationIndex : program->getActiveAttribLocationsMask())
+    for (auto locationIndex : programD3D.getState().getActiveAttribLocationsMask())
     {
         int d3dSemantic = locationToSemantic[locationIndex];
         if (sortedAttributesOut->size() <= static_cast<size_t>(d3dSemantic))
@@ -591,7 +590,10 @@
       mVertexDataManager(renderer),
       mIndexDataManager(renderer),
       mIsMultiviewEnabled(false),
-      mEmptySerial(mRenderer->generateSerial())
+      mEmptySerial(mRenderer->generateSerial()),
+      mProgramD3D(nullptr),
+      mVertexArray11(nullptr),
+      mFramebuffer11(nullptr)
 {
     mCurBlendState.blend                 = false;
     mCurBlendState.sourceBlendRGB        = GL_ONE;
@@ -745,9 +747,7 @@
     mShaderConstants.setComputeWorkGroups(numGroupsX, numGroupsY, numGroupsZ);
 
     // TODO(jmadill): Use dirty bits.
-    const auto &glState = context->getGLState();
-    auto *programD3D    = GetImplAs<ProgramD3D>(glState.getProgram());
-    programD3D->updateSamplerMapping();
+    mProgramD3D->updateSamplerMapping();
 
     // TODO(jmadill): Use dirty bits.
     ANGLE_TRY(generateSwizzlesForShader(context, gl::ShaderType::Compute));
@@ -997,6 +997,7 @@
                 {
                     handleMultiviewDrawFramebufferChange(context);
                 }
+                mFramebuffer11 = GetImplAs<Framebuffer11>(state.getDrawFramebuffer());
                 break;
             case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
                 invalidateVertexBuffer();
@@ -1006,6 +1007,7 @@
                 mDirtyCurrentValueAttribs.set();
                 // Invalidate the cached index buffer.
                 invalidateIndexBuffer();
+                mVertexArray11 = GetImplAs<VertexArray11>(state.getVertexArray());
                 break;
             case gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS:
                 invalidateProgramUniformBuffers();
@@ -1019,6 +1021,9 @@
             case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
                 invalidateTransformFeedback();
                 break;
+            case gl::State::DIRTY_BIT_PROGRAM_BINDING:
+                mProgramD3D = GetImplAs<ProgramD3D>(state.getProgram());
+                break;
             case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
             {
                 mInternalDirtyBits.set(DIRTY_BIT_PRIMITIVE_TOPOLOGY);
@@ -1029,17 +1034,14 @@
                 invalidateProgramUniforms();
                 invalidateProgramUniformBuffers();
                 invalidateDriverUniforms();
-                if (mIsMultiviewEnabled)
+                // If ANGLE_multiview is enabled, the attribute divisor has to be updated for each
+                // binding. When using compute, there could be no vertex array.
+                if (mIsMultiviewEnabled && mVertexArray11)
                 {
-                    gl::VertexArray *vao = state.getVertexArray();
-                    ASSERT(vao);
-                    // If ANGLE_multiview is enabled, the attribute divisor has to be updated for
-                    // each binding.
-                    VertexArray11 *vao11       = GetImplAs<VertexArray11>(vao);
-                    const gl::Program *program = state.getProgram();
-                    ASSERT(program);
-                    int numViews = program->usesMultiview() ? program->getNumViews() : 1;
-                    vao11->markAllAttributeDivisorsForAdjustment(numViews);
+                    ASSERT(mProgramD3D);
+                    const gl::ProgramState &programState = mProgramD3D->getState();
+                    int numViews = programState.usesMultiview() ? programState.getNumViews() : 1;
+                    mVertexArray11->markAllAttributeDivisorsForAdjustment(numViews);
                 }
                 break;
             }
@@ -1100,14 +1102,13 @@
 }
 
 gl::Error StateManager11::syncBlendState(const gl::Context *context,
-                                         const gl::Framebuffer *framebuffer,
                                          const gl::BlendState &blendState,
                                          const gl::ColorF &blendColor,
                                          unsigned int sampleMask)
 {
     const d3d11::BlendState *dxBlendState = nullptr;
     const d3d11::BlendStateKey &key =
-        RenderStateCache::GetBlendStateKey(context, framebuffer, blendState);
+        RenderStateCache::GetBlendStateKey(context, mFramebuffer11, blendState);
 
     ANGLE_TRY(mRenderer->getBlendState(key, &dxBlendState));
 
@@ -1381,14 +1382,9 @@
 
 void StateManager11::processFramebufferInvalidation(const gl::Context *context)
 {
-    if (!mRenderTargetIsDirty)
-    {
-        return;
-    }
-
+    ASSERT(mRenderTargetIsDirty);
     ASSERT(context);
 
-    mRenderTargetIsDirty = false;
     mInternalDirtyBits.set(DIRTY_BIT_RENDER_TARGET);
 
     // The pixel shader is dependent on the output layout.
@@ -1709,20 +1705,20 @@
 }
 
 void StateManager11::unsetConflictingAttachmentResources(
-    const gl::FramebufferAttachment *attachment,
+    const gl::FramebufferAttachment &attachment,
     ID3D11Resource *resource)
 {
     // Unbind render target SRVs from the shader here to prevent D3D11 warnings.
-    if (attachment->type() == GL_TEXTURE)
+    if (attachment.type() == GL_TEXTURE)
     {
         uintptr_t resourcePtr       = reinterpret_cast<uintptr_t>(resource);
-        const gl::ImageIndex &index = attachment->getTextureImageIndex();
+        const gl::ImageIndex &index = attachment.getTextureImageIndex();
         // The index doesn't need to be corrected for the small compressed texture workaround
         // because a rendertarget is never compressed.
         unsetConflictingSRVs(gl::ShaderType::Vertex, resourcePtr, &index);
         unsetConflictingSRVs(gl::ShaderType::Fragment, resourcePtr, &index);
     }
-    else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT)
+    else if (attachment.type() == GL_FRAMEBUFFER_DEFAULT)
     {
         uintptr_t resourcePtr = reinterpret_cast<uintptr_t>(resource);
         unsetConflictingSRVs(gl::ShaderType::Vertex, resourcePtr, nullptr);
@@ -1785,36 +1781,32 @@
     mPointSpriteIndexBuffer.reset();
 }
 
-gl::Error StateManager11::syncFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer)
+// Applies the render target surface, depth stencil surface, viewport rectangle and
+// scissor rectangle to the renderer
+gl::Error StateManager11::syncFramebuffer(const gl::Context *context)
 {
-    Framebuffer11 *framebuffer11 = GetImplAs<Framebuffer11>(framebuffer);
-
-    // Applies the render target surface, depth stencil surface, viewport rectangle and
-    // scissor rectangle to the renderer
-    ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit());
-
     // Check for zero-sized default framebuffer, which is a special case.
     // in this case we do not wish to modify any state and just silently return false.
     // this will not report any gl error but will cause the calling method to return.
-    if (framebuffer->id() == 0)
+    if (mFramebuffer11->getState().id() == 0)
     {
-        const gl::Extents &size = framebuffer->getFirstColorbuffer()->getSize();
-        if (size.width == 0 || size.height == 0)
+        RenderTarget11 *firstRT = mFramebuffer11->getFirstRenderTarget();
+        const gl::Extents &size = firstRT->getExtents();
+        if (size.empty())
         {
             return gl::NoError();
         }
     }
 
     RTVArray framebufferRTVs = {{}};
-
-    const auto &colorRTs = framebuffer11->getCachedColorRenderTargets();
+    const auto &colorRTs     = mFramebuffer11->getCachedColorRenderTargets();
 
     size_t appliedRTIndex  = 0;
     bool skipInactiveRTs   = mRenderer->getWorkarounds().mrtPerfWorkaround;
-    const auto &drawStates = framebuffer->getDrawBufferStates();
-    gl::DrawBufferMask activeProgramOutputs =
-        context->getContextState().getState().getProgram()->getActiveOutputVariables();
+    const auto &drawStates                  = mFramebuffer11->getState().getDrawBufferStates();
+    gl::DrawBufferMask activeProgramOutputs = mProgramD3D->getState().getActiveOutputVariables();
     UINT maxExistingRT = 0;
+    const auto &colorAttachments            = mFramebuffer11->getState().getColorAttachments();
 
     for (size_t rtIndex = 0; rtIndex < colorRTs.size(); ++rtIndex)
     {
@@ -1834,8 +1826,8 @@
             maxExistingRT = static_cast<UINT>(appliedRTIndex) + 1;
 
             // Unset conflicting texture SRVs
-            const auto *attachment = framebuffer->getColorbuffer(rtIndex);
-            ASSERT(attachment);
+            const gl::FramebufferAttachment &attachment = colorAttachments[rtIndex];
+            ASSERT(attachment.isAttached());
             unsetConflictingAttachmentResources(attachment, renderTarget->getTexture().get());
         }
 
@@ -1844,16 +1836,17 @@
 
     // Get the depth stencil buffers
     ID3D11DepthStencilView *framebufferDSV = nullptr;
-    const auto *depthStencilRenderTarget   = framebuffer11->getCachedDepthStencilRenderTarget();
+    const auto *depthStencilRenderTarget   = mFramebuffer11->getCachedDepthStencilRenderTarget();
     if (depthStencilRenderTarget)
     {
         framebufferDSV = depthStencilRenderTarget->getDepthStencilView().get();
         ASSERT(framebufferDSV);
 
         // Unset conflicting texture SRVs
-        const auto *attachment = framebuffer->getDepthOrStencilbuffer();
+        const gl::FramebufferAttachment *attachment =
+            mFramebuffer11->getState().getDepthOrStencilAttachment();
         ASSERT(attachment);
-        unsetConflictingAttachmentResources(attachment,
+        unsetConflictingAttachmentResources(*attachment,
                                             depthStencilRenderTarget->getTexture().get());
     }
 
@@ -1875,9 +1868,10 @@
     invalidateShaders();
 }
 
-gl::Error StateManager11::syncCurrentValueAttribs(const gl::State &glState)
+gl::Error StateManager11::syncCurrentValueAttribs(
+    const std::vector<gl::VertexAttribCurrentValueData> &currentValues)
 {
-    const auto &activeAttribsMask  = glState.getProgram()->getActiveAttribLocationsMask();
+    const auto &activeAttribsMask  = mProgramD3D->getState().getActiveAttribLocationsMask();
     const auto &dirtyActiveAttribs = (activeAttribsMask & mDirtyCurrentValueAttribs);
 
     if (!dirtyActiveAttribs.any())
@@ -1885,8 +1879,8 @@
         return gl::NoError();
     }
 
-    const auto &vertexAttributes = glState.getVertexArray()->getVertexAttributes();
-    const auto &vertexBindings   = glState.getVertexArray()->getVertexBindings();
+    const auto &vertexAttributes = mVertexArray11->getState().getVertexAttributes();
+    const auto &vertexBindings   = mVertexArray11->getState().getVertexBindings();
     mDirtyCurrentValueAttribs    = (mDirtyCurrentValueAttribs & ~dirtyActiveAttribs);
 
     for (auto attribIndex : dirtyActiveAttribs)
@@ -1895,7 +1889,7 @@
             continue;
 
         const auto *attrib                      = &vertexAttributes[attribIndex];
-        const auto &currentValue                = glState.getVertexAttribCurrentValue(attribIndex);
+        const auto &currentValue                = currentValues[attribIndex];
         TranslatedAttribute *currentValueAttrib = &mCurrentValueAttribs[attribIndex];
         currentValueAttrib->currentValueType    = currentValue.Type;
         currentValueAttrib->attribute           = attrib;
@@ -1993,19 +1987,22 @@
                                       const gl::DrawCallParams &drawCallParams)
 {
     const gl::State &glState = context->getGLState();
-    auto *programD3D         = GetImplAs<ProgramD3D>(glState.getProgram());
 
     // TODO(jmadill): Use dirty bits.
-    processFramebufferInvalidation(context);
+    if (mRenderTargetIsDirty)
+    {
+        processFramebufferInvalidation(context);
+        mRenderTargetIsDirty = false;
+    }
 
     // TODO(jmadill): Use dirty bits.
-    if (programD3D->updateSamplerMapping() == ProgramD3D::SamplerMapping::WasDirty)
+    if (mProgramD3D->updateSamplerMapping() == ProgramD3D::SamplerMapping::WasDirty)
     {
         invalidateTexturesAndSamplers();
     }
 
     // TODO(jmadill): Use dirty bits.
-    if (programD3D->anyShaderUniformsDirty())
+    if (mProgramD3D->anyShaderUniformsDirty())
     {
         mInternalDirtyBits.set(DIRTY_BIT_PROGRAM_UNIFORMS);
     }
@@ -2017,13 +2014,11 @@
         mDirtySwizzles = false;
     }
 
-    gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
-    Framebuffer11 *framebuffer11 = GetImplAs<Framebuffer11>(framebuffer);
-    ANGLE_TRY(framebuffer11->markAttachmentsDirty(context));
+    ANGLE_TRY(mFramebuffer11->markAttachmentsDirty(context));
 
     // TODO(jiawei.shao@intel.com): This can be recomputed only on framebuffer or multisample mask
     // state changes.
-    RenderTarget11 *firstRT = framebuffer11->getFirstRenderTarget();
+    RenderTarget11 *firstRT = mFramebuffer11->getFirstRenderTarget();
     int samples             = (firstRT ? firstRT->getSamples() : 0);
     unsigned int sampleMask = GetBlendSampleMask(glState, samples);
     if (sampleMask != mCurSampleMask)
@@ -2031,8 +2026,7 @@
         mInternalDirtyBits.set(DIRTY_BIT_BLEND_STATE);
     }
 
-    VertexArray11 *vao11 = GetImplAs<VertexArray11>(glState.getVertexArray());
-    ANGLE_TRY(vao11->syncStateForDraw(context, drawCallParams));
+    ANGLE_TRY(mVertexArray11->syncStateForDraw(context, drawCallParams));
 
     // Changes in the draw call can affect the vertex buffer translations.
     if (!mLastFirstVertex.valid() || mLastFirstVertex.value() != drawCallParams.firstVertex())
@@ -2069,7 +2063,7 @@
         switch (dirtyBit)
         {
             case DIRTY_BIT_RENDER_TARGET:
-                ANGLE_TRY(syncFramebuffer(context, framebuffer));
+                ANGLE_TRY(syncFramebuffer(context));
                 break;
             case DIRTY_BIT_VIEWPORT_STATE:
                 syncViewport(context);
@@ -2081,8 +2075,8 @@
                 ANGLE_TRY(syncRasterizerState(context, drawCallParams));
                 break;
             case DIRTY_BIT_BLEND_STATE:
-                ANGLE_TRY(syncBlendState(context, framebuffer, glState.getBlendState(),
-                                         glState.getBlendColor(), sampleMask));
+                ANGLE_TRY(syncBlendState(context, glState.getBlendState(), glState.getBlendColor(),
+                                         sampleMask));
                 break;
             case DIRTY_BIT_DEPTH_STENCIL_STATE:
                 ANGLE_TRY(syncDepthStencilState(glState));
@@ -2092,20 +2086,20 @@
                 ANGLE_TRY(syncTextures(context));
                 break;
             case DIRTY_BIT_PROGRAM_UNIFORMS:
-                ANGLE_TRY(applyUniforms(programD3D));
+                ANGLE_TRY(applyUniforms());
                 break;
             case DIRTY_BIT_DRIVER_UNIFORMS:
                 // This must happen after viewport sync; the viewport affects builtin uniforms.
-                ANGLE_TRY(applyDriverUniforms(*programD3D));
+                ANGLE_TRY(applyDriverUniforms());
                 break;
             case DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS:
-                ANGLE_TRY(syncUniformBuffers(context, programD3D));
+                ANGLE_TRY(syncUniformBuffers(context));
                 break;
             case DIRTY_BIT_SHADERS:
                 ANGLE_TRY(syncProgram(context, drawCallParams.mode()));
                 break;
             case DIRTY_BIT_CURRENT_VALUE_ATTRIBS:
-                ANGLE_TRY(syncCurrentValueAttribs(glState));
+                ANGLE_TRY(syncCurrentValueAttribs(glState.getVertexAttribCurrentValues()));
                 break;
             case DIRTY_BIT_TRANSFORM_FEEDBACK:
                 ANGLE_TRY(syncTransformFeedbackBuffers(context));
@@ -2114,7 +2108,7 @@
                 ANGLE_TRY(syncVertexBuffersAndInputLayout(context, drawCallParams));
                 break;
             case DIRTY_BIT_PRIMITIVE_TOPOLOGY:
-                syncPrimitiveTopology(glState, programD3D, drawCallParams.mode());
+                syncPrimitiveTopology(glState, drawCallParams.mode());
                 break;
             default:
                 UNREACHABLE();
@@ -2394,17 +2388,16 @@
     ASSERT(shaderType != gl::ShaderType::Compute);
     const auto &glState    = context->getGLState();
     const auto &caps       = context->getCaps();
-    ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
 
-    ASSERT(!programD3D->isSamplerMappingDirty());
+    ASSERT(!mProgramD3D->isSamplerMappingDirty());
 
     // TODO(jmadill): Use the Program's sampler bindings.
     const auto &completeTextures = glState.getCompleteTextureCache();
 
-    unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType);
+    unsigned int samplerRange = mProgramD3D->getUsedSamplerRange(shaderType);
     for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
     {
-        GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps);
+        GLint textureUnit = mProgramD3D->getSamplerMapping(shaderType, samplerIndex, caps);
         ASSERT(textureUnit != -1);
         gl::Texture *texture = completeTextures[textureUnit];
 
@@ -2422,7 +2415,7 @@
         else
         {
             gl::TextureType textureType =
-                programD3D->getSamplerTextureType(shaderType, samplerIndex);
+                mProgramD3D->getSamplerTextureType(shaderType, samplerIndex);
 
             // Texture is not sampler complete or it is in use by the framebuffer.  Bind the
             // incomplete texture.
@@ -2578,26 +2571,25 @@
 {
     const auto &glState    = context->getGLState();
     const auto &caps       = context->getCaps();
-    ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
 
     // TODO(xinghua.cao@intel.com): Implement sampler feature in compute shader.
-    unsigned int readonlyImageRange = programD3D->getUsedImageRange(gl::ShaderType::Compute, true);
+    unsigned int readonlyImageRange = mProgramD3D->getUsedImageRange(gl::ShaderType::Compute, true);
     for (unsigned int readonlyImageIndex = 0; readonlyImageIndex < readonlyImageRange;
          readonlyImageIndex++)
     {
         GLint imageUnitIndex =
-            programD3D->getImageMapping(gl::ShaderType::Compute, readonlyImageIndex, true, caps);
+            mProgramD3D->getImageMapping(gl::ShaderType::Compute, readonlyImageIndex, true, caps);
         ASSERT(imageUnitIndex != -1);
         const gl::ImageUnit &imageUnit = glState.getImageUnit(imageUnitIndex);
         ANGLE_TRY(setTextureForImage(context, gl::ShaderType::Compute, readonlyImageIndex, true,
                                      imageUnit));
     }
 
-    unsigned int imageRange = programD3D->getUsedImageRange(gl::ShaderType::Compute, false);
+    unsigned int imageRange = mProgramD3D->getUsedImageRange(gl::ShaderType::Compute, false);
     for (unsigned int imageIndex = 0; imageIndex < imageRange; imageIndex++)
     {
         GLint imageUnitIndex =
-            programD3D->getImageMapping(gl::ShaderType::Compute, imageIndex, false, caps);
+            mProgramD3D->getImageMapping(gl::ShaderType::Compute, imageIndex, false, caps);
         ASSERT(imageUnitIndex != -1);
         const gl::ImageUnit &imageUnit = glState.getImageUnit(imageUnitIndex);
         ANGLE_TRY(
@@ -2672,25 +2664,23 @@
     ANGLE_TRY(context11->triggerDrawCallProgramRecompilation(context, drawMode));
 
     const auto &glState = context->getGLState();
-    const auto *va11    = GetImplAs<VertexArray11>(glState.getVertexArray());
-    auto *programD3D    = GetImplAs<ProgramD3D>(glState.getProgram());
 
-    programD3D->updateCachedInputLayout(va11->getCurrentStateSerial(), glState);
+    mProgramD3D->updateCachedInputLayout(mVertexArray11->getCurrentStateSerial(), glState);
 
     // Binaries must be compiled before the sync.
-    ASSERT(programD3D->hasVertexExecutableForCachedInputLayout());
-    ASSERT(programD3D->hasGeometryExecutableForPrimitiveType(drawMode));
-    ASSERT(programD3D->hasPixelExecutableForCachedOutputLayout());
+    ASSERT(mProgramD3D->hasVertexExecutableForCachedInputLayout());
+    ASSERT(mProgramD3D->hasGeometryExecutableForPrimitiveType(drawMode));
+    ASSERT(mProgramD3D->hasPixelExecutableForCachedOutputLayout());
 
     ShaderExecutableD3D *vertexExe = nullptr;
-    ANGLE_TRY(programD3D->getVertexExecutableForCachedInputLayout(&vertexExe, nullptr));
+    ANGLE_TRY(mProgramD3D->getVertexExecutableForCachedInputLayout(&vertexExe, nullptr));
 
     ShaderExecutableD3D *pixelExe = nullptr;
-    ANGLE_TRY(programD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr));
+    ANGLE_TRY(mProgramD3D->getPixelExecutableForCachedOutputLayout(&pixelExe, nullptr));
 
     ShaderExecutableD3D *geometryExe = nullptr;
-    ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context, drawMode, &geometryExe,
-                                                                nullptr));
+    ANGLE_TRY(mProgramD3D->getGeometryExecutableForPrimitiveType(context, drawMode, &geometryExe,
+                                                                 nullptr));
 
     const d3d11::VertexShader *vertexShader =
         (vertexExe ? &GetAs<ShaderExecutable11>(vertexExe)->getVertexShader() : nullptr);
@@ -2725,16 +2715,11 @@
 gl::Error StateManager11::syncVertexBuffersAndInputLayout(const gl::Context *context,
                                                           const gl::DrawCallParams &drawCallParams)
 {
-    const gl::State &state             = context->getGLState();
-    const gl::VertexArray *vertexArray = state.getVertexArray();
-    VertexArray11 *vertexArray11       = GetImplAs<VertexArray11>(vertexArray);
-
-    const auto &vertexArrayAttribs = vertexArray11->getTranslatedAttribs();
-    gl::Program *program           = state.getProgram();
+    const auto &vertexArrayAttribs = mVertexArray11->getTranslatedAttribs();
 
     // Sort the attributes according to ensure we re-use similar input layouts.
     AttribIndexArray sortedSemanticIndices;
-    SortAttributesByLayout(program, vertexArrayAttribs, mCurrentValueAttribs,
+    SortAttributesByLayout(*mProgramD3D, vertexArrayAttribs, mCurrentValueAttribs,
                            &sortedSemanticIndices, &mCurrentAttributes);
 
     D3D_FEATURE_LEVEL featureLevel = mRenderer->getRenderer11DeviceCaps().featureLevel;
@@ -2755,6 +2740,7 @@
     }
 
     // Update the applied input layout by querying the cache.
+    const gl::State &state                = context->getGLState();
     const d3d11::InputLayout *inputLayout = nullptr;
     ANGLE_TRY(mInputLayoutCache.getInputLayout(
         mRenderer, state, mCurrentAttributes, sortedSemanticIndices, drawCallParams, &inputLayout));
@@ -2769,12 +2755,8 @@
 gl::Error StateManager11::applyVertexBuffers(const gl::Context *context,
                                              const gl::DrawCallParams &drawCallParams)
 {
-    const gl::State &state = context->getGLState();
-    gl::Program *program   = state.getProgram();
-    ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
-
     bool programUsesInstancedPointSprites =
-        programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation();
+        mProgramD3D->usesPointSize() && mProgramD3D->usesInstancedPointSpriteEmulation();
     bool instancedPointSpritesActive =
         programUsesInstancedPointSprites && (drawCallParams.mode() == gl::PrimitiveMode::Points);
 
@@ -2805,9 +2787,8 @@
             }
             else if (instancedPointSpritesActive && drawCallParams.isDrawElements())
             {
-                VertexArray11 *vao11 = GetImplAs<VertexArray11>(state.getVertexArray());
-                ASSERT(vao11->isCachedIndexInfoValid());
-                TranslatedIndexData indexInfo = vao11->getCachedIndexInfo();
+                ASSERT(mVertexArray11->isCachedIndexInfoValid());
+                TranslatedIndexData indexInfo = mVertexArray11->getCachedIndexInfo();
                 if (indexInfo.srcIndexData.srcBuffer != nullptr)
                 {
                     const uint8_t *bufferData = nullptr;
@@ -2825,7 +2806,7 @@
                                                             attrib, drawCallParams.firstVertex()),
                     buffer);
 
-                vao11->updateCachedIndexInfo(indexInfo);
+                mVertexArray11->updateCachedIndexInfo(indexInfo);
             }
             else
             {
@@ -2921,18 +2902,14 @@
 gl::Error StateManager11::applyIndexBuffer(const gl::Context *context,
                                            const gl::DrawCallParams &params)
 {
-    const auto &glState  = context->getGLState();
-    gl::VertexArray *vao = glState.getVertexArray();
-    VertexArray11 *vao11 = GetImplAs<VertexArray11>(vao);
-
     if (!mIndexBufferIsDirty)
     {
         // No streaming or index buffer application necessary.
         return gl::NoError();
     }
 
-    GLenum destElementType         = vao11->getCachedDestinationIndexType();
-    gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
+    GLenum destElementType         = mVertexArray11->getCachedDestinationIndexType();
+    gl::Buffer *elementArrayBuffer = mVertexArray11->getState().getElementArrayBuffer().get();
 
     TranslatedIndexData indexInfo;
     ANGLE_TRY(mIndexDataManager.prepareIndexData(context, params.type(), destElementType,
@@ -2960,7 +2937,7 @@
 
     mIndexBufferIsDirty = false;
 
-    vao11->updateCachedIndexInfo(indexInfo);
+    mVertexArray11->updateCachedIndexInfo(indexInfo);
     return gl::NoError();
 }
 
@@ -3044,15 +3021,13 @@
 
 gl::Error StateManager11::generateSwizzlesForShader(const gl::Context *context, gl::ShaderType type)
 {
-    const auto &glState    = context->getGLState();
-    ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
-
-    unsigned int samplerRange = programD3D->getUsedSamplerRange(type);
+    const gl::State &glState  = context->getGLState();
+    unsigned int samplerRange = mProgramD3D->getUsedSamplerRange(type);
 
     for (unsigned int i = 0; i < samplerRange; i++)
     {
-        gl::TextureType textureType = programD3D->getSamplerTextureType(type, i);
-        GLint textureUnit           = programD3D->getSamplerMapping(type, i, context->getCaps());
+        gl::TextureType textureType = mProgramD3D->getSamplerTextureType(type, i);
+        GLint textureUnit           = mProgramD3D->getSamplerMapping(type, i, context->getCaps());
         if (textureUnit != -1)
         {
             gl::Texture *texture = glState.getSamplerTexture(textureUnit, textureType);
@@ -3074,12 +3049,12 @@
     return gl::NoError();
 }
 
-gl::Error StateManager11::applyUniforms(ProgramD3D *programD3D)
+gl::Error StateManager11::applyUniforms()
 {
     UniformStorage11 *vertexUniformStorage =
-        GetAs<UniformStorage11>(programD3D->getShaderUniformStorage(gl::ShaderType::Vertex));
+        GetAs<UniformStorage11>(mProgramD3D->getShaderUniformStorage(gl::ShaderType::Vertex));
     UniformStorage11 *fragmentUniformStorage =
-        GetAs<UniformStorage11>(programD3D->getShaderUniformStorage(gl::ShaderType::Fragment));
+        GetAs<UniformStorage11>(mProgramD3D->getShaderUniformStorage(gl::ShaderType::Fragment));
     ASSERT(vertexUniformStorage);
     ASSERT(fragmentUniformStorage);
 
@@ -3091,13 +3066,13 @@
     ANGLE_TRY(fragmentUniformStorage->getConstantBuffer(mRenderer, &pixelConstantBuffer));
 
     if (vertexUniformStorage->size() > 0 &&
-        programD3D->areShaderUniformsDirty(gl::ShaderType::Vertex))
+        mProgramD3D->areShaderUniformsDirty(gl::ShaderType::Vertex))
     {
         UpdateUniformBuffer(deviceContext, vertexUniformStorage, vertexConstantBuffer);
     }
 
     if (fragmentUniformStorage->size() > 0 &&
-        programD3D->areShaderUniformsDirty(gl::ShaderType::Fragment))
+        mProgramD3D->areShaderUniformsDirty(gl::ShaderType::Fragment))
     {
         UpdateUniformBuffer(deviceContext, fragmentUniformStorage, pixelConstantBuffer);
     }
@@ -3120,12 +3095,12 @@
         mCurrentConstantBufferPSSize[slot]   = 0;
     }
 
-    programD3D->markUniformsClean();
+    mProgramD3D->markUniformsClean();
 
     return gl::NoError();
 }
 
-gl::Error StateManager11::applyDriverUniforms(const ProgramD3D &programD3D)
+gl::Error StateManager11::applyDriverUniforms()
 {
     ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
 
@@ -3157,9 +3132,9 @@
 
     // Sampler metadata and driver constants need to coexist in the same constant buffer to conserve
     // constant buffer slots. We update both in the constant buffer if needed.
-    ANGLE_TRY(mShaderConstants.updateBuffer(mRenderer, gl::ShaderType::Vertex, programD3D,
+    ANGLE_TRY(mShaderConstants.updateBuffer(mRenderer, gl::ShaderType::Vertex, *mProgramD3D,
                                             mDriverConstantBufferVS));
-    ANGLE_TRY(mShaderConstants.updateBuffer(mRenderer, gl::ShaderType::Fragment, programD3D,
+    ANGLE_TRY(mShaderConstants.updateBuffer(mRenderer, gl::ShaderType::Fragment, *mProgramD3D,
                                             mDriverConstantBufferPS));
 
     // needed for the point sprite geometry shader
@@ -3221,15 +3196,15 @@
     return gl::NoError();
 }
 
-gl::Error StateManager11::syncUniformBuffers(const gl::Context *context, ProgramD3D *programD3D)
+gl::Error StateManager11::syncUniformBuffers(const gl::Context *context)
 {
     gl::ShaderMap<unsigned int> shaderReservedUBOs = mRenderer->getReservedShaderUniformBuffers();
-    programD3D->updateUniformBufferCache(context->getCaps(), shaderReservedUBOs);
+    mProgramD3D->updateUniformBufferCache(context->getCaps(), shaderReservedUBOs);
 
     const auto &vertexUniformBuffers =
-        programD3D->getShaderUniformBufferCache(gl::ShaderType::Vertex);
+        mProgramD3D->getShaderUniformBufferCache(gl::ShaderType::Vertex);
     const auto &fragmentUniformBuffers =
-        programD3D->getShaderUniformBufferCache(gl::ShaderType::Fragment);
+        mProgramD3D->getShaderUniformBufferCache(gl::ShaderType::Fragment);
     const auto &glState                  = context->getGLState();
     ID3D11DeviceContext *deviceContext   = mRenderer->getDeviceContext();
     ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
@@ -3449,7 +3424,6 @@
 }
 
 void StateManager11::syncPrimitiveTopology(const gl::State &glState,
-                                           ProgramD3D *programD3D,
                                            gl::PrimitiveMode currentDrawMode)
 {
     D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
@@ -3458,7 +3432,7 @@
     {
         case gl::PrimitiveMode::Points:
         {
-            bool usesPointSize = programD3D->usesPointSize();
+            bool usesPointSize = mProgramD3D->usesPointSize();
 
             // ProgramBinary assumes non-point rendering if gl_PointSize isn't written,
             // which affects varying interpolation. Since the value of gl_PointSize is
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.h b/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
index d38aba0..d7d9fcb 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
@@ -18,14 +18,15 @@
 #include "libANGLE/renderer/d3d/RendererD3D.h"
 #include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h"
 #include "libANGLE/renderer/d3d/d3d11/Query11.h"
-#include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h"
 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
 
 namespace rx
 {
 class Buffer11;
+class Framebuffer11;
 struct RenderTargetDesc;
 struct Renderer11DeviceCaps;
+class VertexArray11;
 
 class ShaderConstants11 : angle::NonCopyable
 {
@@ -261,11 +262,10 @@
     bool unsetConflictingSRVs(gl::ShaderType shaderType,
                               uintptr_t resource,
                               const gl::ImageIndex *index);
-    void unsetConflictingAttachmentResources(const gl::FramebufferAttachment *attachment,
+    void unsetConflictingAttachmentResources(const gl::FramebufferAttachment &attachment,
                                              ID3D11Resource *resource);
 
     gl::Error syncBlendState(const gl::Context *context,
-                             const gl::Framebuffer *framebuffer,
                              const gl::BlendState &blendState,
                              const gl::ColorF &blendColor,
                              unsigned int sampleMask);
@@ -281,7 +281,7 @@
 
     void checkPresentPath(const gl::Context *context);
 
-    gl::Error syncFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer);
+    gl::Error syncFramebuffer(const gl::Context *context);
     gl::Error syncProgram(const gl::Context *context, gl::PrimitiveMode drawMode);
 
     gl::Error syncTextures(const gl::Context *context);
@@ -308,16 +308,17 @@
     gl::Error clearUAVs(gl::ShaderType shaderType, size_t rangeStart, size_t rangeEnd);
     void handleMultiviewDrawFramebufferChange(const gl::Context *context);
 
-    gl::Error syncCurrentValueAttribs(const gl::State &glState);
+    gl::Error syncCurrentValueAttribs(
+        const std::vector<gl::VertexAttribCurrentValueData> &currentValues);
 
     gl::Error generateSwizzle(const gl::Context *context, gl::Texture *texture);
     gl::Error generateSwizzlesForShader(const gl::Context *context, gl::ShaderType type);
     gl::Error generateSwizzles(const gl::Context *context);
 
-    gl::Error applyDriverUniforms(const ProgramD3D &programD3D);
-    gl::Error applyUniforms(ProgramD3D *programD3D);
+    gl::Error applyDriverUniforms();
+    gl::Error applyUniforms();
 
-    gl::Error syncUniformBuffers(const gl::Context *context, ProgramD3D *programD3D);
+    gl::Error syncUniformBuffers(const gl::Context *context);
     gl::Error syncTransformFeedbackBuffers(const gl::Context *context);
 
     // These are currently only called internally.
@@ -344,9 +345,7 @@
                                  UINT offset);
     void applyVertexBufferChanges();
     bool setPrimitiveTopologyInternal(D3D11_PRIMITIVE_TOPOLOGY primitiveTopology);
-    void syncPrimitiveTopology(const gl::State &glState,
-                               ProgramD3D *programD3D,
-                               gl::PrimitiveMode currentDrawMode);
+    void syncPrimitiveTopology(const gl::State &glState, gl::PrimitiveMode currentDrawMode);
 
     // Not handled by an internal dirty bit because it isn't synced on drawArrays calls.
     gl::Error applyIndexBuffer(const gl::Context *context,
@@ -575,6 +574,11 @@
     Serial mAppliedTFSerial;
 
     Serial mEmptySerial;
+
+    // These objects are cached to avoid having to query the impls.
+    ProgramD3D *mProgramD3D;
+    VertexArray11 *mVertexArray11;
+    Framebuffer11 *mFramebuffer11;
 };
 
 }  // namespace rx