D3D11: Consolidate input layout application.

This merges all calls to IASetInputLayout to a single place in
StateManager11. This means we no longer have to invalidate the state
for D3D11, and can always lazily apply the input layout state.

Introduces a new ResourceSerial class to replace the uintptr_t and
DirtyPointer design.

BUG=angleproject:2052

Change-Id: I76b874218b754395f25a129967c769b1f8f82115
Reviewed-on: https://chromium-review.googlesource.com/523025
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp b/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
index b6adc6b..612ff80 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
@@ -951,7 +951,7 @@
     {
         ANGLE_TRY(mQuad2DIL.resolve(mRenderer));
         ANGLE_TRY(mQuad2DVS.resolve(mRenderer));
-        supportOut->inputLayout         = mQuad2DIL.get();
+        supportOut->inputLayout         = &mQuad2DIL.getObj();
         supportOut->vertexShader        = mQuad2DVS.get();
         supportOut->geometryShader      = nullptr;
         supportOut->vertexWriteFunction = Write2DVertices;
@@ -962,7 +962,7 @@
         ANGLE_TRY(mQuad3DIL.resolve(mRenderer));
         ANGLE_TRY(mQuad3DVS.resolve(mRenderer));
         ANGLE_TRY(mQuad3DGS.resolve(mRenderer));
-        supportOut->inputLayout         = mQuad2DIL.get();
+        supportOut->inputLayout         = &mQuad2DIL.getObj();
         supportOut->vertexShader        = mQuad3DVS.get();
         supportOut->geometryShader      = mQuad3DGS.get();
         supportOut->vertexWriteFunction = Write3DVertices;
@@ -1063,6 +1063,8 @@
 
     deviceContext->Unmap(mSwizzleCB.get(), 0);
 
+    auto stateManager = mRenderer->getStateManager();
+
     // Apply vertex buffer
     ID3D11Buffer *vertexBuffer = mVertexBuffer.get();
     deviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &startIdx);
@@ -1077,7 +1079,7 @@
     deviceContext->RSSetState(mScissorDisabledRasterizerState.get());
 
     // Apply shaders
-    deviceContext->IASetInputLayout(support.inputLayout);
+    stateManager->setInputLayout(support.inputLayout);
     deviceContext->IASetPrimitiveTopology(topology);
     deviceContext->VSSetShader(support.vertexShader, nullptr, 0);
 
@@ -1085,7 +1087,6 @@
     deviceContext->GSSetShader(support.geometryShader, nullptr, 0);
 
     // Unset the currently bound shader resource to avoid conflicts
-    auto stateManager = mRenderer->getStateManager();
     stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
 
     // Apply render target
@@ -1183,6 +1184,8 @@
 
     deviceContext->Unmap(mVertexBuffer.get(), 0);
 
+    auto stateManager = mRenderer->getStateManager();
+
     // Apply vertex buffer
     ID3D11Buffer *vertexBuffer = mVertexBuffer.get();
     deviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &startIdx);
@@ -1217,7 +1220,7 @@
     }
 
     // Apply shaders
-    deviceContext->IASetInputLayout(support.inputLayout);
+    stateManager->setInputLayout(support.inputLayout);
     deviceContext->IASetPrimitiveTopology(topology);
     deviceContext->VSSetShader(support.vertexShader, nullptr, 0);
 
@@ -1225,7 +1228,6 @@
     deviceContext->GSSetShader(support.geometryShader, nullptr, 0);
 
     // Unset the currently bound shader resource to avoid conflicts
-    auto stateManager = mRenderer->getStateManager();
     stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
 
     // Apply render target
@@ -1351,8 +1353,10 @@
     ANGLE_TRY(mQuad2DVS.resolve(mRenderer));
     ANGLE_TRY(mDepthPS.resolve(mRenderer));
 
+    auto stateManager = mRenderer->getStateManager();
+
     // Apply shaders
-    deviceContext->IASetInputLayout(mQuad2DIL.get());
+    stateManager->setInputLayout(&mQuad2DIL.getObj());
     deviceContext->IASetPrimitiveTopology(topology);
     deviceContext->VSSetShader(mQuad2DVS.get(), nullptr, 0);
 
@@ -1360,7 +1364,6 @@
     deviceContext->GSSetShader(nullptr, nullptr, 0);
 
     // Unset the currently bound shader resource to avoid conflicts
-    auto stateManager = mRenderer->getStateManager();
     stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
 
     // Apply render target
@@ -1984,6 +1987,7 @@
 
     const auto &extents          = depth->getExtents();
     ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+    auto *stateManager           = mRenderer->getStateManager();
 
     ANGLE_TRY(initResolveDepthOnly(depth->getFormatSet(), extents));
 
@@ -1994,7 +1998,7 @@
     ANGLE_TRY(mResolveDepthPS.resolve(mRenderer));
 
     // Apply the necessary state changes to the D3D11 immediate device context.
-    context->IASetInputLayout(nullptr);
+    stateManager->setInputLayout(nullptr);
     context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
     context->VSSetShader(mResolveDepthStencilVS.get(), nullptr, 0);
     context->GSSetShader(nullptr, nullptr, 0);
@@ -2116,7 +2120,7 @@
     ANGLE_TRY(initResolveDepthStencil(extents));
 
     ID3D11DeviceContext *context = mRenderer->getDeviceContext();
-
+    auto *stateManager              = mRenderer->getStateManager();
     ID3D11Resource *stencilResource = depthStencil->getTexture().get();
 
     // Check if we need to re-create the stencil SRV.
@@ -2151,7 +2155,7 @@
     ANGLE_TRY(mResolveDepthStencilVS.resolve(mRenderer));
 
     // Apply the necessary state changes to the D3D11 immediate device context.
-    context->IASetInputLayout(nullptr);
+    stateManager->setInputLayout(nullptr);
     context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
     context->VSSetShader(mResolveDepthStencilVS.get(), nullptr, 0);
     context->GSSetShader(nullptr, nullptr, 0);
diff --git a/src/libANGLE/renderer/d3d/d3d11/Blit11.h b/src/libANGLE/renderer/d3d/d3d11/Blit11.h
index f2fd7b5..ba783f2 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Blit11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Blit11.h
@@ -187,7 +187,7 @@
 
     struct ShaderSupport
     {
-        ID3D11InputLayout *inputLayout;
+        const d3d11::InputLayout *inputLayout;
         ID3D11VertexShader *vertexShader;
         ID3D11GeometryShader *geometryShader;
         WriteVertexFunction vertexWriteFunction;
diff --git a/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp b/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp
index cbfd645..d4093d9 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp
@@ -98,7 +98,7 @@
 
 gl::Error Clear11::ShaderManager::getShadersAndLayout(Renderer11 *renderer,
                                                       const INT clearType,
-                                                      ID3D11InputLayout **il,
+                                                      const d3d11::InputLayout **il,
                                                       ID3D11VertexShader **vs,
                                                       ID3D11PixelShader **ps)
 {
@@ -121,7 +121,7 @@
         }
 
         *vs = mVs9.get();
-        *il = mIl9.get();
+        *il = &mIl9;
         *ps = mPsFloat9.get();
         return gl::NoError();
     }
@@ -694,10 +694,12 @@
         deviceContext->RSSetState(mScissorDisabledRasterizerState.get());
     }
 
+    auto *stateManager = mRenderer->getStateManager();
+
     // Get Shaders
-    ID3D11VertexShader *vs = nullptr;
-    ID3D11InputLayout *il  = nullptr;
-    ID3D11PixelShader *ps  = nullptr;
+    ID3D11VertexShader *vs       = nullptr;
+    const d3d11::InputLayout *il = nullptr;
+    ID3D11PixelShader *ps        = nullptr;
 
     ANGLE_TRY(mShaderManager.getShadersAndLayout(mRenderer, clearParams.colorType, &il, &vs, &ps));
 
@@ -710,7 +712,7 @@
 
     // Bind IL & VB if needed
     deviceContext->IASetIndexBuffer(nullptr, DXGI_FORMAT_UNKNOWN, 0);
-    deviceContext->IASetInputLayout(il);
+    stateManager->setInputLayout(il);
 
     if (useVertexBuffer())
     {
@@ -727,7 +729,7 @@
     deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
 
     // Apply render targets
-    mRenderer->getStateManager()->setOneTimeRenderTargets(&rtvs[0], numRtvs, dsv);
+    stateManager->setOneTimeRenderTargets(&rtvs[0], numRtvs, dsv);
 
     // Draw the fullscreen quad
     deviceContext->Draw(6, 0);
diff --git a/src/libANGLE/renderer/d3d/d3d11/Clear11.h b/src/libANGLE/renderer/d3d/d3d11/Clear11.h
index 0b22522..78ad66f 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Clear11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Clear11.h
@@ -49,7 +49,7 @@
         ~ShaderManager();
         gl::Error getShadersAndLayout(Renderer11 *renderer,
                                       const INT clearType,
-                                      ID3D11InputLayout **il,
+                                      const d3d11::InputLayout **il,
                                       ID3D11VertexShader **vs,
                                       ID3D11PixelShader **ps);
 
diff --git a/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
index 7773806..468509b 100644
--- a/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
@@ -172,10 +172,7 @@
 }
 
 InputLayoutCache::InputLayoutCache()
-    : mCurrentIL(angle::DirtyPointer),
-      mPointSpriteVertexBuffer(),
-      mPointSpriteIndexBuffer(),
-      mCacheSize(kDefaultCacheSize)
+    : mPointSpriteVertexBuffer(), mPointSpriteIndexBuffer(), mCacheSize(kDefaultCacheSize)
 {
     mCurrentBuffers.fill(nullptr);
     mCurrentVertexStrides.fill(std::numeric_limits<UINT>::max());
@@ -185,7 +182,6 @@
 
 InputLayoutCache::~InputLayoutCache()
 {
-    clear();
 }
 
 void InputLayoutCache::initialize()
@@ -203,7 +199,6 @@
 
 void InputLayoutCache::markDirty()
 {
-    mCurrentIL = angle::DirtyPointer;
     for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     {
         mCurrentBuffers[i]       = nullptr;
@@ -494,13 +489,13 @@
         layout.addAttributeData(glslElementType, d3dSemantic, vertexFormatType, binding.divisor);
     }
 
-    ID3D11InputLayout *inputLayout = nullptr;
+    const d3d11::InputLayout *inputLayout = nullptr;
     if (layout.numAttributes > 0 || layout.flags != 0)
     {
         auto layoutMapIt = mLayoutMap.find(layout);
         if (layoutMapIt != mLayoutMap.end())
         {
-            inputLayout = layoutMapIt->second.get();
+            inputLayout = &layoutMapIt->second;
         }
         else
         {
@@ -525,18 +520,12 @@
                 }
             }
 
-            inputLayout        = newInputLayout.get();
-            mLayoutMap[layout] = std::move(newInputLayout);
+            auto result = mLayoutMap.insert(std::make_pair(layout, std::move(newInputLayout)));
+            inputLayout = &result.first->second;
         }
     }
 
-    if (reinterpret_cast<uintptr_t>(inputLayout) != mCurrentIL)
-    {
-        ID3D11DeviceContext *deviceContext = renderer->getDeviceContext();
-        deviceContext->IASetInputLayout(inputLayout);
-        mCurrentIL = reinterpret_cast<uintptr_t>(inputLayout);
-    }
-
+    renderer->getStateManager()->setInputLayout(inputLayout);
     return gl::NoError();
 }
 
diff --git a/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h b/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h
index b506cca..2a09ad2 100644
--- a/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h
+++ b/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h
@@ -105,7 +105,6 @@
 
     std::map<PackedAttributeLayout, d3d11::InputLayout> mLayoutMap;
 
-    uintptr_t mCurrentIL;
     std::array<ID3D11Buffer *, gl::MAX_VERTEX_ATTRIBS> mCurrentBuffers;
     std::array<UINT, gl::MAX_VERTEX_ATTRIBS> mCurrentVertexStrides;
     std::array<UINT, gl::MAX_VERTEX_ATTRIBS> mCurrentVertexOffsets;
diff --git a/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp
index 48d4bbd..163233e 100644
--- a/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp
@@ -192,7 +192,7 @@
     deviceContext->GSSetShader(geometryShader, nullptr, 0);
     deviceContext->PSSetShader(pixelShader, nullptr, 0);
     stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, bufferSRV);
-    deviceContext->IASetInputLayout(nullptr);
+    stateManager->setInputLayout(nullptr);
     deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
 
     deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero);
diff --git a/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h b/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h
index 2f684e8..6bed5ee 100644
--- a/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.h
@@ -16,6 +16,7 @@
 #include "common/angleutils.h"
 #include "common/debug.h"
 #include "libANGLE/Error.h"
+#include "libANGLE/renderer/renderer_utils.h"
 
 namespace rx
 {
@@ -175,6 +176,11 @@
 
     void reset() { mData.reset(new DataT()); }
 
+    ResourceSerial getSerial() const
+    {
+        return ResourceSerial(reinterpret_cast<uintptr_t>(mData->object));
+    }
+
   protected:
     friend class TextureHelper11;
 
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
index 506ed87..fd6173c 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
@@ -159,7 +159,8 @@
       mViewportBounds(),
       mRenderTargetIsDirty(false),
       mDirtyCurrentValueAttribs(),
-      mCurrentValueAttribs()
+      mCurrentValueAttribs(),
+      mCurrentInputLayout()
 {
     mCurBlendState.blend                 = false;
     mCurBlendState.sourceBlendRGB        = GL_ONE;
@@ -819,6 +820,9 @@
     // anymore. For example when a currently used SRV is used as an RTV, D3D silently
     // remove it from its state.
     invalidateBoundViews();
+
+    // All calls to IASetInputLayout go through the state manager, so it shouldn't be
+    // necessary to invalidate the state.
 }
 
 void StateManager11::setOneTimeRenderTarget(ID3D11RenderTargetView *rtv,
@@ -1137,4 +1141,22 @@
     return mCurrentValueAttribs;
 }
 
+void StateManager11::setInputLayout(const d3d11::InputLayout *inputLayout)
+{
+    ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+    if (inputLayout == nullptr)
+    {
+        if (mCurrentInputLayout != 0)
+        {
+            deviceContext->IASetInputLayout(nullptr);
+            mCurrentInputLayout = 0;
+        }
+    }
+    else if (inputLayout->getSerial() != mCurrentInputLayout)
+    {
+        deviceContext->IASetInputLayout(inputLayout->get());
+        mCurrentInputLayout = inputLayout->getSerial();
+    }
+}
+
 }  // namespace rx
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.h b/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
index f9dea00..76a3118 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
@@ -106,6 +106,8 @@
 
     const std::vector<TranslatedAttribute> &getCurrentValueAttribs() const;
 
+    void setInputLayout(const d3d11::InputLayout *inputLayout);
+
   private:
     void setViewportBounds(const int width, const int height);
     void unsetConflictingSRVs(gl::SamplerType shaderType,
@@ -207,6 +209,9 @@
     // Current translations of "Current-Value" data - owned by Context, not VertexArray.
     gl::AttributesMask mDirtyCurrentValueAttribs;
     std::vector<TranslatedAttribute> mCurrentValueAttribs;
+
+    // Current applied input layout.
+    ResourceSerial mCurrentInputLayout;
 };
 
 }  // namespace rx
diff --git a/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
index 64f576e..857f739 100644
--- a/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
@@ -782,15 +782,15 @@
 
     deviceContext->RSSetState(mPassThroughRS.get());
 
+    auto stateManager = mRenderer->getStateManager();
+
     // Apply shaders
-    deviceContext->IASetInputLayout(mPassThroughIL.get());
+    stateManager->setInputLayout(&mPassThroughIL);
     deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
     deviceContext->VSSetShader(mPassThroughVS.get(), nullptr, 0);
     deviceContext->PSSetShader(mPassThroughPS.get(), nullptr, 0);
     deviceContext->GSSetShader(nullptr, nullptr, 0);
 
-    auto stateManager = mRenderer->getStateManager();
-
     // Apply render targets
     stateManager->setOneTimeRenderTarget(mBackBufferRTView.get(), nullptr);
 
diff --git a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
index 3c1275d..99853d6 100644
--- a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
+++ b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
@@ -199,6 +199,8 @@
         return mResource.get();
     }
 
+    const Resource11<GetD3D11Type<ResourceT>> &getObj() const { return mResource; }
+
   protected:
     gl::Error resolveImpl(Renderer11 *renderer,
                           const GetDescType<ResourceT> &desc,
diff --git a/src/libANGLE/renderer/renderer_utils.h b/src/libANGLE/renderer/renderer_utils.h
index 803c8c2..a146d0f 100644
--- a/src/libANGLE/renderer/renderer_utils.h
+++ b/src/libANGLE/renderer/renderer_utils.h
@@ -12,6 +12,7 @@
 
 #include <cstdint>
 
+#include <limits>
 #include <map>
 
 #include "libANGLE/angletypes.h"
@@ -30,6 +31,22 @@
 namespace rx
 {
 
+class ResourceSerial
+{
+  public:
+    constexpr ResourceSerial() : mValue(kDirty) {}
+    constexpr ResourceSerial(uintptr_t value) : mValue(value) {}
+    constexpr bool operator==(ResourceSerial other) const { return mValue == other.mValue; }
+    constexpr bool operator!=(ResourceSerial other) const { return mValue != other.mValue; }
+
+    void dirty() { mValue = kDirty; }
+
+  private:
+    constexpr static uintptr_t kDirty = std::numeric_limits<uintptr_t>::max();
+
+    uintptr_t mValue;
+};
+
 using MipGenerationFunction = void (*)(size_t sourceWidth,
                                        size_t sourceHeight,
                                        size_t sourceDepth,