mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-19 05:52:11 +01:00
[dxvk] Use new allocators for chunk suballocation
This commit is contained in:
parent
5efaa06c61
commit
661385584a
@ -68,9 +68,10 @@ namespace dxvk {
|
|||||||
DxvkMemoryType* type,
|
DxvkMemoryType* type,
|
||||||
DxvkDeviceMemory memory,
|
DxvkDeviceMemory memory,
|
||||||
DxvkMemoryFlags hints)
|
DxvkMemoryFlags hints)
|
||||||
: m_alloc(alloc), m_type(type), m_memory(memory), m_hints(hints) {
|
: m_alloc(alloc), m_type(type), m_memory(memory), m_hints(hints),
|
||||||
// Mark the entire chunk as free
|
m_pageAllocator(memory.memSize),
|
||||||
m_freeList.push_back(FreeSlice { 0, memory.memSize });
|
m_poolAllocator(m_pageAllocator) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -91,78 +92,34 @@ namespace dxvk {
|
|||||||
if (m_memory.memFlags != flags || !checkHints(hints))
|
if (m_memory.memFlags != flags || !checkHints(hints))
|
||||||
return DxvkMemory();
|
return DxvkMemory();
|
||||||
|
|
||||||
// If the chunk is full, return
|
size = dxvk::align(size, align);
|
||||||
if (m_freeList.size() == 0)
|
|
||||||
|
int64_t address = size <= DxvkPoolAllocator::MaxSize
|
||||||
|
? m_poolAllocator.alloc(size)
|
||||||
|
: m_pageAllocator.alloc(size, align);
|
||||||
|
|
||||||
|
if (address < 0)
|
||||||
return DxvkMemory();
|
return DxvkMemory();
|
||||||
|
|
||||||
// Select the slice to allocate from in a worst-fit
|
|
||||||
// manner. This may help keep fragmentation low.
|
|
||||||
auto bestSlice = m_freeList.begin();
|
|
||||||
|
|
||||||
for (auto slice = m_freeList.begin(); slice != m_freeList.end(); slice++) {
|
|
||||||
if (slice->length == size) {
|
|
||||||
bestSlice = slice;
|
|
||||||
break;
|
|
||||||
} else if (slice->length > bestSlice->length) {
|
|
||||||
bestSlice = slice;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to align the allocation to the requested alignment
|
|
||||||
const VkDeviceSize sliceStart = bestSlice->offset;
|
|
||||||
const VkDeviceSize sliceEnd = bestSlice->offset + bestSlice->length;
|
|
||||||
|
|
||||||
const VkDeviceSize allocStart = dxvk::align(sliceStart, align);
|
|
||||||
const VkDeviceSize allocEnd = dxvk::align(allocStart + size, align);
|
|
||||||
|
|
||||||
if (allocEnd > sliceEnd)
|
|
||||||
return DxvkMemory();
|
|
||||||
|
|
||||||
// We can use this slice, but we'll have to add
|
|
||||||
// the unused parts of it back to the free list.
|
|
||||||
m_freeList.erase(bestSlice);
|
|
||||||
|
|
||||||
if (allocStart != sliceStart)
|
|
||||||
m_freeList.push_back({ sliceStart, allocStart - sliceStart });
|
|
||||||
|
|
||||||
if (allocEnd != sliceEnd)
|
|
||||||
m_freeList.push_back({ allocEnd, sliceEnd - allocEnd });
|
|
||||||
|
|
||||||
// Create the memory object with the aligned slice
|
// Create the memory object with the aligned slice
|
||||||
return DxvkMemory(m_alloc, this, m_type,
|
return DxvkMemory(m_alloc, this, m_type,
|
||||||
m_memory.buffer, m_memory.memHandle, allocStart, allocEnd - allocStart,
|
m_memory.buffer, m_memory.memHandle, address, size,
|
||||||
reinterpret_cast<char*>(m_memory.memPointer) + allocStart);
|
reinterpret_cast<char*>(m_memory.memPointer) + address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkMemoryChunk::free(
|
void DxvkMemoryChunk::free(
|
||||||
VkDeviceSize offset,
|
VkDeviceSize offset,
|
||||||
VkDeviceSize length) {
|
VkDeviceSize length) {
|
||||||
// Remove adjacent entries from the free list and then add
|
if (length <= DxvkPoolAllocator::MaxSize)
|
||||||
// a new slice that covers all those entries. Without doing
|
m_poolAllocator.free(offset, length);
|
||||||
// so, the slice could not be reused for larger allocations.
|
else
|
||||||
auto curr = m_freeList.begin();
|
m_pageAllocator.free(offset, length);
|
||||||
|
|
||||||
while (curr != m_freeList.end()) {
|
|
||||||
if (curr->offset == offset + length) {
|
|
||||||
length += curr->length;
|
|
||||||
curr = m_freeList.erase(curr);
|
|
||||||
} else if (curr->offset + curr->length == offset) {
|
|
||||||
offset -= curr->length;
|
|
||||||
length += curr->length;
|
|
||||||
curr = m_freeList.erase(curr);
|
|
||||||
} else {
|
|
||||||
curr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_freeList.push_back({ offset, length });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DxvkMemoryChunk::isEmpty() const {
|
bool DxvkMemoryChunk::isEmpty() const {
|
||||||
return m_freeList.size() == 1
|
return m_pageAllocator.pagesUsed() == 0u;
|
||||||
&& m_freeList[0].length == m_memory.memSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "dxvk_adapter.h"
|
#include "dxvk_adapter.h"
|
||||||
|
#include "dxvk_allocator.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
@ -287,17 +288,13 @@ namespace dxvk {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct FreeSlice {
|
|
||||||
VkDeviceSize offset;
|
|
||||||
VkDeviceSize length;
|
|
||||||
};
|
|
||||||
|
|
||||||
DxvkMemoryAllocator* m_alloc;
|
DxvkMemoryAllocator* m_alloc;
|
||||||
DxvkMemoryType* m_type;
|
DxvkMemoryType* m_type;
|
||||||
DxvkDeviceMemory m_memory;
|
DxvkDeviceMemory m_memory;
|
||||||
DxvkMemoryFlags m_hints;
|
DxvkMemoryFlags m_hints;
|
||||||
|
|
||||||
std::vector<FreeSlice> m_freeList;
|
DxvkPageAllocator m_pageAllocator;
|
||||||
|
DxvkPoolAllocator m_poolAllocator;
|
||||||
|
|
||||||
bool checkHints(DxvkMemoryFlags hints) const;
|
bool checkHints(DxvkMemoryFlags hints) const;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user