diff --git a/src/dxvk/dxvk_memory.cpp b/src/dxvk/dxvk_memory.cpp index aca64296..af4760b5 100644 --- a/src/dxvk/dxvk_memory.cpp +++ b/src/dxvk/dxvk_memory.cpp @@ -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;