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:
parent
212bd56b93
commit
8044ce6c7e
@ -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 {
|
||||
|
||||
|
@ -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 },
|
||||
|
@ -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();
|
||||
|
||||
};
|
||||
|
67
src/d3d11/d3d11_uav_counter.cpp
Normal file
67
src/d3d11/d3d11_uav_counter.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
69
src/d3d11/d3d11_uav_counter.h
Normal file
69
src/d3d11/d3d11_uav_counter.h
Normal 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;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -8,11 +8,6 @@ namespace dxvk {
|
||||
|
||||
class D3D11Device;
|
||||
|
||||
struct D3D11UavCounter {
|
||||
uint32_t atomicCtr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Unordered access view
|
||||
*
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user