restructure allocation strategy for small allocations
continuous-integration/drone/push Build is passing Details

pull/51/head
cosmonaut 2024-03-02 00:56:46 -08:00
parent 0994ac152e
commit 2c77bf96d9
1 changed files with 108 additions and 84 deletions

View File

@ -74,11 +74,11 @@ typedef struct VulkanExtensions
/* Defines */ /* Defines */
#define STARTING_ALLOCATION_SIZE 67108864 /* 64MiB */ #define SMALL_ALLOCATION_THRESHOLD 1048576 /* 1 MiB */
#define MAX_ALLOCATION_SIZE 268435456 /* 256MiB */ #define SMALL_ALLOCATION_SIZE 16777216 /* 16 MiB */
#define ALLOCATION_INCREMENT 16777216 /* 16MiB */ #define LARGE_ALLOCATION_INCREMENT 67108864 /* 64 MiB */
#define UBO_BUFFER_SIZE 16777216 /* 16MiB */ #define UBO_BUFFER_SIZE 16777216 /* 16 MiB */
#define MAX_UBO_SECTION_SIZE 4096 /* 4KiB */ #define MAX_UBO_SECTION_SIZE 4096 /* 4 KiB */
#define DESCRIPTOR_POOL_STARTING_SIZE 128 #define DESCRIPTOR_POOL_STARTING_SIZE 128
#define MAX_FRAMES_IN_FLIGHT 3 #define MAX_FRAMES_IN_FLIGHT 3
#define WINDOW_DATA "Refresh_VulkanWindowData" #define WINDOW_DATA "Refresh_VulkanWindowData"
@ -424,7 +424,6 @@ typedef struct VulkanMemoryUsedRegion
typedef struct VulkanMemorySubAllocator typedef struct VulkanMemorySubAllocator
{ {
uint32_t memoryTypeIndex; uint32_t memoryTypeIndex;
VkDeviceSize nextAllocationSize;
VulkanMemoryAllocation **allocations; VulkanMemoryAllocation **allocations;
uint32_t allocationCount; uint32_t allocationCount;
VulkanMemoryFreeRegion **sortedFreeRegions; VulkanMemoryFreeRegion **sortedFreeRegions;
@ -2626,13 +2625,15 @@ static uint8_t VULKAN_INTERNAL_BindResourceMemory(
VulkanMemoryAllocation *allocation; VulkanMemoryAllocation *allocation;
VulkanMemorySubAllocator *allocator; VulkanMemorySubAllocator *allocator;
VulkanMemoryFreeRegion *region; VulkanMemoryFreeRegion *region;
VulkanMemoryFreeRegion *selectedRegion;
VulkanMemoryUsedRegion *usedRegion; VulkanMemoryUsedRegion *usedRegion;
VkDeviceSize requiredSize, allocationSize; VkDeviceSize requiredSize, allocationSize;
VkDeviceSize alignedOffset; VkDeviceSize alignedOffset;
uint32_t newRegionSize, newRegionOffset; uint32_t newRegionSize, newRegionOffset;
uint8_t shouldAllocDedicated = forceDedicated; uint8_t shouldAllocDedicated = forceDedicated;
uint8_t isHostVisible, allocationResult; uint8_t isHostVisible, smallAllocation, allocationResult;
int32_t i;
isHostVisible = isHostVisible =
(renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags &
@ -2640,6 +2641,7 @@ static uint8_t VULKAN_INTERNAL_BindResourceMemory(
allocator = &renderer->memoryAllocator->subAllocators[memoryTypeIndex]; allocator = &renderer->memoryAllocator->subAllocators[memoryTypeIndex];
requiredSize = memoryRequirements->memoryRequirements.size; requiredSize = memoryRequirements->memoryRequirements.size;
smallAllocation = requiredSize < SMALL_ALLOCATION_THRESHOLD;
if ( (buffer == VK_NULL_HANDLE && image == VK_NULL_HANDLE) || if ( (buffer == VK_NULL_HANDLE && image == VK_NULL_HANDLE) ||
(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); SDL_LockMutex(renderer->allocatorLock);
/* find the largest free region and use it */ selectedRegion = NULL;
if (!shouldAllocDedicated && allocator->sortedFreeRegionCount > 0)
if (!shouldAllocDedicated)
{ {
region = allocator->sortedFreeRegions[0]; for (i = allocator->sortedFreeRegionCount - 1; i >= 0; i -= 1)
allocation = region->allocation;
alignedOffset = VULKAN_INTERNAL_NextHighestAlignment(
region->offset,
memoryRequirements->memoryRequirements.alignment
);
if (alignedOffset + requiredSize <= region->offset + region->size)
{ {
usedRegion = VULKAN_INTERNAL_NewMemoryUsedRegion( region = allocator->sortedFreeRegions[i];
renderer,
allocation, 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, region->offset,
requiredSize + (alignedOffset - region->offset),
alignedOffset,
resourceSize,
memoryRequirements->memoryRequirements.alignment memoryRequirements->memoryRequirements.alignment
); );
usedRegion->isBuffer = buffer != VK_NULL_HANDLE; if (alignedOffset + requiredSize <= region->offset + region->size)
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( selectedRegion = region;
renderer, break;
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 (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 ( if (
!shouldAllocDedicated && !shouldAllocDedicated &&
renderer->allocationsToDefragCount == 0 && renderer->allocationsToDefragCount == 0 &&
@ -2747,15 +2772,15 @@ static uint8_t VULKAN_INTERNAL_BindResourceMemory(
{ {
allocationSize = requiredSize; 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 = allocationSize =
VULKAN_INTERNAL_NextHighestAlignment(requiredSize, ALLOCATION_INCREMENT); VULKAN_INTERNAL_NextHighestAlignment(requiredSize, LARGE_ALLOCATION_INCREMENT);
} }
else else
{ {
allocationSize = allocator->nextAllocationSize; allocationSize = SMALL_ALLOCATION_SIZE;
} }
allocationResult = VULKAN_INTERNAL_AllocateMemory( allocationResult = VULKAN_INTERNAL_AllocateMemory(
@ -11543,7 +11568,6 @@ static Refresh_Device* VULKAN_CreateDevice(
for (i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) for (i = 0; i < VK_MAX_MEMORY_TYPES; i += 1)
{ {
renderer->memoryAllocator->subAllocators[i].memoryTypeIndex = i; renderer->memoryAllocator->subAllocators[i].memoryTypeIndex = i;
renderer->memoryAllocator->subAllocators[i].nextAllocationSize = STARTING_ALLOCATION_SIZE;
renderer->memoryAllocator->subAllocators[i].allocations = NULL; renderer->memoryAllocator->subAllocators[i].allocations = NULL;
renderer->memoryAllocator->subAllocators[i].allocationCount = 0; renderer->memoryAllocator->subAllocators[i].allocationCount = 0;
renderer->memoryAllocator->subAllocators[i].sortedFreeRegions = SDL_malloc( renderer->memoryAllocator->subAllocators[i].sortedFreeRegions = SDL_malloc(