From 3c993143320cf5c826a650314a1da457f4d03d31 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 16 Mar 2023 14:55:46 +0100 Subject: [PATCH] [d3d11] Implement CreateWrappedResource for D3D12 buffers --- src/d3d11/d3d11_buffer.cpp | 60 +++++++++++++++++++++++++++++++++----- src/d3d11/d3d11_buffer.h | 27 ++++++++++++++++- src/d3d11/d3d11_device.cpp | 2 +- src/d3d11/d3d11_on_12.cpp | 39 +++++++++++++++++++++++-- src/d3d11/d3d11_on_12.h | 13 +++++++++ src/dxvk/dxvk_device.cpp | 8 +++++ src/dxvk/dxvk_device.h | 13 +++++++++ 7 files changed, 151 insertions(+), 11 deletions(-) diff --git a/src/d3d11/d3d11_buffer.cpp b/src/d3d11/d3d11_buffer.cpp index 6695fd05..c0ea5210 100644 --- a/src/d3d11/d3d11_buffer.cpp +++ b/src/d3d11/d3d11_buffer.cpp @@ -8,7 +8,8 @@ namespace dxvk { D3D11Buffer::D3D11Buffer( D3D11Device* pDevice, - const D3D11_BUFFER_DESC* pDesc) + const D3D11_BUFFER_DESC* pDesc, + const D3D11_ON_12_RESOURCE_INFO* p11on12Info) : D3D11DeviceChild(pDevice), m_desc (*pDesc), m_resource (this), @@ -83,17 +84,27 @@ namespace dxvk { info.access |= VK_ACCESS_HOST_WRITE_BIT; } - if (!(pDesc->MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL)) { + if (p11on12Info) { + m_11on12 = *p11on12Info; + + DxvkBufferImportInfo importInfo; + importInfo.buffer = VkBuffer(m_11on12.VulkanHandle); + importInfo.offset = m_11on12.VulkanOffset; + + if (m_desc.CPUAccessFlags) + m_11on12.Resource->Map(0, nullptr, &importInfo.mapPtr); + + m_buffer = m_parent->GetDXVKDevice()->importBuffer(info, importInfo, GetMemoryFlags()); + m_mapped = m_buffer->getSliceHandle(); + + m_mapMode = DetermineMapMode(); + } else if (!(pDesc->MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL)) { // Create the buffer and set the entire buffer slice as mapped, // so that we only have to update it when invalidating the buffer m_buffer = m_parent->GetDXVKDevice()->createBuffer(info, GetMemoryFlags()); m_mapped = m_buffer->getSliceHandle(); m_mapMode = DetermineMapMode(); - - // For Stream Output buffers we need a counter - if (pDesc->BindFlags & D3D11_BIND_STREAM_OUTPUT) - m_soCounter = CreateSoCounterBuffer(); } else { m_sparseAllocator = m_parent->GetDXVKDevice()->createSparsePageAllocator(); m_sparseAllocator->setCapacity(info.size / SparseMemoryPageSize); @@ -101,11 +112,16 @@ namespace dxvk { m_mapped = DxvkBufferSliceHandle(); m_mapMode = D3D11_COMMON_BUFFER_MAP_MODE_NONE; } + + // For Stream Output buffers we need a counter + if (pDesc->BindFlags & D3D11_BIND_STREAM_OUTPUT) + m_soCounter = CreateSoCounterBuffer(); } D3D11Buffer::~D3D11Buffer() { - + if (m_desc.CPUAccessFlags && m_11on12.Resource != nullptr) + m_11on12.Resource->Unmap(0, nullptr); } @@ -241,6 +257,36 @@ namespace dxvk { } + HRESULT D3D11Buffer::GetDescFromD3D12( + ID3D12Resource* pResource, + const D3D11_RESOURCE_FLAGS* pResourceFlags, + D3D11_BUFFER_DESC* pBufferDesc) { + D3D12_RESOURCE_DESC desc12 = pResource->GetDesc(); + + pBufferDesc->ByteWidth = desc12.Width; + pBufferDesc->Usage = D3D11_USAGE_DEFAULT; + pBufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE; + pBufferDesc->MiscFlags = 0; + pBufferDesc->CPUAccessFlags = 0; + pBufferDesc->StructureByteStride = 0; + + if (desc12.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) + pBufferDesc->BindFlags |= D3D11_BIND_RENDER_TARGET; + + if (desc12.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) + pBufferDesc->BindFlags |= D3D11_BIND_UNORDERED_ACCESS; + + if (pResourceFlags) { + pBufferDesc->BindFlags = pResourceFlags->BindFlags; + pBufferDesc->MiscFlags |= pResourceFlags->MiscFlags; + pBufferDesc->CPUAccessFlags = pResourceFlags->CPUAccessFlags; + pBufferDesc->StructureByteStride = pResourceFlags->StructureByteStride; + } + + return S_OK; + } + + BOOL D3D11Buffer::CheckFormatFeatureSupport( VkFormat Format, VkFormatFeatureFlags2 Features) const { diff --git a/src/d3d11/d3d11_buffer.h b/src/d3d11/d3d11_buffer.h index a169c440..097a8fcb 100644 --- a/src/d3d11/d3d11_buffer.h +++ b/src/d3d11/d3d11_buffer.h @@ -7,6 +7,7 @@ #include "d3d11_device_child.h" #include "d3d11_interfaces.h" +#include "d3d11_on_12.h" #include "d3d11_resource.h" namespace dxvk { @@ -41,7 +42,9 @@ namespace dxvk { D3D11Buffer( D3D11Device* pDevice, - const D3D11_BUFFER_DESC* pDesc); + const D3D11_BUFFER_DESC* pDesc, + const D3D11_ON_12_RESOURCE_INFO* p11on12Info); + ~D3D11Buffer(); HRESULT STDMETHODCALLTYPE QueryInterface( @@ -142,6 +145,14 @@ namespace dxvk { : DxvkCsThread::SynchronizeAll; } + /** + * \brief Retrieves D3D11on12 resource info + * \returns 11on12 resource info + */ + D3D11_ON_12_RESOURCE_INFO Get11on12Info() const { + return m_11on12; + } + /** * \brief Normalizes buffer description * @@ -151,9 +162,23 @@ namespace dxvk { static HRESULT NormalizeBufferProperties( D3D11_BUFFER_DESC* pDesc); + /** + * \brief Initializes D3D11 buffer description from D3D12 + * + * \param [in] pResource D3D12 resource + * \param [in] pResourceFlags D3D11 flag overrides + * \param [out] pBufferDesc D3D11 buffer description + * \returns \c S_OK if the parameters are valid + */ + static HRESULT GetDescFromD3D12( + ID3D12Resource* pResource, + const D3D11_RESOURCE_FLAGS* pResourceFlags, + D3D11_BUFFER_DESC* pBufferDesc); + private: D3D11_BUFFER_DESC m_desc; + D3D11_ON_12_RESOURCE_INFO m_11on12; D3D11_COMMON_BUFFER_MAP_MODE m_mapMode; Rc m_buffer; diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 866cb2ef..ffcb25d6 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -100,7 +100,7 @@ namespace dxvk { return S_FALSE; try { - const Com buffer = new D3D11Buffer(this, &desc); + const Com buffer = new D3D11Buffer(this, &desc, nullptr); if (!(desc.MiscFlags & D3D11_RESOURCE_MISC_TILE_POOL)) m_initializer->InitBuffer(buffer.ptr(), pInitialData); diff --git a/src/d3d11/d3d11_on_12.cpp b/src/d3d11/d3d11_on_12.cpp index 82e1b047..4f92b87c 100644 --- a/src/d3d11/d3d11_on_12.cpp +++ b/src/d3d11/d3d11_on_12.cpp @@ -45,8 +45,43 @@ namespace dxvk { D3D12_RESOURCE_STATES OutputState, REFIID riid, void** ppResource11) { - Logger::err("D3D11on12Device::CreateWrappedResource: Stub"); - return E_NOTIMPL; + Com interopDevice; + m_d3d12Device->QueryInterface(__uuidof(ID3D12DXVKInteropDevice), reinterpret_cast(&interopDevice)); + + D3D11_ON_12_RESOURCE_INFO info = { }; + info.InputState = InputState; + info.OutputState = OutputState; + info.IsWrappedResource = TRUE; + + // 11on12 technically allows importing D3D12 heaps as tile pools, + // but we don't support importing sparse resources at this time. + if (FAILED(pResource12->QueryInterface(__uuidof(ID3D12Resource), reinterpret_cast(&info.Resource)))) { + Logger::err("D3D11on12Device::CreateWrappedResource: Resource not a valid D3D12 resource"); + return E_INVALIDARG; + } + + // Query Vulkan resource handle and buffer offset + if (FAILED(interopDevice->GetVulkanResourceInfo(info.Resource.ptr(), &info.VulkanHandle, &info.VulkanOffset))) { + Logger::err("D3D11on12Device::CreateWrappedResource: Failed to retrieve Vulkan resource info"); + return E_INVALIDARG; + } + + Com resource; + D3D12_RESOURCE_DESC desc = info.Resource->GetDesc(); + + if (desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { + D3D11_BUFFER_DESC bufferDesc; + + if (FAILED(D3D11Buffer::GetDescFromD3D12(info.Resource.ptr(), pResourceFlags, &bufferDesc))) + return E_INVALIDARG; + + resource = new D3D11Buffer(m_device, &bufferDesc, &info); + } else { + Logger::err("D3D11on12Device::CreateWrappedResource: Resource type not supported"); + return E_NOTIMPL; + } + + return resource->QueryInterface(riid, ppResource11); } diff --git a/src/d3d11/d3d11_on_12.h b/src/d3d11/d3d11_on_12.h index 8865a607..9620662b 100644 --- a/src/d3d11/d3d11_on_12.h +++ b/src/d3d11/d3d11_on_12.h @@ -9,6 +9,19 @@ namespace dxvk { class D3D11Device; class D3D11DXGIDevice; + /** + * \brief Resource info for 11on12 resources + */ + struct D3D11_ON_12_RESOURCE_INFO { + Com Resource; + UINT64 VulkanHandle = 0; + UINT64 VulkanOffset = 0; + BOOL IsWrappedResource = FALSE; + D3D12_RESOURCE_STATES InputState = D3D12_RESOURCE_STATE_COMMON; + D3D12_RESOURCE_STATES OutputState = D3D12_RESOURCE_STATE_COMMON; + }; + + class D3D11on12Device : public ID3D11On12Device { public: diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index a14f428f..2591da5a 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -220,6 +220,14 @@ namespace dxvk { } + Rc DxvkDevice::importBuffer( + const DxvkBufferCreateInfo& createInfo, + const DxvkBufferImportInfo& importInfo, + VkMemoryPropertyFlags memoryType) { + return new DxvkBuffer(this, createInfo, importInfo, memoryType); + } + + DxvkMemoryStats DxvkDevice::getMemoryStats(uint32_t heap) { return m_objects.memoryManager().getMemoryStats(heap); } diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index f967a5bb..85d2e557 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -372,6 +372,19 @@ namespace dxvk { */ Rc createSparsePageAllocator(); + /** + * \brief Imports a buffer + * + * \param [in] createInfo Buffer create info + * \param [in] importInfo Buffer import info + * \param [in] memoryType Memory type flags + * \returns The buffer object + */ + Rc importBuffer( + const DxvkBufferCreateInfo& createInfo, + const DxvkBufferImportInfo& importInfo, + VkMemoryPropertyFlags memoryType); + /** * \brief Retrieves stat counters *