From 2c77bf96d9c8f58a76f879a21f81ed6b6d8655e2 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Sat, 2 Mar 2024 00:56:46 -0800 Subject: [PATCH] restructure allocation strategy for small allocations --- src/Refresh_Driver_Vulkan.c | 192 ++++++++++++++++++++---------------- 1 file changed, 108 insertions(+), 84 deletions(-) diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index 9753c82..6be59f9 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -74,11 +74,11 @@ typedef struct VulkanExtensions /* Defines */ -#define STARTING_ALLOCATION_SIZE 67108864 /* 64MiB */ -#define MAX_ALLOCATION_SIZE 268435456 /* 256MiB */ -#define ALLOCATION_INCREMENT 16777216 /* 16MiB */ -#define UBO_BUFFER_SIZE 16777216 /* 16MiB */ -#define MAX_UBO_SECTION_SIZE 4096 /* 4KiB */ +#define SMALL_ALLOCATION_THRESHOLD 1048576 /* 1 MiB */ +#define SMALL_ALLOCATION_SIZE 16777216 /* 16 MiB */ +#define LARGE_ALLOCATION_INCREMENT 67108864 /* 64 MiB */ +#define UBO_BUFFER_SIZE 16777216 /* 16 MiB */ +#define MAX_UBO_SECTION_SIZE 4096 /* 4 KiB */ #define DESCRIPTOR_POOL_STARTING_SIZE 128 #define MAX_FRAMES_IN_FLIGHT 3 #define WINDOW_DATA "Refresh_VulkanWindowData" @@ -424,7 +424,6 @@ typedef struct VulkanMemoryUsedRegion typedef struct VulkanMemorySubAllocator { uint32_t memoryTypeIndex; - VkDeviceSize nextAllocationSize; VulkanMemoryAllocation **allocations; uint32_t allocationCount; VulkanMemoryFreeRegion **sortedFreeRegions; @@ -2626,13 +2625,15 @@ static uint8_t VULKAN_INTERNAL_BindResourceMemory( VulkanMemoryAllocation *allocation; VulkanMemorySubAllocator *allocator; VulkanMemoryFreeRegion *region; + VulkanMemoryFreeRegion *selectedRegion; VulkanMemoryUsedRegion *usedRegion; VkDeviceSize requiredSize, allocationSize; VkDeviceSize alignedOffset; uint32_t newRegionSize, newRegionOffset; uint8_t shouldAllocDedicated = forceDedicated; - uint8_t isHostVisible, allocationResult; + uint8_t isHostVisible, smallAllocation, allocationResult; + int32_t i; isHostVisible = (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & @@ -2640,6 +2641,7 @@ static uint8_t VULKAN_INTERNAL_BindResourceMemory( allocator = &renderer->memoryAllocator->subAllocators[memoryTypeIndex]; requiredSize = memoryRequirements->memoryRequirements.size; + smallAllocation = requiredSize < SMALL_ALLOCATION_THRESHOLD; if ( (buffer == VK_NULL_HANDLE && image == VK_NULL_HANDLE) || (buffer != VK_NULL_HANDLE && image != VK_NULL_HANDLE) ) @@ -2650,90 +2652,113 @@ static uint8_t VULKAN_INTERNAL_BindResourceMemory( SDL_LockMutex(renderer->allocatorLock); - /* find the largest free region and use it */ - if (!shouldAllocDedicated && allocator->sortedFreeRegionCount > 0) + selectedRegion = NULL; + + if (!shouldAllocDedicated) { - region = allocator->sortedFreeRegions[0]; - allocation = region->allocation; - - alignedOffset = VULKAN_INTERNAL_NextHighestAlignment( - region->offset, - memoryRequirements->memoryRequirements.alignment - ); - - if (alignedOffset + requiredSize <= region->offset + region->size) + for (i = allocator->sortedFreeRegionCount - 1; i >= 0; i -= 1) { - usedRegion = VULKAN_INTERNAL_NewMemoryUsedRegion( - renderer, - allocation, + region = allocator->sortedFreeRegions[i]; + + if (smallAllocation && region->allocation->size != SMALL_ALLOCATION_SIZE) + { + /* region is not in a small allocation */ + continue; + } + + if (!smallAllocation && region->allocation->size == SMALL_ALLOCATION_SIZE) + { + /* allocation is not small and current region is in a small allocation */ + continue; + } + + alignedOffset = VULKAN_INTERNAL_NextHighestAlignment( region->offset, - requiredSize + (alignedOffset - region->offset), - alignedOffset, - resourceSize, memoryRequirements->memoryRequirements.alignment ); - usedRegion->isBuffer = buffer != VK_NULL_HANDLE; - - newRegionSize = region->size - ((alignedOffset - region->offset) + requiredSize); - newRegionOffset = alignedOffset + requiredSize; - - /* remove and add modified region to re-sort */ - VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, region); - - /* if size is 0, no need to re-insert */ - if (newRegionSize != 0) + if (alignedOffset + requiredSize <= region->offset + region->size) { - VULKAN_INTERNAL_NewMemoryFreeRegion( - renderer, - allocation, - newRegionOffset, - newRegionSize - ); + selectedRegion = region; + break; } - - SDL_UnlockMutex(renderer->allocatorLock); - - if (buffer != VK_NULL_HANDLE) - { - if (!VULKAN_INTERNAL_BindBufferMemory( - renderer, - usedRegion, - alignedOffset, - buffer - )) { - VULKAN_INTERNAL_RemoveMemoryUsedRegion( - renderer, - usedRegion - ); - - return 0; - } - } - else if (image != VK_NULL_HANDLE) - { - if (!VULKAN_INTERNAL_BindImageMemory( - renderer, - usedRegion, - alignedOffset, - image - )) { - VULKAN_INTERNAL_RemoveMemoryUsedRegion( - renderer, - usedRegion - ); - - return 0; - } - } - - *pMemoryUsedRegion = usedRegion; - return 1; } } - /* No suitable free regions exist, allocate a new memory region */ + if (selectedRegion != NULL) + { + region = selectedRegion; + allocation = region->allocation; + usedRegion = VULKAN_INTERNAL_NewMemoryUsedRegion( + renderer, + allocation, + region->offset, + requiredSize + (alignedOffset - region->offset), + alignedOffset, + resourceSize, + memoryRequirements->memoryRequirements.alignment + ); + + usedRegion->isBuffer = buffer != VK_NULL_HANDLE; + + newRegionSize = region->size - ((alignedOffset - region->offset) + requiredSize); + newRegionOffset = alignedOffset + requiredSize; + + /* remove and add modified region to re-sort */ + VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, region); + + /* if size is 0, no need to re-insert */ + if (newRegionSize != 0) + { + VULKAN_INTERNAL_NewMemoryFreeRegion( + renderer, + allocation, + newRegionOffset, + newRegionSize + ); + } + + SDL_UnlockMutex(renderer->allocatorLock); + + if (buffer != VK_NULL_HANDLE) + { + if (!VULKAN_INTERNAL_BindBufferMemory( + renderer, + usedRegion, + alignedOffset, + buffer + )) { + VULKAN_INTERNAL_RemoveMemoryUsedRegion( + renderer, + usedRegion + ); + + return 0; + } + } + else if (image != VK_NULL_HANDLE) + { + if (!VULKAN_INTERNAL_BindImageMemory( + renderer, + usedRegion, + alignedOffset, + image + )) { + VULKAN_INTERNAL_RemoveMemoryUsedRegion( + renderer, + usedRegion + ); + + return 0; + } + } + + *pMemoryUsedRegion = usedRegion; + return 1; + } + + /* No suitable free regions exist, allocate a new memory region */ if ( !shouldAllocDedicated && renderer->allocationsToDefragCount == 0 && @@ -2747,15 +2772,15 @@ static uint8_t VULKAN_INTERNAL_BindResourceMemory( { allocationSize = requiredSize; } - else if (requiredSize > allocator->nextAllocationSize) + else if (requiredSize > SMALL_ALLOCATION_THRESHOLD) { - /* allocate a page of required size aligned to ALLOCATION_INCREMENT increments */ + /* allocate a page of required size aligned to LARGE_ALLOCATION_INCREMENT increments */ allocationSize = - VULKAN_INTERNAL_NextHighestAlignment(requiredSize, ALLOCATION_INCREMENT); + VULKAN_INTERNAL_NextHighestAlignment(requiredSize, LARGE_ALLOCATION_INCREMENT); } else { - allocationSize = allocator->nextAllocationSize; + allocationSize = SMALL_ALLOCATION_SIZE; } allocationResult = VULKAN_INTERNAL_AllocateMemory( @@ -11543,7 +11568,6 @@ static Refresh_Device* VULKAN_CreateDevice( for (i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { renderer->memoryAllocator->subAllocators[i].memoryTypeIndex = i; - renderer->memoryAllocator->subAllocators[i].nextAllocationSize = STARTING_ALLOCATION_SIZE; renderer->memoryAllocator->subAllocators[i].allocations = NULL; renderer->memoryAllocator->subAllocators[i].allocationCount = 0; renderer->memoryAllocator->subAllocators[i].sortedFreeRegions = SDL_malloc(