[dxvk] Rework allocation logic for large resources

This may reduce internal fragmentation with very large resources.

We previously changed behaviour to not do this in order to reduce memory
pressure in the average case, however by trying to suballocate from existing
chunks and falling back to a dedicated allocation on failure, rather than
allocating a new chunk, we can mostly avoid that situation.
This commit is contained in:
Philip Rebohle 2022-09-22 16:37:41 +02:00
parent 15588004b4
commit f1f8d45fcd
1 changed files with 26 additions and 8 deletions

View File

@ -326,19 +326,25 @@ namespace dxvk {
DxvkMemory memory;
if (size >= chunkSize || info.dedicated.buffer || info.dedicated.image) {
if (this->shouldFreeEmptyChunks(type->heap, size))
this->freeEmptyChunks(type->heap);
// Require dedicated allocations for resources that use the Vulkan dedicated
// allocation bits, or are too large to fit into a single full-sized chunk
bool needsDedicatedAlocation = size >= chunkSize || info.dedicated.buffer || info.dedicated.image;
DxvkDeviceMemory devMem = this->tryAllocDeviceMemory(type, size, info, hints);
// Prefer a dedicated allocation for very large resources in order to
// reduce fragmentation if a large number of those resources are in use
bool wantsDedicatedAllocation = 3 * size >= chunkSize;
if (devMem.memHandle != VK_NULL_HANDLE)
memory = DxvkMemory(this, nullptr, type, devMem.memHandle, 0, size, devMem.memPointer);
} else {
// Try to reuse existing memory as much as possible in case the heap is nearly full
bool heapBudgedExceeded = 5 * type->heap->stats.memoryUsed + size > 4 * type->heap->properties.size;
if (!needsDedicatedAlocation && (!wantsDedicatedAllocation || heapBudgedExceeded)) {
// Attempt to suballocate from existing chunks first
for (uint32_t i = 0; i < type->chunks.size() && !memory; i++)
memory = type->chunks[i]->alloc(info.flags, size, align, hints);
if (!memory) {
// If no existing chunk can accomodate the allocation, and if a dedicated
// allocation is not preferred, create a new chunk and suballocate from it
if (!memory && !wantsDedicatedAllocation) {
DxvkDeviceMemory devMem;
if (this->shouldFreeEmptyChunks(type->heap, chunkSize))
@ -356,6 +362,18 @@ namespace dxvk {
}
}
// If a dedicated allocation is required or preferred and we haven't managed
// to suballocate any memory before, try to create a dedicated allocation
if (!memory && (needsDedicatedAlocation || wantsDedicatedAllocation)) {
if (this->shouldFreeEmptyChunks(type->heap, size))
this->freeEmptyChunks(type->heap);
DxvkDeviceMemory devMem = this->tryAllocDeviceMemory(type, size, info, hints);
if (devMem.memHandle != VK_NULL_HANDLE)
memory = DxvkMemory(this, nullptr, type, devMem.memHandle, 0, size, devMem.memPointer);
}
if (memory)
type->heap->stats.memoryUsed += memory.m_length;