1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-02 10:24:12 +01:00

[d3d11] Refactor UAV counter buffer allocator

- Fixes violation of the minStorageBufferOffsetAlignment limit
- Allows allocation of multiple counter buffers if necessary
This commit is contained in:
Philip Rebohle 2018-08-03 10:17:02 +02:00
parent 212bd56b93
commit 8044ce6c7e
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
7 changed files with 151 additions and 65 deletions

View File

@ -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 {

View File

@ -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<std::mutex> 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<std::mutex> 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<std::pair<std::string, D3D_FEATURE_LEVEL>, 7> s_featureLevels = {{
{ "11_1", D3D_FEATURE_LEVEL_11_1 },

View File

@ -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<uint32_t> m_counterSlices;
Rc<DxvkBuffer> m_counterBuffer;
D3D11StateObjectSet<D3D11BlendState> m_bsStateObjects;
D3D11StateObjectSet<D3D11DepthStencilState> m_dsStateObjects;
D3D11StateObjectSet<D3D11RasterizerState> m_rsStateObjects;
@ -388,8 +390,6 @@ namespace dxvk {
VkFormat Format,
VkImageType Type) const;
void CreateCounterBuffer();
static D3D_FEATURE_LEVEL GetMaxFeatureLevel();
};

View File

@ -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<std::mutex> 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<std::mutex> 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<DxvkBuffer> 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);
}
}

View File

@ -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<DxvkBufferSlice> m_freeSlices;
void CreateBuffer(VkDeviceSize SliceCount);
VkDeviceSize GetOffsetAlignment() const;
};
}

View File

@ -8,11 +8,6 @@ namespace dxvk {
class D3D11Device;
struct D3D11UavCounter {
uint32_t atomicCtr;
};
/**
* \brief Unordered access view
*

View File

@ -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',