From 8044ce6c7ecbbbd6f95ccdbad9bbf1d9b32f0c3d Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 3 Aug 2018 10:17:02 +0200 Subject: [PATCH] [d3d11] Refactor UAV counter buffer allocator - Fixes violation of the minStorageBufferOffsetAlignment limit - Allows allocation of multiple counter buffers if necessary --- src/d3d11/d3d11_context.h | 1 + src/d3d11/d3d11_device.cpp | 53 ++----------------------- src/d3d11/d3d11_device.h | 20 +++++----- src/d3d11/d3d11_uav_counter.cpp | 67 ++++++++++++++++++++++++++++++++ src/d3d11/d3d11_uav_counter.h | 69 +++++++++++++++++++++++++++++++++ src/d3d11/d3d11_view_uav.h | 5 --- src/d3d11/meson.build | 1 + 7 files changed, 151 insertions(+), 65 deletions(-) create mode 100644 src/d3d11/d3d11_uav_counter.cpp create mode 100644 src/d3d11/d3d11_uav_counter.h diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index d3ad9e35..2a920a84 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -7,6 +7,7 @@ #include "d3d11_annotation.h" #include "d3d11_context_state.h" #include "d3d11_device_child.h" +#include "d3d11_uav_counter.h" namespace dxvk { diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 512b2cbc..6541fa3d 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -103,14 +103,14 @@ namespace dxvk { throw DxvkError("D3D11Device: Failed to query adapter"); m_initializer = new D3D11Initializer(m_dxvkDevice); + m_uavCounters = new D3D11UavCounterAllocator(this); m_context = new D3D11ImmediateContext(this, m_dxvkDevice); - - CreateCounterBuffer(); } D3D11Device::~D3D11Device() { delete m_context; + delete m_uavCounters; delete m_initializer; } @@ -555,7 +555,7 @@ namespace dxvk { DxvkBufferSlice counterSlice; if (desc.Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_APPEND | D3D11_BUFFER_UAV_FLAG_COUNTER)) - counterSlice = AllocateCounterSlice(); + counterSlice = AllocCounterSlice(); *ppUAView = ref(new D3D11UnorderedAccessView( this, pResource, desc, @@ -1727,27 +1727,6 @@ namespace dxvk { } - DxvkBufferSlice D3D11Device::AllocateCounterSlice() { - std::lock_guard lock(m_counterMutex); - - if (m_counterSlices.size() == 0) - throw DxvkError("D3D11Device: Failed to allocate counter slice"); - - uint32_t sliceId = m_counterSlices.back(); - m_counterSlices.pop_back(); - - return DxvkBufferSlice(m_counterBuffer, - sizeof(D3D11UavCounter) * sliceId, - sizeof(D3D11UavCounter)); - } - - - void D3D11Device::FreeCounterSlice(const DxvkBufferSlice& Slice) { - std::lock_guard lock(m_counterMutex); - m_counterSlices.push_back(Slice.offset() / sizeof(D3D11UavCounter)); - } - - void D3D11Device::FlushInitContext() { m_initializer->Flush(); } @@ -2022,32 +2001,6 @@ namespace dxvk { } - void D3D11Device::CreateCounterBuffer() { - const uint32_t MaxCounterStructs = 1 << 16; - - // The counter buffer is used as a storage buffer - DxvkBufferCreateInfo info; - info.size = MaxCounterStructs * sizeof(D3D11UavCounter); - info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT - | VK_BUFFER_USAGE_TRANSFER_DST_BIT - | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT - | GetEnabledShaderStages(); - info.access = VK_ACCESS_TRANSFER_READ_BIT - | VK_ACCESS_TRANSFER_WRITE_BIT - | VK_ACCESS_SHADER_READ_BIT - | VK_ACCESS_SHADER_WRITE_BIT; - m_counterBuffer = m_dxvkDevice->createBuffer( - info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - // Init the counter struct allocator as well - m_counterSlices.resize(MaxCounterStructs); - - for (uint32_t i = 0; i < MaxCounterStructs; i++) - m_counterSlices[i] = MaxCounterStructs - i - 1; - } - - 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 0967ecd6..907722bf 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -14,6 +14,7 @@ #include "d3d11_options.h" #include "d3d11_shader.h" #include "d3d11_state.h" +#include "d3d11_uav_counter.h" #include "d3d11_util.h" namespace dxvk { @@ -316,10 +317,6 @@ namespace dxvk { return m_dxvkDevice; } - DxvkBufferSlice AllocateCounterSlice(); - - void FreeCounterSlice(const DxvkBufferSlice& Slice); - void FlushInitContext(); VkPipelineStageFlags GetEnabledShaderStages() const; @@ -332,6 +329,14 @@ namespace dxvk { DXGI_FORMAT Format, DXGI_VK_FORMAT_MODE Mode) const; + DxvkBufferSlice AllocCounterSlice() { + return m_uavCounters->AllocSlice(); + } + + void FreeCounterSlice(const DxvkBufferSlice& Slice) { + m_uavCounters->FreeSlice(Slice); + } + bool TestOption(D3D11Option Option) const { return m_d3d11Options.test(Option); } @@ -359,12 +364,9 @@ namespace dxvk { const DxbcOptions m_dxbcOptions; D3D11Initializer* m_initializer = nullptr; + D3D11UavCounterAllocator* m_uavCounters = nullptr; D3D11ImmediateContext* m_context = nullptr; - std::mutex m_counterMutex; - std::vector m_counterSlices; - Rc m_counterBuffer; - D3D11StateObjectSet m_bsStateObjects; D3D11StateObjectSet m_dsStateObjects; D3D11StateObjectSet m_rsStateObjects; @@ -388,8 +390,6 @@ namespace dxvk { VkFormat Format, VkImageType Type) const; - void CreateCounterBuffer(); - static D3D_FEATURE_LEVEL GetMaxFeatureLevel(); }; diff --git a/src/d3d11/d3d11_uav_counter.cpp b/src/d3d11/d3d11_uav_counter.cpp new file mode 100644 index 00000000..ff976801 --- /dev/null +++ b/src/d3d11/d3d11_uav_counter.cpp @@ -0,0 +1,67 @@ +#include "d3d11_device.h" +#include "d3d11_uav_counter.h" + +namespace dxvk { + + constexpr VkDeviceSize D3D11UavCounterAllocator::SlicesPerBuffer; + + + D3D11UavCounterAllocator::D3D11UavCounterAllocator(D3D11Device* pDevice) + : m_device (pDevice), + m_alignment (GetOffsetAlignment()) { + + } + + + D3D11UavCounterAllocator::~D3D11UavCounterAllocator() { + + } + + + DxvkBufferSlice D3D11UavCounterAllocator::AllocSlice() { + std::lock_guard lock(m_mutex); + + if (m_freeSlices.size() == 0) + CreateBuffer(SlicesPerBuffer); + + DxvkBufferSlice slice = m_freeSlices.back(); + m_freeSlices.pop_back(); + return slice; + } + + + void D3D11UavCounterAllocator::FreeSlice(const DxvkBufferSlice& Slice) { + std::lock_guard lock(m_mutex); + m_freeSlices.push_back(Slice); + } + + + void D3D11UavCounterAllocator::CreateBuffer(VkDeviceSize SliceCount) { + DxvkBufferCreateInfo info; + info.size = SliceCount * m_alignment; + info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_TRANSFER_SRC_BIT + | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT + | m_device->GetEnabledShaderStages(); + info.access = VK_ACCESS_TRANSFER_READ_BIT + | VK_ACCESS_TRANSFER_WRITE_BIT + | VK_ACCESS_SHADER_READ_BIT + | VK_ACCESS_SHADER_WRITE_BIT; + + Rc buffer = m_device->GetDXVKDevice()->createBuffer( + info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + for (uint32_t i = 0; i < SliceCount; i++) { + m_freeSlices.push_back(DxvkBufferSlice( + buffer, m_alignment * i, m_alignment)); + } + } + + + VkDeviceSize D3D11UavCounterAllocator::GetOffsetAlignment() const { + const auto& devInfo = m_device->GetDXVKDevice()->adapter()->deviceProperties(); + return align(sizeof(D3D11UavCounter), devInfo.limits.minStorageBufferOffsetAlignment); + } + +} \ No newline at end of file diff --git a/src/d3d11/d3d11_uav_counter.h b/src/d3d11/d3d11_uav_counter.h new file mode 100644 index 00000000..46859cb4 --- /dev/null +++ b/src/d3d11/d3d11_uav_counter.h @@ -0,0 +1,69 @@ +#pragma once + +#include "d3d11_include.h" + +namespace dxvk { + + class D3D11Device; + + /** + * \brief UAV counter structure + * + * Data structure passed to shaders that use + * append/consume buffer functionality. + */ + struct D3D11UavCounter { + uint32_t atomicCtr; + }; + + + /** + * \brief D3D11 UAV counter slice allocator + * + * Thread-safe allocator for UAV counter slices. + * The resulting slices are aligned to the device's + * \c minStorageBufferOffsetAlignment. + */ + class D3D11UavCounterAllocator { + constexpr static VkDeviceSize SlicesPerBuffer = 16384; + public: + + D3D11UavCounterAllocator( + D3D11Device* pDevice); + + ~D3D11UavCounterAllocator(); + + /** + * \brief Allocates a counter slice + * + * Picks a slice from the free list or + * creates a new buffer if necessary. + * \returns The counter slice + */ + DxvkBufferSlice AllocSlice(); + + /** + * \brief Frees a counter slice + * + * Adds the given slice back to the + * free list so that it can be reused. + * \param [in] Slice the slice to free + */ + void FreeSlice( + const DxvkBufferSlice& Slice); + + private: + + D3D11Device* m_device; + VkDeviceSize m_alignment; + + std::mutex m_mutex; + std::vector m_freeSlices; + + void CreateBuffer(VkDeviceSize SliceCount); + + VkDeviceSize GetOffsetAlignment() const; + + }; + +} \ No newline at end of file diff --git a/src/d3d11/d3d11_view_uav.h b/src/d3d11/d3d11_view_uav.h index 1dbce10b..8ef7bcf6 100644 --- a/src/d3d11/d3d11_view_uav.h +++ b/src/d3d11/d3d11_view_uav.h @@ -8,11 +8,6 @@ namespace dxvk { class D3D11Device; - struct D3D11UavCounter { - uint32_t atomicCtr; - }; - - /** * \brief Unordered access view * diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index 88bbf824..db007a57 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -22,6 +22,7 @@ d3d11_src = [ 'd3d11_shader.cpp', 'd3d11_state.cpp', 'd3d11_texture.cpp', + 'd3d11_uav_counter.cpp', 'd3d11_util.cpp', 'd3d11_view_dsv.cpp', 'd3d11_view_rtv.cpp',