diff --git a/src/d3d10/d3d10_device.cpp b/src/d3d10/d3d10_device.cpp
index 3f604547..83f41f57 100644
--- a/src/d3d10/d3d10_device.cpp
+++ b/src/d3d10/d3d10_device.cpp
@@ -8,10 +8,9 @@ namespace dxvk {
   D3D10Device::D3D10Device(
           D3D11Device*                      pDevice,
           D3D11ImmediateContext*            pContext)
-  : m_device(pDevice), m_context(pContext) {
-    // Respecting the single-threaded flag may improve performance
-    UINT flags = pDevice->GetCreationFlags();
-    m_threadSafe = !(flags & D3D10_CREATE_DEVICE_SINGLETHREADED);
+  : m_device(pDevice), m_context(pContext),
+    m_multithread(this, !(pDevice->GetCreationFlags() & D3D10_CREATE_DEVICE_SINGLETHREADED)) {
+    
   }
 
   
diff --git a/src/d3d10/d3d10_device.h b/src/d3d10/d3d10_device.h
index df9d50fd..e8d917e2 100644
--- a/src/d3d10/d3d10_device.h
+++ b/src/d3d10/d3d10_device.h
@@ -1,12 +1,9 @@
 #pragma once
 
-#include "d3d10_include.h"
+#include "d3d10_multithread.h"
 
 namespace dxvk {
 
-  using D3D10DeviceMutex = sync::Spinlock;
-  using D3D10DeviceLock = std::unique_lock<D3D10DeviceMutex>;
-  
   class D3D11Device;
   class D3D11ImmediateContext;
 
@@ -474,18 +471,18 @@ namespace dxvk {
             UINT*                             pHeight);
     
     D3D10DeviceLock LockDevice() {
-      return m_threadSafe
-        ? D3D10DeviceLock(m_mutex)
-        : D3D10DeviceLock();
+      return m_multithread.AcquireLock();
+    }
+
+    D3D10Multithread* GetMultithread() {
+      return &m_multithread;
     }
     
   private:
 
-    D3D10DeviceMutex        m_mutex;
     D3D11Device*            m_device;
     D3D11ImmediateContext*  m_context;
-
-    bool m_threadSafe = true;
+    D3D10Multithread        m_multithread;
 
   };
 
diff --git a/src/d3d10/d3d10_multithread.cpp b/src/d3d10/d3d10_multithread.cpp
new file mode 100644
index 00000000..bc93e92e
--- /dev/null
+++ b/src/d3d10/d3d10_multithread.cpp
@@ -0,0 +1,90 @@
+#include "d3d10_device.h"
+
+namespace dxvk {
+
+  void D3D10DeviceMutex::lock() {
+    while (!try_lock())
+      dxvk::this_thread::yield();
+  }
+
+
+  void D3D10DeviceMutex::unlock() {
+    if (likely(m_counter == 0))
+      m_owner.store(0, std::memory_order_release);
+    else
+      m_counter -= 1;
+  }
+
+
+  bool D3D10DeviceMutex::try_lock() {
+    uint32_t threadId = GetCurrentThreadId();
+    uint32_t expected = 0;
+
+    bool status = m_owner.compare_exchange_weak(
+      expected, threadId, std::memory_order_acquire);
+    
+    if (status)
+      return true;
+    
+    if (expected != threadId)
+      return false;
+    
+    m_counter += 1;
+    return true;
+  }
+
+
+  D3D10Multithread::D3D10Multithread(
+          IUnknown*             pParent,
+          BOOL                  Protected)
+  : m_parent    (pParent),
+    m_protected (Protected) {
+    
+  }
+
+
+  D3D10Multithread::~D3D10Multithread() {
+
+  }
+
+
+  ULONG STDMETHODCALLTYPE D3D10Multithread::AddRef() {
+    return m_parent->AddRef();
+  }
+
+  
+  ULONG STDMETHODCALLTYPE D3D10Multithread::Release() {
+    return m_parent->Release();
+  }
+
+  
+  HRESULT STDMETHODCALLTYPE D3D10Multithread::QueryInterface(
+          REFIID                riid,
+          void**                ppvObject) {
+    return m_parent->QueryInterface(riid, ppvObject);
+  }
+
+  
+  void STDMETHODCALLTYPE D3D10Multithread::Enter() {
+    if (m_protected)
+      m_mutex.lock();
+  }
+
+
+  void STDMETHODCALLTYPE D3D10Multithread::Leave() {
+    if (m_protected)
+      m_mutex.unlock();
+  }
+
+
+  BOOL STDMETHODCALLTYPE D3D10Multithread::SetMultithreadProtected(
+          BOOL                  bMTProtect) {
+    return std::exchange(m_protected, bMTProtect);
+  }
+
+
+  BOOL STDMETHODCALLTYPE D3D10Multithread::GetMultithreadProtected() {
+    return m_protected;
+  }
+
+}
\ No newline at end of file
diff --git a/src/d3d10/d3d10_multithread.h b/src/d3d10/d3d10_multithread.h
new file mode 100644
index 00000000..f29ee8c7
--- /dev/null
+++ b/src/d3d10/d3d10_multithread.h
@@ -0,0 +1,127 @@
+#pragma once
+
+#include "d3d10_include.h"
+
+namespace dxvk {
+  
+  /**
+   * \brief Device mutex
+   * 
+   * Effectively implements a recursive spinlock
+   * which is used to lock the D3D10 device.
+   */
+  class D3D10DeviceMutex {
+
+  public:
+
+    void lock();
+
+    void unlock();
+
+    bool try_lock();
+
+  private:
+
+    std::atomic<uint32_t> m_owner   = { 0u };
+    uint32_t              m_counter = { 0u };
+    
+  };
+
+
+  /**
+   * \brief Device lock
+   * 
+   * Lightweight RAII wrapper that implements
+   * a subset of the functionality provided by
+   * \c std::unique_lock, with the goal of being
+   * cheaper to construct and destroy.
+   */  
+  class D3D10DeviceLock {
+
+  public:
+
+    D3D10DeviceLock()
+    : m_mutex(nullptr) { }
+
+    D3D10DeviceLock(D3D10DeviceMutex& mutex)
+    : m_mutex(&mutex) {
+      mutex.lock();
+    }
+
+    D3D10DeviceLock(D3D10DeviceLock&& other)
+    : m_mutex(other.m_mutex) {
+      other.m_mutex = nullptr;
+    }
+
+    D3D10DeviceLock& operator = (D3D10DeviceLock&& other) {
+      if (m_mutex)
+        m_mutex->unlock();
+      
+      m_mutex = other.m_mutex;
+      other.m_mutex = nullptr;
+      return *this;
+    }
+
+    ~D3D10DeviceLock() {
+      if (unlikely(m_mutex != nullptr))
+        m_mutex->unlock();
+    }
+
+  private:
+
+    D3D10DeviceMutex* m_mutex;
+    
+  };
+
+  
+  /**
+   * \brief D3D10 device and D3D11 context lock
+   * 
+   * Can be queried from the D3D10 device or from
+   * any D3D11 context in order to make individual
+   * calls thread-safe. Provides methods to lock
+   * the device or context explicitly.
+   */
+  class D3D10Multithread : public ID3D10Multithread {
+
+  public:
+
+    D3D10Multithread(
+            IUnknown*             pParent,
+            BOOL                  Protected);
+    
+    ~D3D10Multithread();
+
+    ULONG STDMETHODCALLTYPE AddRef() final;
+    
+    ULONG STDMETHODCALLTYPE Release() final;
+    
+    HRESULT STDMETHODCALLTYPE QueryInterface(
+            REFIID                riid,
+            void**                ppvObject) final;
+    
+    void STDMETHODCALLTYPE Enter() final;
+
+    void STDMETHODCALLTYPE Leave() final;
+
+    BOOL STDMETHODCALLTYPE SetMultithreadProtected(
+            BOOL                  bMTProtect) final;
+
+    BOOL STDMETHODCALLTYPE GetMultithreadProtected() final;
+
+    D3D10DeviceLock AcquireLock() {
+      return unlikely(m_protected)
+        ? D3D10DeviceLock(m_mutex)
+        : D3D10DeviceLock();
+    }
+    
+  private:
+
+    IUnknown* m_parent;
+    BOOL      m_protected;
+
+    D3D10DeviceMutex m_mutex;
+
+  };
+
+}
\ No newline at end of file
diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp
index e62b53f0..684593a1 100644
--- a/src/d3d11/d3d11_device.cpp
+++ b/src/d3d11/d3d11_device.cpp
@@ -72,6 +72,11 @@ namespace dxvk {
       *ppvObject = ref(m_d3d11Presenter);
       return S_OK;
     }
+
+    if (riid == __uuidof(ID3D10Multithread)) {
+      *ppvObject = ref(m_d3d11Device->GetD3D10Multithread());
+      return S_OK;
+    }
     
     if (riid == __uuidof(ID3D11Debug))
       return E_NOINTERFACE;      
diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h
index 718d33ce..4049e6b2 100644
--- a/src/d3d11/d3d11_device.h
+++ b/src/d3d11/d3d11_device.h
@@ -345,6 +345,10 @@ namespace dxvk {
     D3D10Device* GetD3D10Interface() const {
       return m_d3d10Device;
     }
+
+    D3D10Multithread* GetD3D10Multithread() const {
+      return m_d3d10Device->GetMultithread();
+    }
     
     DxvkBufferSlice AllocUavCounterSlice() { return m_uavCounters->AllocSlice(); }
     DxvkBufferSlice AllocXfbCounterSlice() { return m_xfbCounters->AllocSlice(); }
diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build
index a604e687..3e687038 100644
--- a/src/d3d11/meson.build
+++ b/src/d3d11/meson.build
@@ -8,6 +8,7 @@ d3d10_src = [
   '../d3d10/d3d10_depth_stencil.cpp',
   '../d3d10/d3d10_device.cpp',
   '../d3d10/d3d10_input_layout.cpp',
+  '../d3d10/d3d10_multithread.cpp',
   '../d3d10/d3d10_query.cpp',
   '../d3d10/d3d10_rasterizer.cpp',
   '../d3d10/d3d10_sampler.cpp',