From 6432787ac31f998bc85a9519923cc0aecbc38499 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 16 Mar 2023 01:34:49 +0100 Subject: [PATCH] [d3d11] Implement D3D11on12 device creation --- src/d3d11/d3d11_device.cpp | 30 +++-- src/d3d11/d3d11_device.h | 19 +++- src/d3d11/d3d11_main.cpp | 172 ++++++++++++++++++++++++++++- src/d3d11/d3d11_on_12.cpp | 66 +++++++++++ src/d3d11/d3d11_on_12.h | 62 +++++++++++ src/d3d11/d3d11_on_12_interfaces.h | 56 ++++++++++ src/d3d11/meson.build | 1 + 7 files changed, 386 insertions(+), 20 deletions(-) create mode 100644 src/d3d11/d3d11_on_12.cpp create mode 100644 src/d3d11/d3d11_on_12.h create mode 100644 src/d3d11/d3d11_on_12_interfaces.h diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 1398fa70..866cb2ef 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -1832,6 +1832,11 @@ namespace dxvk { DXGI_VK_FORMAT_MODE Mode) const { return m_d3d11Formats.GetFormatFamily(Format, Mode); } + + + bool D3D11Device::Is11on12Device() const { + return m_container->Is11on12Device(); + } void D3D11Device::FlushInitContext() { @@ -3057,18 +3062,22 @@ namespace dxvk { D3D11DXGIDevice::D3D11DXGIDevice( IDXGIAdapter* pAdapter, - const Rc& pDxvkInstance, - const Rc& pDxvkAdapter, + ID3D12Device* pD3D12Device, + ID3D12CommandQueue* pD3D12Queue, + Rc pDxvkInstance, + Rc pDxvkAdapter, + Rc pDxvkDevice, D3D_FEATURE_LEVEL FeatureLevel, UINT FeatureFlags) : m_dxgiAdapter (pAdapter), m_dxvkInstance (pDxvkInstance), m_dxvkAdapter (pDxvkAdapter), - m_dxvkDevice (CreateDevice(FeatureLevel)), + m_dxvkDevice (pDxvkDevice), m_d3d11Device (this, FeatureLevel, FeatureFlags), m_d3d11DeviceExt(this, &m_d3d11Device), m_d3d11Interop (this, &m_d3d11Device), m_d3d11Video (this, &m_d3d11Device), + m_d3d11on12 (this, &m_d3d11Device, pD3D12Device, pD3D12Queue), m_metaDevice (this), m_dxvkFactory (this, &m_d3d11Device) { @@ -3076,7 +3085,7 @@ namespace dxvk { D3D11DXGIDevice::~D3D11DXGIDevice() { - + } @@ -3140,6 +3149,13 @@ namespace dxvk { return S_OK; } + if (m_d3d11on12.Is11on12Device()) { + if (riid == __uuidof(ID3D11On12Device)) { + *ppvObject = ref(&m_d3d11on12); + return S_OK; + } + } + if (riid == __uuidof(ID3D10Multithread)) { Com context; m_d3d11Device.GetImmediateContext(&context); @@ -3403,10 +3419,4 @@ namespace dxvk { return m_dxvkDevice; } - - Rc D3D11DXGIDevice::CreateDevice(D3D_FEATURE_LEVEL FeatureLevel) { - DxvkDeviceFeatures deviceFeatures = D3D11Device::GetDeviceFeatures(m_dxvkAdapter); - return m_dxvkAdapter->createDevice(m_dxvkInstance, deviceFeatures); - } - } diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h index 58700cc3..f8ad108e 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -20,6 +20,7 @@ #include "d3d11_initializer.h" #include "d3d11_interfaces.h" #include "d3d11_interop.h" +#include "d3d11_on_12.h" #include "d3d11_options.h" #include "d3d11_shader.h" #include "d3d11_state.h" @@ -421,6 +422,8 @@ namespace dxvk { return m_d3d10Device; } + bool Is11on12Device() const; + static D3D_FEATURE_LEVEL GetMaxFeatureLevel( const Rc& Instance, const Rc& Adapter); @@ -430,7 +433,7 @@ namespace dxvk { private: - IDXGIObject* m_container; + D3D11DXGIDevice* m_container; D3D_FEATURE_LEVEL m_featureLevel; UINT m_featureFlags; @@ -764,8 +767,11 @@ namespace dxvk { D3D11DXGIDevice( IDXGIAdapter* pAdapter, - const Rc& pDxvkInstance, - const Rc& pDxvkAdapter, + ID3D12Device* pD3D12Device, + ID3D12CommandQueue* pD3D12Queue, + Rc pDxvkInstance, + Rc pDxvkAdapter, + Rc pDxvkDevice, D3D_FEATURE_LEVEL FeatureLevel, UINT FeatureFlags); @@ -834,6 +840,10 @@ namespace dxvk { Rc STDMETHODCALLTYPE GetDXVKDevice(); + BOOL Is11on12Device() const { + return m_d3d11on12.Is11on12Device(); + } + private: Com m_dxgiAdapter; @@ -846,14 +856,13 @@ namespace dxvk { D3D11DeviceExt m_d3d11DeviceExt; D3D11VkInterop m_d3d11Interop; D3D11VideoDevice m_d3d11Video; + D3D11on12Device m_d3d11on12; DXGIDXVKDevice m_metaDevice; DXGIVkSwapChainFactory m_dxvkFactory; uint32_t m_frameLatency = DefaultFrameLatency; - Rc CreateDevice(D3D_FEATURE_LEVEL FeatureLevel); - }; } diff --git a/src/d3d11/d3d11_main.cpp b/src/d3d11/d3d11_main.cpp index 36537539..0c0aad66 100644 --- a/src/d3d11/d3d11_main.cpp +++ b/src/d3d11/d3d11_main.cpp @@ -89,8 +89,13 @@ extern "C" { try { Logger::info(str::format("D3D11CoreCreateDevice: Using feature level ", devFeatureLevel)); + DxvkDeviceFeatures deviceFeatures = D3D11Device::GetDeviceFeatures(dxvkAdapter); + Rc dxvkDevice = dxvkAdapter->createDevice(dxvkInstance, deviceFeatures); + Com device = new D3D11DXGIDevice( - pAdapter, dxvkInstance, dxvkAdapter, devFeatureLevel, Flags); + pAdapter, nullptr, nullptr, + dxvkInstance, dxvkAdapter, dxvkDevice, + devFeatureLevel, Flags); return device->QueryInterface( __uuidof(ID3D11Device), @@ -258,12 +263,169 @@ extern "C" { ID3D11Device** ppDevice, ID3D11DeviceContext** ppImmediateContext, D3D_FEATURE_LEVEL* pChosenFeatureLevel) { - static bool s_errorShown = false; + InitReturnPtr(ppDevice); + InitReturnPtr(ppImmediateContext); - if (!std::exchange(s_errorShown, true)) - Logger::err("D3D11On12CreateDevice: Not implemented"); + if (pChosenFeatureLevel) + *pChosenFeatureLevel = D3D_FEATURE_LEVEL(0); - return E_NOTIMPL; + if (!pDevice) + return E_INVALIDARG; + + // Figure out D3D12 objects + Com d3d12Device; + Com d3d12Queue; + + if (FAILED(pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&d3d12Device)))) { + Logger::err("D3D11On12CreateDevice: Device is not a valid D3D12 device"); + return E_INVALIDARG; + } + + if (NodeMask & (NodeMask - 1)) { + Logger::err("D3D11On12CreateDevice: Invalid node mask"); + return E_INVALIDARG; + } + + if (!NumQueues || !ppCommandQueues || !ppCommandQueues[0]) { + Logger::err("D3D11On12CreateDevice: No command queue specified"); + return E_INVALIDARG; + } + + if (NumQueues > 1) { + // Not sure what to do with more than one graphics queue + Logger::warn("D3D11On12CreateDevice: Only one queue supported"); + } + + if (FAILED(ppCommandQueues[0]->QueryInterface(__uuidof(ID3D12CommandQueue), reinterpret_cast(&d3d12Queue)))) { + Logger::err("D3D11On12CreateDevice: Queue is not a valid D3D12 command queue"); + return E_INVALIDARG; + } + + // Determine feature level for the D3D11 device + std::array defaultFeatureLevels = {{ + D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_12_1, + }}; + + D3D12_FEATURE_DATA_FEATURE_LEVELS featureLevel = { }; + + if (!FeatureLevels || !pFeatureLevels) { + featureLevel.NumFeatureLevels = defaultFeatureLevels.size(); + featureLevel.pFeatureLevelsRequested = defaultFeatureLevels.data(); + } else { + featureLevel.NumFeatureLevels = FeatureLevels; + featureLevel.pFeatureLevelsRequested = pFeatureLevels; + } + + HRESULT hr = d3d12Device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &featureLevel, sizeof(featureLevel)); + + if (FAILED(hr) || !featureLevel.MaxSupportedFeatureLevel) { + Logger::err(str::format("D3D11On12CreateDevice: Minimum required feature level not supported")); + return hr; + } + + Logger::info(str::format("D3D11On12CreateDevice: Chosen feature level: ", featureLevel.MaxSupportedFeatureLevel)); + + Com interopDevice; + + if (FAILED(d3d12Device->QueryInterface(__uuidof(ID3D12DXVKInteropDevice), reinterpret_cast(&interopDevice)))) { + Logger::err("D3D11On12CreateDevice: Device not a vkd3d-proton device."); + return E_INVALIDARG; + } + + Com dxgiAdapter; + + if (FAILED(interopDevice->GetDXGIAdapter(IID_PPV_ARGS(&dxgiAdapter)))) { + Logger::err("D3D11On12CreateDevice: Failed to query DXGI adapter."); + return E_INVALIDARG; + } + + try { + // Initialize DXVK instance + DxvkInstanceImportInfo instanceInfo = { }; + DxvkDeviceImportInfo deviceInfo = { }; + VkPhysicalDevice vulkanAdapter = VK_NULL_HANDLE; + + interopDevice->GetVulkanHandles(&instanceInfo.instance, &vulkanAdapter, &deviceInfo.device); + + uint32_t instanceExtensionCount = 0; + interopDevice->GetInstanceExtensions(&instanceExtensionCount, nullptr); + + std::vector instanceExtensions(instanceExtensionCount); + interopDevice->GetInstanceExtensions(&instanceExtensionCount, instanceExtensions.data()); + + instanceInfo.extensionCount = instanceExtensions.size(); + instanceInfo.extensionNames = instanceExtensions.data(); + + Rc dxvkInstance = new DxvkInstance(instanceInfo); + + // Find adapter by physical device handle + Rc dxvkAdapter; + + for (uint32_t i = 0; i < dxvkInstance->adapterCount(); i++) { + Rc curr = dxvkInstance->enumAdapters(i); + + if (curr->handle() == vulkanAdapter) + dxvkAdapter = std::move(curr); + } + + if (dxvkAdapter == nullptr) { + Logger::err("D3D11On12CreateDevice: No matching adapter found"); + return E_INVALIDARG; + } + + interopDevice->GetVulkanQueueInfo(d3d12Queue.ptr(), &deviceInfo.queue, &deviceInfo.queueFamily); + interopDevice->GetDeviceFeatures(&deviceInfo.features); + + uint32_t deviceExtensionCount = 0; + interopDevice->GetDeviceExtensions(&deviceExtensionCount, nullptr); + + std::vector deviceExtensions(deviceExtensionCount); + interopDevice->GetDeviceExtensions(&deviceExtensionCount, deviceExtensions.data()); + + deviceInfo.extensionCount = deviceExtensions.size(); + deviceInfo.extensionNames = deviceExtensions.data(); + + deviceInfo.queueCallback = [ + cDevice = interopDevice, + cQueue = d3d12Queue + ] (bool doLock) { + HRESULT hr = doLock + ? cDevice->LockCommandQueue(cQueue.ptr()) + : cDevice->UnlockCommandQueue(cQueue.ptr()); + + if (FAILED(hr)) + Logger::err(str::format("Failed to lock vkd3d-proton device queue: ", hr)); + }; + + Rc dxvkDevice = dxvkAdapter->importDevice(dxvkInstance, deviceInfo); + + // Create and return the actual D3D11 device + Com device = new D3D11DXGIDevice( + dxgiAdapter.ptr(), d3d12Device.ptr(), d3d12Queue.ptr(), + dxvkInstance, dxvkAdapter, dxvkDevice, + featureLevel.MaxSupportedFeatureLevel, Flags); + + Com d3d11Device; + device->QueryInterface(__uuidof(ID3D11Device), reinterpret_cast(&d3d11Device)); + + if (ppDevice) + *ppDevice = d3d11Device.ref(); + + if (ppImmediateContext) + d3d11Device->GetImmediateContext(ppImmediateContext); + + if (pChosenFeatureLevel) + *pChosenFeatureLevel = d3d11Device->GetFeatureLevel(); + + if (!ppDevice && !ppImmediateContext) + return S_FALSE; + + return S_OK; + } catch (const DxvkError& e) { + Logger::err("D3D11On12CreateDevice: Failed to create D3D11 device"); + return E_FAIL; + } } } \ No newline at end of file diff --git a/src/d3d11/d3d11_on_12.cpp b/src/d3d11/d3d11_on_12.cpp new file mode 100644 index 00000000..82e1b047 --- /dev/null +++ b/src/d3d11/d3d11_on_12.cpp @@ -0,0 +1,66 @@ +#include "d3d11_device.h" +#include "d3d11_on_12.h" + +namespace dxvk { + + D3D11on12Device::D3D11on12Device( + D3D11DXGIDevice* pContainer, + D3D11Device* pDevice, + ID3D12Device* pD3D12Device, + ID3D12CommandQueue* pD3D12Queue) + : m_container (pContainer), + m_device (pDevice), + m_d3d12Device (pD3D12Device), + m_d3d12Queue (pD3D12Queue) { + + } + + + D3D11on12Device::~D3D11on12Device() { + + } + + + ULONG STDMETHODCALLTYPE D3D11on12Device::AddRef() { + return m_container->AddRef(); + } + + + ULONG STDMETHODCALLTYPE D3D11on12Device::Release() { + return m_container->Release(); + } + + + HRESULT STDMETHODCALLTYPE D3D11on12Device::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_container->QueryInterface(riid, ppvObject); + } + + + HRESULT STDMETHODCALLTYPE D3D11on12Device::CreateWrappedResource( + IUnknown* pResource12, + const D3D11_RESOURCE_FLAGS* pResourceFlags, + D3D12_RESOURCE_STATES InputState, + D3D12_RESOURCE_STATES OutputState, + REFIID riid, + void** ppResource11) { + Logger::err("D3D11on12Device::CreateWrappedResource: Stub"); + return E_NOTIMPL; + } + + + void STDMETHODCALLTYPE D3D11on12Device::ReleaseWrappedResources( + ID3D11Resource* const* ppResources, + UINT ResourceCount) { + Logger::err("D3D11on12Device::ReleaseWrappedResources: Stub"); + } + + + void STDMETHODCALLTYPE D3D11on12Device::AcquireWrappedResources( + ID3D11Resource* const* ppResources, + UINT ResourceCount) { + Logger::err("D3D11on12Device::AcquireWrappedResources: Stub"); + } + +} diff --git a/src/d3d11/d3d11_on_12.h b/src/d3d11/d3d11_on_12.h new file mode 100644 index 00000000..8865a607 --- /dev/null +++ b/src/d3d11/d3d11_on_12.h @@ -0,0 +1,62 @@ +#pragma once + +#include "d3d11_on_12_interfaces.h" + +#include "../util/log/log.h" + +namespace dxvk { + + class D3D11Device; + class D3D11DXGIDevice; + + class D3D11on12Device : public ID3D11On12Device { + + public: + + D3D11on12Device( + D3D11DXGIDevice* pContainer, + D3D11Device* pDevice, + ID3D12Device* pD3D12Device, + ID3D12CommandQueue* pD3D12Queue); + + ~D3D11on12Device(); + + ULONG STDMETHODCALLTYPE AddRef(); + + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void** ppvObject); + + HRESULT STDMETHODCALLTYPE CreateWrappedResource( + IUnknown* pResource12, + const D3D11_RESOURCE_FLAGS* pResourceFlags, + D3D12_RESOURCE_STATES InputState, + D3D12_RESOURCE_STATES OutputState, + REFIID riid, + void** ppResource11); + + void STDMETHODCALLTYPE ReleaseWrappedResources( + ID3D11Resource* const* ppResources, + UINT ResourceCount); + + void STDMETHODCALLTYPE AcquireWrappedResources( + ID3D11Resource* const* ppResources, + UINT ResourceCount); + + bool Is11on12Device() const { + return m_d3d12Device != nullptr; + } + + private: + + D3D11DXGIDevice* m_container; + D3D11Device* m_device; + + Com m_d3d12Device; + Com m_d3d12Queue; + + }; + +} diff --git a/src/d3d11/d3d11_on_12_interfaces.h b/src/d3d11/d3d11_on_12_interfaces.h new file mode 100644 index 00000000..2ec22e0a --- /dev/null +++ b/src/d3d11/d3d11_on_12_interfaces.h @@ -0,0 +1,56 @@ +#pragma once + +#include "../vulkan/vulkan_loader.h" + +#include + +MIDL_INTERFACE("39da4e09-bd1c-4198-9fae-86bbe3be41fd") +ID3D12DXVKInteropDevice : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE GetDXGIAdapter( + REFIID iid, + void** ppvObject) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetInstanceExtensions( + UINT* pExtensionCount, + const char** ppExtensions) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeviceExtensions( + UINT* pExtensionCount, + const char** ppExtensions) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDeviceFeatures( + const VkPhysicalDeviceFeatures2** ppFeatures) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVulkanHandles( + VkInstance* pVkInstance, + VkPhysicalDevice* pVkPhysicalDevice, + VkDevice* pVkDevice) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVulkanQueueInfo( + ID3D12CommandQueue* pCommandQueue, + VkQueue* pVkQueue, + UINT32* pVkQueueFamily) = 0; + + virtual void STDMETHODCALLTYPE GetVulkanImageLayout( + ID3D12Resource* pResource, + D3D12_RESOURCE_STATES State, + VkImageLayout* pVkLayout) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVulkanResourceInfo( + ID3D12Resource* pResource, + UINT64* pVkHandle, + UINT64* pBufferOffset) = 0; + + virtual HRESULT STDMETHODCALLTYPE LockCommandQueue( + ID3D12CommandQueue* pCommandQueue) = 0; + + virtual HRESULT STDMETHODCALLTYPE UnlockCommandQueue( + ID3D12CommandQueue* pCommandQueue) = 0; + +}; + +#ifdef _MSC_VER +struct __declspec(uuid("39da4e09-bd1c-4198-9fae-86bbe3be41fd")) ID3D12DXVKInteropDevice; +#else +__CRT_UUID_DECL(ID3D12DXVKInteropDevice, 0x39da4e09, 0xbd1c, 0x4198, 0x9f,0xae, 0x86,0xbb,0xe3,0xbe,0x41,0xfd) +#endif diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index ea51a9d5..4b71df30 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -42,6 +42,7 @@ d3d11_src = [ 'd3d11_input_layout.cpp', 'd3d11_interop.cpp', 'd3d11_main.cpp', + 'd3d11_on_12.cpp', 'd3d11_options.cpp', 'd3d11_query.cpp', 'd3d11_rasterizer.cpp',