[d3d10] Implement D3D10Multithread

This commit is contained in:
Philip Rebohle 2018-11-29 20:13:36 +01:00
parent d1f179c5af
commit 28216909bd
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
7 changed files with 237 additions and 14 deletions

View File

@ -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)) {
}

View File

@ -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;
};

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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;

View File

@ -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(); }

View File

@ -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',