diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index f49687bd..e5e8f895 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -3,8 +3,12 @@ namespace dxvk { - D3D11DeviceContext::D3D11DeviceContext() { - TRACE(this); + D3D11DeviceContext::D3D11DeviceContext( + ID3D11Device* parent, + Rc device) + : m_parent(parent), + m_device(device) { + TRACE(this, parent, device); } @@ -24,7 +28,7 @@ namespace dxvk { void D3D11DeviceContext::GetDevice(ID3D11Device **ppDevice) { - Logger::warn("D3D11DeviceContext::GetDevice: Not implemented"); + *ppDevice = ref(m_parent); } diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index 4581dee7..7d8f7b14 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -13,9 +13,10 @@ namespace dxvk { public: - D3D11DeviceContext(); + D3D11DeviceContext( + ID3D11Device* parent, + Rc device); ~D3D11DeviceContext(); - HRESULT QueryInterface( REFIID riid, @@ -536,6 +537,11 @@ namespace dxvk { private: + ID3D11Device* const m_parent; + + Rc m_device; + Rc m_context; + }; } diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 8b641d75..39804c1e 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -6,28 +6,37 @@ namespace dxvk { D3D11Device::D3D11Device( + IDXVKDevice* dxgiDevice, D3D_FEATURE_LEVEL featureLevel, UINT featureFlags) - : m_featureLevel(featureLevel), - m_featureFlags(featureFlags) { - TRACE(this, featureLevel, featureFlags); + : m_dxgiDevice (dxgiDevice), + m_featureLevel(featureLevel), + m_featureFlags(featureFlags), + m_dxvkDevice (m_dxgiDevice->GetDXVKDevice()), + m_dxvkAdapter (m_dxvkDevice->adapter()) { + TRACE(this, dxgiDevice, featureLevel, featureFlags); + m_dxgiDevice->SetDeviceLayer(this); + m_context = new D3D11DeviceContext(this, m_dxvkDevice); } D3D11Device::~D3D11Device() { TRACE(this); + m_dxgiDevice->SetDeviceLayer(nullptr); } - HRESULT D3D11Device::QueryInterface( - REFIID riid, - void **ppvObject) { + HRESULT D3D11Device::QueryInterface(REFIID riid, void** ppvObject) { COM_QUERY_IFACE(riid, ppvObject, ID3D11Device); + if (riid == __uuidof(IDXVKDevice) + || riid == __uuidof(IDXGIDevice)) + return m_dxgiDevice->QueryInterface(riid, ppvObject); + Logger::warn("D3D11Device::QueryInterface: Unknown interface query"); return E_NOINTERFACE; } - + HRESULT D3D11Device::CreateBuffer( const D3D11_BUFFER_DESC* pDesc, @@ -314,19 +323,19 @@ namespace dxvk { HRESULT D3D11Device::GetPrivateData( REFGUID guid, UINT* pDataSize, void* pData) { - return m_privateData.getData(guid, pDataSize, pData); + return m_dxgiDevice->GetPrivateData(guid, pDataSize, pData); } HRESULT D3D11Device::SetPrivateData( REFGUID guid, UINT DataSize, const void* pData) { - return m_privateData.setData(guid, DataSize, pData); + return m_dxgiDevice->SetPrivateData(guid, DataSize, pData); } HRESULT D3D11Device::SetPrivateDataInterface( REFGUID guid, const IUnknown* pData) { - return m_privateData.setInterface(guid, pData); + return m_dxgiDevice->SetPrivateDataInterface(guid, pData); } @@ -347,7 +356,7 @@ namespace dxvk { void D3D11Device::GetImmediateContext(ID3D11DeviceContext** ppImmediateContext) { - Logger::err("D3D11Device::GetImmediateContext: Not implemented"); + *ppImmediateContext = m_context.ref(); } @@ -362,4 +371,10 @@ namespace dxvk { return 0; } + + bool D3D11Device::CheckFeatureLevelSupport( + D3D_FEATURE_LEVEL featureLevel) { + return featureLevel <= D3D_FEATURE_LEVEL_11_0; + } + } diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h index 241f912c..bb9cfa11 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + #include "d3d11_include.h" #include "../util/com/com_private_data.h" @@ -14,13 +17,14 @@ namespace dxvk { public: D3D11Device( - D3D_FEATURE_LEVEL featureLevel, - UINT featureFlags); + IDXVKDevice* dxgiDevice, + D3D_FEATURE_LEVEL featureLevel, + UINT featureFlags); ~D3D11Device(); HRESULT QueryInterface( - REFIID riid, - void **ppvObject) final; + REFIID riid, + void** ppvObject) final; HRESULT CreateBuffer( const D3D11_BUFFER_DESC* pDesc, @@ -185,18 +189,18 @@ namespace dxvk { UINT FeatureSupportDataSize) final; HRESULT GetPrivateData( - REFGUID guid, - UINT* pDataSize, - void* pData) final; + REFGUID Name, + UINT *pDataSize, + void *pData) final; HRESULT SetPrivateData( - REFGUID guid, - UINT DataSize, - const void* pData) final; + REFGUID Name, + UINT DataSize, + const void *pData) final; HRESULT SetPrivateDataInterface( - REFGUID guid, - const IUnknown* pData) final; + REFGUID Name, + const IUnknown *pUnknown) final; D3D_FEATURE_LEVEL GetFeatureLevel() final; @@ -211,12 +215,19 @@ namespace dxvk { UINT GetExceptionMode() final; + static bool CheckFeatureLevelSupport( + D3D_FEATURE_LEVEL featureLevel); + private: - const D3D_FEATURE_LEVEL m_featureLevel; - const UINT m_featureFlags; + const Com m_dxgiDevice; + const D3D_FEATURE_LEVEL m_featureLevel; + const UINT m_featureFlags; - ComPrivateData m_privateData; + const Rc m_dxvkDevice; + const Rc m_dxvkAdapter; + + Com m_context; }; diff --git a/src/d3d11/d3d11_main.cpp b/src/d3d11/d3d11_main.cpp index 26ab036d..9e942917 100644 --- a/src/d3d11/d3d11_main.cpp +++ b/src/d3d11/d3d11_main.cpp @@ -1,10 +1,12 @@ +#include + #include +#include #include "d3d11_device.h" -using namespace dxvk; - extern "C" { + using namespace dxvk; DLLEXPORT HRESULT __stdcall D3D11CreateDevice( IDXGIAdapter *pAdapter, @@ -21,8 +23,114 @@ extern "C" { Flags, pFeatureLevels, FeatureLevels, SDKVersion, ppDevice, pFeatureLevel, ppImmediateContext); - Logger::err("D3D11CreateDevice: Not implemented"); - return E_NOTIMPL; + + Com dxgiAdapter = pAdapter; + Com dxvkAdapter = nullptr; + + if (dxgiAdapter == nullptr) { + // We'll treat everything as hardware, even if the + // Vulkan device is actually a software device. + if (DriverType != D3D_DRIVER_TYPE_HARDWARE) { + Logger::err("D3D11CreateDevice: Unsupported driver type"); + return DXGI_ERROR_UNSUPPORTED; + } + + // We'll use the first adapter returned by a DXGI factory + Com factory = nullptr; + + if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast(&factory)))) { + Logger::err("D3D11CreateDevice: Failed to create a DXGI factory"); + return E_FAIL; + } + + if (FAILED(factory->EnumAdapters(0, &dxgiAdapter))) { + Logger::err("D3D11CreateDevice: No default adapter available"); + return E_FAIL; + } + + } else { + // In theory we could ignore these, but the Microsoft docs explicitly + // state that we need to return E_INVALIDARG in case the arguments are + // invalid. Both the driver type and software parameter can only be + // set if the adapter itself is unspecified. + // See: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476082(v=vs.85).aspx + if (DriverType != D3D_DRIVER_TYPE_UNKNOWN || Software != nullptr) + return E_INVALIDARG; + } + + // The adapter must obviously be a DXVK-compatible adapter so + // that we can create a DXVK-compatible DXGI device from it. + if (FAILED(dxgiAdapter->QueryInterface(__uuidof(IDXVKAdapter), + reinterpret_cast(&dxvkAdapter)))) { + Logger::err("D3D11CreateDevice: Adapter is not a DXVK adapter"); + return E_FAIL; + } + + // Feature levels to probe if the + // application does not specify any. + std::array defaultFeatureLevels = { + D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1, + }; + + if (pFeatureLevels == nullptr || FeatureLevels == 0) { + pFeatureLevels = defaultFeatureLevels.data(); + FeatureLevels = defaultFeatureLevels.size(); + } + + // Find the highest feature level supported by the device. + // This works because the feature level array is ordered. + UINT flId; + for (flId = 0 ; flId < FeatureLevels; flId++) { + if (D3D11Device::CheckFeatureLevelSupport(pFeatureLevels[flId])) + break; + } + + if (flId == FeatureLevels) { + Logger::err("D3D11CreateDevice: Requested feature level not supported"); + return DXGI_ERROR_UNSUPPORTED; + } + + // Try to create the device with the given parameters. + const D3D_FEATURE_LEVEL fl = pFeatureLevels[flId]; + + try { + + // Write back the actual feature level + // if the application requested it. + if (pFeatureLevel != nullptr) + *pFeatureLevel = fl; + + // The documentation is unclear about what exactly should be done if + // the application passes NULL to ppDevice, but a non-NULL pointer to + // ppImmediateContext. In our implementation, the immediate context + // does not hold a strong reference to the device that owns it, so + // if we cannot write back the device, it would be destroyed. + if (ppDevice != nullptr) { + Com dxvkDevice = nullptr; + + if (FAILED(DXGICreateDXVKDevice(dxvkAdapter.ptr(), &dxvkDevice))) { + Logger::err("D3D11CreateDevice: Failed to create DXGI device"); + return E_FAIL; + } + + Com d3d11Device = new D3D11Device( + dxvkDevice.ptr(), fl, Flags); + + *ppDevice = d3d11Device.ref(); + if (ppImmediateContext != nullptr) + d3d11Device->GetImmediateContext(ppImmediateContext); + return S_OK; + } else { + Logger::warn("D3D11CreateDevice: ppDevice is null"); + return S_OK; + } + + } catch (const DxvkError& e) { + Logger::err("D3D11CreateDevice: Failed to create D3D11 device"); + return E_FAIL; + } } @@ -39,8 +147,56 @@ extern "C" { ID3D11Device **ppDevice, D3D_FEATURE_LEVEL *pFeatureLevel, ID3D11DeviceContext **ppImmediateContext) { - Logger::err("D3D11CreateDeviceAndSwapChain: Not implemented"); - return E_NOTIMPL; + TRACE(pAdapter, DriverType, Software, + Flags, pFeatureLevels, FeatureLevels, + SDKVersion, pSwapChainDesc, ppSwapChain, + ppDevice, pFeatureLevel, ppImmediateContext); + + // Try to create a device first. + HRESULT status = D3D11CreateDevice(pAdapter, DriverType, + Software, Flags, pFeatureLevels, FeatureLevels, + SDKVersion, ppDevice, pFeatureLevel, ppImmediateContext); + + if (FAILED(status)) + return status; + + // Again, the documentation does not exactly tell us what we + // need to do in case one of the arguments is a null pointer. + if (ppDevice != nullptr && ppSwapChain != nullptr) { + if (pSwapChainDesc == nullptr) + return E_INVALIDARG; + + Com d3d11Device = *ppDevice; + Com dxgiDevice = nullptr; + Com dxgiAdapter = nullptr; + Com dxgiFactory = nullptr; + + if (FAILED(d3d11Device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&dxgiDevice)))) { + Logger::err("D3D11CreateDeviceAndSwapChain: Failed to query DXGI device"); + return E_FAIL; + } + + if (FAILED(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast(&dxgiAdapter)))) { + Logger::err("D3D11CreateDeviceAndSwapChain: Failed to query DXGI adapter"); + return E_FAIL; + } + + if (FAILED(dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast(&dxgiFactory)))) { + Logger::err("D3D11CreateDeviceAndSwapChain: Failed to query DXGI factory"); + return E_FAIL; + } + + DXGI_SWAP_CHAIN_DESC desc = *pSwapChainDesc; + if (FAILED(dxgiFactory->CreateSwapChain(d3d11Device.ptr(), &desc, ppSwapChain))) { + Logger::err("D3D11CreateDeviceAndSwapChain: Failed to create swap chain"); + return E_FAIL; + } + + return S_OK; + } else { + Logger::warn("D3D11CreateDeviceAndSwapChain: Not creating a swap chain"); + return S_OK; + } } - + } \ No newline at end of file diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index 7914c5a6..b9955139 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -5,9 +5,11 @@ d3d11_src = [ ] d3d11_dll = shared_library('d3d11', d3d11_src, + name_prefix : '', link_with : [ util_lib ], dependencies : [ dxvk_dep, dxgi_dep ], - include_directories : dxvk_include_path) + include_directories : dxvk_include_path, + install : true) d3d11_dep = declare_dependency( link_with : [ d3d11_dll ],