mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-22 16:54:27 +01:00
[dxvk] Tune small buffer allocation sizes
The pool allocator works on powers of two, so buffers should too.
This commit is contained in:
parent
3faa1a76da
commit
35fea6475d
@ -22,31 +22,38 @@ namespace dxvk {
|
|||||||
VkDeviceSize sliceAlignment = computeSliceAlignment(device);
|
VkDeviceSize sliceAlignment = computeSliceAlignment(device);
|
||||||
m_physSliceLength = createInfo.size;
|
m_physSliceLength = createInfo.size;
|
||||||
m_physSliceStride = align(createInfo.size, sliceAlignment);
|
m_physSliceStride = align(createInfo.size, sliceAlignment);
|
||||||
m_physSliceCount = std::max<VkDeviceSize>(1, 256 / m_physSliceStride);
|
|
||||||
|
|
||||||
// Limit size of multi-slice buffers to reduce fragmentation
|
// Determine optimal allocation size for the buffer. If the buffer
|
||||||
constexpr VkDeviceSize MaxBufferSize = 256 << 10;
|
// is small enough to hit the pool allocator, round its size up to
|
||||||
|
// a power of two to minimize the amount of internal fragmentation.
|
||||||
|
VkDeviceSize sliceSize = align(createInfo.size, sliceAlignment);
|
||||||
|
m_allocationSize = std::max(MinAllocationSize, sliceSize);
|
||||||
|
|
||||||
m_physSliceMaxCount = MaxBufferSize >= m_physSliceStride
|
if (m_allocationSize <= DxvkPoolAllocator::MaxSize)
|
||||||
? MaxBufferSize / m_physSliceStride
|
m_allocationSize = (VkDeviceSize(-1) >> bit::lzcnt(m_allocationSize - 1u)) + 1u;
|
||||||
: 1;
|
|
||||||
|
m_maxAllocationSize = MaxSlicesPerAllocation * sliceSize;
|
||||||
|
m_maxAllocationSize = std::max(m_maxAllocationSize, MinAllocationSizeLimit);
|
||||||
|
m_maxAllocationSize = std::min(m_maxAllocationSize, MaxAllocationSize);
|
||||||
|
|
||||||
// Allocate the initial set of buffer slices. Only clear
|
// Allocate the initial set of buffer slices. Only clear
|
||||||
// buffer memory if there is more than one slice, since
|
// buffer memory if there is more than one slice, since
|
||||||
// we expect the client api to initialize the first slice.
|
// we expect the client api to initialize the first slice.
|
||||||
m_buffer = allocBuffer(m_physSliceCount, m_physSliceCount > 1);
|
bool hasMultipleSlices = m_allocationSize >= sliceSize + sliceSize;
|
||||||
|
|
||||||
|
m_buffer = allocBuffer(m_allocationSize, hasMultipleSlices);
|
||||||
|
|
||||||
m_physSlice.handle = m_buffer.buffer;
|
m_physSlice.handle = m_buffer.buffer;
|
||||||
m_physSlice.offset = m_buffer.getBaseOffset();
|
m_physSlice.offset = m_buffer.getBaseOffset();
|
||||||
m_physSlice.length = m_physSliceLength;
|
m_physSlice.length = m_physSliceLength;
|
||||||
m_physSlice.mapPtr = m_buffer.memory.mapPtr(0);
|
m_physSlice.mapPtr = m_buffer.memory.mapPtr(0);
|
||||||
|
|
||||||
m_lazyAlloc = m_physSliceCount > 1;
|
m_lazyAlloc = hasMultipleSlices;
|
||||||
} else {
|
} else {
|
||||||
m_physSliceLength = createInfo.size;
|
m_physSliceLength = createInfo.size;
|
||||||
m_physSliceStride = createInfo.size;
|
m_physSliceStride = createInfo.size;
|
||||||
m_physSliceCount = 1;
|
|
||||||
m_physSliceMaxCount = 1;
|
m_allocationSize = createInfo.size;
|
||||||
|
|
||||||
m_buffer = createSparseBuffer();
|
m_buffer = createSparseBuffer();
|
||||||
|
|
||||||
@ -75,14 +82,14 @@ namespace dxvk {
|
|||||||
m_shaderStages (util::shaderStages(createInfo.stages)) {
|
m_shaderStages (util::shaderStages(createInfo.stages)) {
|
||||||
m_physSliceLength = createInfo.size;
|
m_physSliceLength = createInfo.size;
|
||||||
m_physSliceStride = createInfo.size;
|
m_physSliceStride = createInfo.size;
|
||||||
m_physSliceCount = 1;
|
|
||||||
m_physSliceMaxCount = 1;
|
|
||||||
|
|
||||||
m_physSlice.handle = importInfo.buffer;
|
m_physSlice.handle = importInfo.buffer;
|
||||||
m_physSlice.offset = importInfo.offset;
|
m_physSlice.offset = importInfo.offset;
|
||||||
m_physSlice.length = createInfo.size;
|
m_physSlice.length = createInfo.size;
|
||||||
m_physSlice.mapPtr = importInfo.mapPtr;
|
m_physSlice.mapPtr = importInfo.mapPtr;
|
||||||
|
|
||||||
|
m_allocationSize = createInfo.size;
|
||||||
|
|
||||||
m_lazyAlloc = false;
|
m_lazyAlloc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,10 +105,10 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkBufferHandle DxvkBuffer::allocBuffer(VkDeviceSize sliceCount, bool clear) const {
|
DxvkBufferHandle DxvkBuffer::allocBuffer(VkDeviceSize allocationSize, bool clear) const {
|
||||||
VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||||
info.flags = m_info.flags;
|
info.flags = m_info.flags;
|
||||||
info.size = m_physSliceStride * sliceCount;
|
info.size = allocationSize;
|
||||||
info.usage = m_info.usage;
|
info.usage = m_info.usage;
|
||||||
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
@ -130,6 +130,13 @@ namespace dxvk {
|
|||||||
*/
|
*/
|
||||||
class DxvkBuffer : public DxvkPagedResource {
|
class DxvkBuffer : public DxvkPagedResource {
|
||||||
friend class DxvkBufferView;
|
friend class DxvkBufferView;
|
||||||
|
|
||||||
|
constexpr static VkDeviceSize MaxAllocationSize = DxvkPageAllocator::PageSize;
|
||||||
|
constexpr static VkDeviceSize MinAllocationSize = DxvkPoolAllocator::MinSize;
|
||||||
|
|
||||||
|
constexpr static VkDeviceSize MinAllocationSizeLimit = MaxAllocationSize / 32u;
|
||||||
|
|
||||||
|
constexpr static uint32_t MaxSlicesPerAllocation = 64u;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DxvkBuffer(
|
DxvkBuffer(
|
||||||
@ -280,15 +287,17 @@ namespace dxvk {
|
|||||||
// backing buffer and add all slices to the free list.
|
// backing buffer and add all slices to the free list.
|
||||||
if (unlikely(m_freeSlices.empty())) {
|
if (unlikely(m_freeSlices.empty())) {
|
||||||
if (likely(!m_lazyAlloc)) {
|
if (likely(!m_lazyAlloc)) {
|
||||||
DxvkBufferHandle handle = allocBuffer(m_physSliceCount, true);
|
DxvkBufferHandle handle = allocBuffer(m_allocationSize, true);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < m_physSliceCount; i++)
|
for (uint32_t i = 0; (i + 1) * m_physSliceStride <= m_allocationSize; i++)
|
||||||
pushSlice(handle, i);
|
pushSlice(handle, i);
|
||||||
|
|
||||||
m_buffers.push_back(std::move(handle));
|
m_buffers.push_back(std::move(handle));
|
||||||
m_physSliceCount = std::min(m_physSliceCount * 2, m_physSliceMaxCount);
|
|
||||||
|
if (2u * m_allocationSize <= m_maxAllocationSize)
|
||||||
|
m_allocationSize *= 2u;
|
||||||
} else {
|
} else {
|
||||||
for (uint32_t i = 1; i < m_physSliceCount; i++)
|
for (uint32_t i = 1; (i + 1) * m_physSliceStride <= m_allocationSize; i++)
|
||||||
pushSlice(m_buffer, i);
|
pushSlice(m_buffer, i);
|
||||||
|
|
||||||
m_lazyAlloc = false;
|
m_lazyAlloc = false;
|
||||||
@ -342,8 +351,9 @@ namespace dxvk {
|
|||||||
uint32_t m_lazyAlloc = false;
|
uint32_t m_lazyAlloc = false;
|
||||||
VkDeviceSize m_physSliceLength = 0;
|
VkDeviceSize m_physSliceLength = 0;
|
||||||
VkDeviceSize m_physSliceStride = 0;
|
VkDeviceSize m_physSliceStride = 0;
|
||||||
VkDeviceSize m_physSliceCount = 1;
|
|
||||||
VkDeviceSize m_physSliceMaxCount = 1;
|
VkDeviceSize m_allocationSize = 0;
|
||||||
|
VkDeviceSize m_maxAllocationSize = 0;
|
||||||
|
|
||||||
std::vector<DxvkBufferHandle> m_buffers;
|
std::vector<DxvkBufferHandle> m_buffers;
|
||||||
std::vector<DxvkBufferSliceHandle> m_freeSlices;
|
std::vector<DxvkBufferSliceHandle> m_freeSlices;
|
||||||
@ -362,7 +372,7 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DxvkBufferHandle allocBuffer(
|
DxvkBufferHandle allocBuffer(
|
||||||
VkDeviceSize sliceCount,
|
VkDeviceSize allocationSize,
|
||||||
bool clear) const;
|
bool clear) const;
|
||||||
|
|
||||||
DxvkBufferHandle createSparseBuffer() const;
|
DxvkBufferHandle createSparseBuffer() const;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user