mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 19:54:19 +01:00
[d3d10] Implement D3D10Multithread
This commit is contained in:
parent
d1f179c5af
commit
28216909bd
@ -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)) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
90
src/d3d10/d3d10_multithread.cpp
Normal file
90
src/d3d10/d3d10_multithread.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
127
src/d3d10/d3d10_multithread.h
Normal file
127
src/d3d10/d3d10_multithread.h
Normal 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;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -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(); }
|
||||
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user