diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 608206f4..b7db2a39 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -102,18 +102,16 @@ namespace dxvk { reinterpret_cast(&m_dxgiAdapter)))) throw DxvkError("D3D11Device: Failed to query adapter"); + m_initializer = new D3D11Initializer(m_dxvkDevice); m_context = new D3D11ImmediateContext(this, m_dxvkDevice); - m_resourceInitContext = m_dxvkDevice->createContext(); - m_resourceInitContext->beginRecording( - m_dxvkDevice->createCommandList()); - CreateCounterBuffer(); } D3D11Device::~D3D11Device() { delete m_context; + delete m_initializer; } @@ -145,7 +143,7 @@ namespace dxvk { const Com buffer = new D3D11Buffer(this, pDesc); - this->InitBuffer(buffer.ptr(), pInitialData); + m_initializer->InitBuffer(buffer.ptr(), pInitialData); *ppBuffer = buffer.ref(); return S_OK; } catch (const DxvkError& e) { @@ -182,7 +180,7 @@ namespace dxvk { try { const Com texture = new D3D11Texture1D(this, &desc); - this->InitTexture(texture->GetCommonTexture(), pInitialData); + m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData); *ppTexture1D = texture.ref(); return S_OK; } catch (const DxvkError& e) { @@ -219,7 +217,7 @@ namespace dxvk { try { const Com texture = new D3D11Texture2D(this, &desc); - this->InitTexture(texture->GetCommonTexture(), pInitialData); + m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData); *ppTexture2D = texture.ref(); return S_OK; } catch (const DxvkError& e) { @@ -256,7 +254,7 @@ namespace dxvk { try { const Com texture = new D3D11Texture3D(this, &desc); - this->InitTexture(texture->GetCommonTexture(), pInitialData); + m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData); *ppTexture3D = texture.ref(); return S_OK; } catch (const DxvkError& e) { @@ -1752,10 +1750,7 @@ namespace dxvk { void D3D11Device::FlushInitContext() { - LockResourceInitContext(); - if (m_resourceInitCommands != 0) - SubmitResourceInitCommands(); - UnlockResourceInitContext(0); + m_initializer->Flush(); } @@ -1877,113 +1872,6 @@ namespace dxvk { } - void D3D11Device::InitBuffer( - D3D11Buffer* pBuffer, - const D3D11_SUBRESOURCE_DATA* pInitialData) { - const DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice(); - - D3D11_BUFFER_DESC desc; - pBuffer->GetDesc(&desc); - - if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) { - LockResourceInitContext(); - - m_resourceInitContext->updateBuffer( - bufferSlice.buffer(), - bufferSlice.offset(), - bufferSlice.length(), - pInitialData->pSysMem); - - UnlockResourceInitContext(1); - } else if (desc.Usage == D3D11_USAGE_DEFAULT) { - LockResourceInitContext(); - - m_resourceInitContext->clearBuffer( - bufferSlice.buffer(), - bufferSlice.offset(), - bufferSlice.length(), - 0u); - - UnlockResourceInitContext(1); - } - } - - - void D3D11Device::InitTexture( - D3D11CommonTexture* pTexture, - const D3D11_SUBRESOURCE_DATA* pInitialData) { - const Rc image = pTexture->GetImage(); - const DxvkFormatInfo* formatInfo = imageFormatInfo(image->info().format); - - if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) { - LockResourceInitContext(); - - // pInitialData is an array that stores an entry for - // every single subresource. Since we will define all - // subresources, this counts as initialization. - VkImageSubresourceLayers subresourceLayers; - subresourceLayers.aspectMask = formatInfo->aspectMask; - subresourceLayers.mipLevel = 0; - subresourceLayers.baseArrayLayer = 0; - subresourceLayers.layerCount = 1; - - for (uint32_t layer = 0; layer < image->info().numLayers; layer++) { - for (uint32_t level = 0; level < image->info().mipLevels; level++) { - subresourceLayers.baseArrayLayer = layer; - subresourceLayers.mipLevel = level; - - const uint32_t id = D3D11CalcSubresource( - level, layer, image->info().mipLevels); - - m_resourceInitContext->updateImage( - image, subresourceLayers, - VkOffset3D { 0, 0, 0 }, - image->mipLevelExtent(level), - pInitialData[id].pSysMem, - pInitialData[id].SysMemPitch, - pInitialData[id].SysMemSlicePitch); - } - } - - const uint32_t subresourceCount = - image->info().numLayers * image->info().mipLevels; - UnlockResourceInitContext(subresourceCount); - } else { - LockResourceInitContext(); - - // While the Microsoft docs state that resource contents are - // undefined if no initial data is provided, some applications - // expect a resource to be pre-cleared. We can only do that - // for non-compressed images, but that should be fine. - VkImageSubresourceRange subresources; - subresources.aspectMask = formatInfo->aspectMask; - subresources.baseMipLevel = 0; - subresources.levelCount = image->info().mipLevels; - subresources.baseArrayLayer = 0; - subresources.layerCount = image->info().numLayers; - - if (formatInfo->flags.test(DxvkFormatFlag::BlockCompressed)) { - m_resourceInitContext->initImage( - image, subresources); - } else { - if (subresources.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) { - m_resourceInitContext->clearColorImage( - image, VkClearColorValue(), subresources); - } else { - VkClearDepthStencilValue value; - value.depth = 1.0f; - value.stencil = 0; - - m_resourceInitContext->clearDepthStencilImage( - image, value, subresources); - } - } - - UnlockResourceInitContext(1); - } - } - - HRESULT D3D11Device::GetFormatSupportFlags(DXGI_FORMAT Format, UINT* pFlags1, UINT* pFlags2) const { // Query some general information from DXGI, DXVK and Vulkan about the format const DXGI_VK_FORMAT_INFO fmtMapping = m_dxgiAdapter->LookupFormat(Format, DXGI_VK_FORMAT_MODE_ANY); @@ -2158,33 +2046,6 @@ namespace dxvk { } - void D3D11Device::LockResourceInitContext() { - m_resourceInitMutex.lock(); - } - - - void D3D11Device::UnlockResourceInitContext(uint64_t CommandCount) { - m_resourceInitCommands += CommandCount; - - if (m_resourceInitCommands >= InitCommandThreshold) - SubmitResourceInitCommands(); - - m_resourceInitMutex.unlock(); - } - - - void D3D11Device::SubmitResourceInitCommands() { - m_dxvkDevice->submitCommandList( - m_resourceInitContext->endRecording(), - nullptr, nullptr); - - m_resourceInitContext->beginRecording( - m_dxvkDevice->createCommandList()); - - m_resourceInitCommands = 0; - } - - D3D_FEATURE_LEVEL D3D11Device::GetMaxFeatureLevel() { static const std::array, 7> s_featureLevels = {{ { "11_1", D3D_FEATURE_LEVEL_11_1 }, diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h index 12e302ce..82d43101 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -9,6 +9,7 @@ #include "../util/com/com_private_data.h" +#include "d3d11_initializer.h" #include "d3d11_interfaces.h" #include "d3d11_options.h" #include "d3d11_shader.h" @@ -357,16 +358,13 @@ namespace dxvk { const D3D11OptionSet m_d3d11Options; const DxbcOptions m_dxbcOptions; - D3D11ImmediateContext* m_context = nullptr; + D3D11Initializer* m_initializer = nullptr; + D3D11ImmediateContext* m_context = nullptr; std::mutex m_counterMutex; std::vector m_counterSlices; Rc m_counterBuffer; - std::mutex m_resourceInitMutex; - Rc m_resourceInitContext; - uint64_t m_resourceInitCommands = 0; - D3D11StateObjectSet m_bsStateObjects; D3D11StateObjectSet m_dsStateObjects; D3D11StateObjectSet m_rsStateObjects; @@ -381,14 +379,6 @@ namespace dxvk { const DxbcModuleInfo* pModuleInfo, DxbcProgramType ProgramType); - void InitBuffer( - D3D11Buffer* pBuffer, - const D3D11_SUBRESOURCE_DATA* pInitialData); - - void InitTexture( - D3D11CommonTexture* pTexture, - const D3D11_SUBRESOURCE_DATA* pInitialData); - HRESULT GetFormatSupportFlags( DXGI_FORMAT Format, UINT* pFlags1, @@ -400,10 +390,6 @@ namespace dxvk { void CreateCounterBuffer(); - void LockResourceInitContext(); - void UnlockResourceInitContext(uint64_t CommandCount); - void SubmitResourceInitCommands(); - static D3D_FEATURE_LEVEL GetMaxFeatureLevel(); }; diff --git a/src/d3d11/d3d11_initializer.cpp b/src/d3d11/d3d11_initializer.cpp new file mode 100644 index 00000000..a1a7ea04 --- /dev/null +++ b/src/d3d11/d3d11_initializer.cpp @@ -0,0 +1,207 @@ +#include + +#include "d3d11_initializer.h" + +namespace dxvk { + + D3D11Initializer::D3D11Initializer( + const Rc& Device) + : m_device(Device), m_context(m_device->createContext()) { + m_context->beginRecording( + m_device->createCommandList()); + } + + + D3D11Initializer::~D3D11Initializer() { + + } + + + void D3D11Initializer::Flush() { + std::lock_guard lock(m_mutex); + + if (m_transferCommands != 0) + FlushInternal(); + } + + void D3D11Initializer::InitBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + VkMemoryPropertyFlags memFlags = pBuffer->GetBuffer()->memFlags(); + + (memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + ? InitHostVisibleBuffer(pBuffer, pInitialData) + : InitDeviceLocalBuffer(pBuffer, pInitialData); + } + + + void D3D11Initializer::InitTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + VkMemoryPropertyFlags memFlags = pTexture->GetImage()->memFlags(); + + (memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + ? InitHostVisibleTexture(pTexture, pInitialData) + : InitDeviceLocalTexture(pTexture, pInitialData); + } + + + void D3D11Initializer::InitDeviceLocalBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + std::lock_guard lock(m_mutex); + + DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice(); + + if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) { + m_transferMemory += bufferSlice.length(); + m_transferCommands += 1; + + m_context->updateBuffer( + bufferSlice.buffer(), + bufferSlice.offset(), + bufferSlice.length(), + pInitialData->pSysMem); + } else { + m_transferCommands += 1; + + m_context->clearBuffer( + bufferSlice.buffer(), + bufferSlice.offset(), + bufferSlice.length(), + 0u); + } + + FlushImplicit(); + } + + + void D3D11Initializer::InitHostVisibleBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + // If the buffer is mapped, we can write data directly + // to the mapped memory region instead of doing it on + // the GPU. Same goes for zero-initialization. + DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice(); + + if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) { + std::memcpy( + bufferSlice.mapPtr(0), + pInitialData->pSysMem, + bufferSlice.length()); + } else { + std::memset( + bufferSlice.mapPtr(0), 0, + bufferSlice.length()); + } + } + + + void D3D11Initializer::InitDeviceLocalTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + std::lock_guard lock(m_mutex); + + Rc image = pTexture->GetImage(); + + auto formatInfo = imageFormatInfo(image->info().format); + + if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) { + // pInitialData is an array that stores an entry for + // every single subresource. Since we will define all + // subresources, this counts as initialization. + VkImageSubresourceLayers subresourceLayers; + subresourceLayers.aspectMask = formatInfo->aspectMask; + subresourceLayers.mipLevel = 0; + subresourceLayers.baseArrayLayer = 0; + subresourceLayers.layerCount = 1; + + for (uint32_t layer = 0; layer < image->info().numLayers; layer++) { + for (uint32_t level = 0; level < image->info().mipLevels; level++) { + subresourceLayers.baseArrayLayer = layer; + subresourceLayers.mipLevel = level; + + const uint32_t id = D3D11CalcSubresource( + level, layer, image->info().mipLevels); + + VkOffset3D mipLevelOffset = { 0, 0, 0 }; + VkExtent3D mipLevelExtent = image->mipLevelExtent(level); + + m_transferCommands += 1; + m_transferMemory += util::computeImageDataSize( + image->info().format, mipLevelExtent); + + m_context->updateImage( + image, subresourceLayers, + mipLevelOffset, + mipLevelExtent, + pInitialData[id].pSysMem, + pInitialData[id].SysMemPitch, + pInitialData[id].SysMemSlicePitch); + } + } + } else { + m_transferCommands += 1; + + // While the Microsoft docs state that resource contents are + // undefined if no initial data is provided, some applications + // expect a resource to be pre-cleared. We can only do that + // for non-compressed images, but that should be fine. + VkImageSubresourceRange subresources; + subresources.aspectMask = formatInfo->aspectMask; + subresources.baseMipLevel = 0; + subresources.levelCount = image->info().mipLevels; + subresources.baseArrayLayer = 0; + subresources.layerCount = image->info().numLayers; + + if (formatInfo->flags.test(DxvkFormatFlag::BlockCompressed)) { + m_context->initImage(image, subresources); + } else { + if (subresources.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) { + VkClearColorValue value = { }; + + m_context->clearColorImage( + image, value, subresources); + } else { + VkClearDepthStencilValue value; + value.depth = 1.0f; + value.stencil = 0; + + m_context->clearDepthStencilImage( + image, value, subresources); + } + } + } + + FlushImplicit(); + } + + + void D3D11Initializer::InitHostVisibleTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData) { + // TODO implement properly with memset/memcpy + InitDeviceLocalTexture(pTexture, pInitialData); + } + + + void D3D11Initializer::FlushImplicit() { + if (m_transferCommands > MaxTransferCommands + || m_transferMemory > MaxTransferMemory) + FlushInternal(); + } + + + void D3D11Initializer::FlushInternal() { + m_device->submitCommandList( + m_context->endRecording(), + nullptr, nullptr); + + m_context->beginRecording( + m_device->createCommandList()); + + m_transferCommands = 0; + m_transferMemory = 0; + } + +} \ No newline at end of file diff --git a/src/d3d11/d3d11_initializer.h b/src/d3d11/d3d11_initializer.h new file mode 100644 index 00000000..c4b82d35 --- /dev/null +++ b/src/d3d11/d3d11_initializer.h @@ -0,0 +1,67 @@ +#pragma once + +#include "d3d11_buffer.h" +#include "d3d11_texture.h" + +namespace dxvk { + + /** + * \brief Resource initialization context + * + * Manages a context which is used for resource + * initialization. This includes initialization + * with application-defined data, as well as + * zero-initialization for buffers and images. + */ + class D3D11Initializer { + constexpr static size_t MaxTransferMemory = 32 * 1024 * 1024; + constexpr static size_t MaxTransferCommands = 512; + public: + + D3D11Initializer( + const Rc& Device); + + ~D3D11Initializer(); + + void Flush(); + + void InitBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + void InitTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + private: + + std::mutex m_mutex; + + Rc m_device; + Rc m_context; + + size_t m_transferCommands = 0; + size_t m_transferMemory = 0; + + void InitDeviceLocalBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + void InitHostVisibleBuffer( + D3D11Buffer* pBuffer, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + void InitDeviceLocalTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + void InitHostVisibleTexture( + D3D11CommonTexture* pTexture, + const D3D11_SUBRESOURCE_DATA* pInitialData); + + void FlushImplicit(); + void FlushInternal(); + + }; + +} \ No newline at end of file diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index 28cc2eeb..88bbf824 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -10,6 +10,7 @@ d3d11_src = [ 'd3d11_depth_stencil.cpp', 'd3d11_device.cpp', 'd3d11_enums.cpp', + 'd3d11_initializer.cpp', 'd3d11_input_layout.cpp', 'd3d11_interop.cpp', 'd3d11_main.cpp',