diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp
index e7ab7e9e..62bb9844 100644
--- a/src/d3d11/d3d11_context.cpp
+++ b/src/d3d11/d3d11_context.cpp
@@ -1235,8 +1235,18 @@ namespace dxvk {
     auto inputLayout = static_cast<D3D11InputLayout*>(pInputLayout);
     
     if (m_state.ia.inputLayout != inputLayout) {
+      bool equal = false;
+      
+      // Some games (e.g. Grim Dawn) create lots and lots of
+      // identical input layouts, so we'll only apply the state
+      // if the input layouts has actually changed between calls.
+      if (m_state.ia.inputLayout != nullptr && inputLayout != nullptr)
+        equal = m_state.ia.inputLayout->Compare(inputLayout);
+      
       m_state.ia.inputLayout = inputLayout;
-      ApplyInputLayout();
+      
+      if (!equal)
+        ApplyInputLayout();
     }
   }
   
diff --git a/src/d3d11/d3d11_input_layout.cpp b/src/d3d11/d3d11_input_layout.cpp
index a19aa915..2e4e794f 100644
--- a/src/d3d11/d3d11_input_layout.cpp
+++ b/src/d3d11/d3d11_input_layout.cpp
@@ -4,11 +4,11 @@
 namespace dxvk {
   
   D3D11InputLayout::D3D11InputLayout(
-          D3D11Device*                pDevice,
-          uint32_t                    numAttributes,
-    const DxvkVertexAttribute*        pAttributes,
-          uint32_t                    numBindings,
-    const DxvkVertexBinding*          pBindings)
+          D3D11Device*          pDevice,
+          uint32_t              numAttributes,
+    const DxvkVertexAttribute*  pAttributes,
+          uint32_t              numBindings,
+    const DxvkVertexBinding*    pBindings)
   : m_device(pDevice) {
     m_attributes.resize(numAttributes);
     m_bindings.resize(numBindings);
@@ -55,4 +55,25 @@ namespace dxvk {
       m_bindings.data());
   }
   
+  
+  bool D3D11InputLayout::Compare(const D3D11InputLayout* pOther) const {
+    bool eq = m_attributes.size() == pOther->m_attributes.size()
+           && m_bindings.size()   == pOther->m_bindings.size();
+    
+    for (uint32_t i = 0; eq && i < m_attributes.size(); i++) {
+      eq &= m_attributes[i].location == pOther->m_attributes[i].location
+         && m_attributes[i].binding  == pOther->m_attributes[i].binding
+         && m_attributes[i].format   == pOther->m_attributes[i].format
+         && m_attributes[i].offset   == pOther->m_attributes[i].offset;
+    }
+    
+    for (uint32_t i = 0; eq && i < m_bindings.size(); i++) {
+      eq &= m_bindings[i].binding    == pOther->m_bindings[i].binding
+         && m_bindings[i].fetchRate  == pOther->m_bindings[i].fetchRate
+         && m_bindings[i].inputRate  == pOther->m_bindings[i].inputRate;
+    }
+    
+    return eq;
+  }
+  
 }
diff --git a/src/d3d11/d3d11_input_layout.h b/src/d3d11/d3d11_input_layout.h
index cfe068d3..e3d33d1d 100644
--- a/src/d3d11/d3d11_input_layout.h
+++ b/src/d3d11/d3d11_input_layout.h
@@ -11,23 +11,26 @@ namespace dxvk {
   public:
     
     D3D11InputLayout(
-            D3D11Device*                pDevice,
-            uint32_t                    numAttributes,
-      const DxvkVertexAttribute*        pAttributes,
-            uint32_t                    numBindings,
-      const DxvkVertexBinding*          pBindings);
+            D3D11Device*          pDevice,
+            uint32_t              numAttributes,
+      const DxvkVertexAttribute*  pAttributes,
+            uint32_t              numBindings,
+      const DxvkVertexBinding*    pBindings);
     
     ~D3D11InputLayout();
     
     HRESULT STDMETHODCALLTYPE QueryInterface(
-            REFIID  riid,
-            void**  ppvObject) final;
+            REFIID                riid,
+            void**                ppvObject) final;
     
     void STDMETHODCALLTYPE GetDevice(
-            ID3D11Device **ppDevice) final;
+            ID3D11Device**        ppDevice) final;
     
     void BindToContext(
-      const Rc<DxvkContext>& ctx);
+      const Rc<DxvkContext>&      ctx);
+    
+    bool Compare(
+      const D3D11InputLayout*     pOther) const;
     
   private: