diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index d1a0fee..fb81d56 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -75,6 +75,7 @@ static uint32_t deviceExtensionCount = SDL_arraysize(deviceExtensionNames); #define MAX_ALLOCATION_SIZE 256000000 /* 256MB */ #define ALLOCATION_INCREMENT 16000000 /* 16MB */ #define TRANSFER_BUFFER_STARTING_SIZE 8000000 /* 8MB */ +#define POOLED_TRANSFER_BUFFER_SIZE 16000000 /* 16MB */ #define UBO_BUFFER_SIZE 16000 /* 16KB */ #define DESCRIPTOR_POOL_STARTING_SIZE 128 #define WINDOW_DATA "Refresh_VulkanWindowData" @@ -1516,8 +1517,18 @@ typedef struct VulkanTransferBuffer { VulkanBuffer* buffer; VkDeviceSize offset; + uint8_t fromPool; } VulkanTransferBuffer; +typedef struct VulkanTransferBufferPool +{ + SDL_mutex *lock; + + VulkanTransferBuffer **availableBuffers; + uint32_t availableBufferCount; + uint32_t availableBufferCapacity; +} VulkanTransferBufferPool; + typedef struct VulkanCommandPool VulkanCommandPool; typedef struct VulkanCommandBuffer @@ -1723,6 +1734,8 @@ typedef struct VulkanRenderer uint32_t submittedCommandBufferCount; uint32_t submittedCommandBufferCapacity; + VulkanTransferBufferPool transferBufferPool; + CommandPoolHashTable commandPoolHashTable; DescriptorSetLayoutHashTable descriptorSetLayoutHashTable; GraphicsPipelineLayoutHashTable graphicsPipelineLayoutHashTable; @@ -5151,6 +5164,15 @@ static void VULKAN_DestroyDevice( SDL_free(renderer->dummyFragmentUniformBuffer); SDL_free(renderer->dummyComputeUniformBuffer); + for (i = 0; i < renderer->transferBufferPool.availableBufferCount; i += 1) + { + VULKAN_INTERNAL_DestroyBuffer(renderer, renderer->transferBufferPool.availableBuffers[i]->buffer); + SDL_free(renderer->transferBufferPool.availableBuffers[i]); + } + + SDL_free(renderer->transferBufferPool.availableBuffers); + SDL_DestroyMutex(renderer->transferBufferPool.lock); + for (i = 0; i < NUM_COMMAND_POOL_BUCKETS; i += 1) { commandPoolHashArray = renderer->commandPoolHashTable.buckets[i]; @@ -7099,6 +7121,40 @@ static VulkanTransferBuffer* VULKAN_INTERNAL_AcquireTransferBuffer( } } + /* Nothing fits, can we get a transfer buffer from the pool? */ + + SDL_LockMutex(renderer->transferBufferPool.lock); + + for (i = 0; i < renderer->transferBufferPool.availableBufferCount; i += 1) + { + transferBuffer = renderer->transferBufferPool.availableBuffers[i]; + offset = transferBuffer->offset + alignment - (transferBuffer->offset % alignment); + + if (offset + requiredSize <= transferBuffer->buffer->size) + { + if (commandBuffer->transferBufferCount == commandBuffer->transferBufferCapacity) + { + commandBuffer->transferBufferCapacity *= 2; + commandBuffer->transferBuffers = SDL_realloc( + commandBuffer->transferBuffers, + commandBuffer->transferBufferCapacity * sizeof(VulkanTransferBuffer*) + ); + } + + commandBuffer->transferBuffers[commandBuffer->transferBufferCount] = transferBuffer; + commandBuffer->transferBufferCount += 1; + + renderer->transferBufferPool.availableBuffers[i] = renderer->transferBufferPool.availableBuffers[renderer->transferBufferPool.availableBufferCount - 1]; + renderer->transferBufferPool.availableBufferCount -= 1; + SDL_UnlockMutex(renderer->transferBufferPool.lock); + + transferBuffer->offset = offset; + return transferBuffer; + } + } + + SDL_UnlockMutex(renderer->transferBufferPool.lock); + /* Nothing fits, so let's create a new transfer buffer */ size = TRANSFER_BUFFER_STARTING_SIZE; @@ -7118,10 +7174,12 @@ static VulkanTransferBuffer* VULKAN_INTERNAL_AcquireTransferBuffer( 1, 1 ); + transferBuffer->fromPool = 0; if (transferBuffer->buffer == NULL) { Refresh_LogError("Failed to allocate transfer buffer!"); + SDL_free(transferBuffer); return NULL; } @@ -10040,9 +10098,22 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( for (i = 0; i < commandBuffer->transferBufferCount; i += 1) { - VULKAN_INTERNAL_QueueDestroyBuffer(renderer, commandBuffer->transferBuffers[i]->buffer); - SDL_free(commandBuffer->transferBuffers[i]); - commandBuffer->transferBuffers[i] = NULL; + if (commandBuffer->transferBuffers[i]->fromPool) + { + SDL_LockMutex(renderer->transferBufferPool.lock); + + commandBuffer->transferBuffers[i]->offset = 0; + renderer->transferBufferPool.availableBuffers[renderer->transferBufferPool.availableBufferCount] = commandBuffer->transferBuffers[i]; + renderer->transferBufferPool.availableBufferCount += 1; + + SDL_UnlockMutex(renderer->transferBufferPool.lock); + } + else + { + VULKAN_INTERNAL_QueueDestroyBuffer(renderer, commandBuffer->transferBuffers[i]->buffer); + SDL_free(commandBuffer->transferBuffers[i]); + commandBuffer->transferBuffers[i] = NULL; + } } commandBuffer->transferBufferCount = 0; @@ -11392,6 +11463,9 @@ static Refresh_Device* VULKAN_CreateDevice( /* Variables: Image Format Detection */ VkImageFormatProperties imageFormatProperties; + /* Variables: Transfer buffer init */ + VulkanTransferBuffer *transferBuffer; + SDL_memset(renderer, '\0', sizeof(VulkanRenderer)); renderer->debugMode = debugMode; @@ -11774,6 +11848,40 @@ static Refresh_Device* VULKAN_CreateDevice( renderer->renderTargetHashArray.count = 0; renderer->renderTargetHashArray.capacity = 0; + /* Initialize transfer buffer pool */ + + renderer->transferBufferPool.lock = SDL_CreateMutex(); + + renderer->transferBufferPool.availableBufferCapacity = 4; + renderer->transferBufferPool.availableBufferCount = 0; + renderer->transferBufferPool.availableBuffers = SDL_malloc( + renderer->transferBufferPool.availableBufferCapacity * sizeof(VulkanTransferBuffer*) + ); + + for (i = 0; i < renderer->transferBufferPool.availableBufferCapacity; i += 1) + { + transferBuffer = SDL_malloc(sizeof(VulkanTransferBuffer)); + transferBuffer->offset = 0; + transferBuffer->fromPool = 1; + transferBuffer->buffer = VULKAN_INTERNAL_CreateBuffer( + renderer, + POOLED_TRANSFER_BUFFER_SIZE, + RESOURCE_ACCESS_TRANSFER_READ_WRITE, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + 1, + 1 + ); + + if (transferBuffer->buffer == NULL) + { + Refresh_LogError("Failed to allocate transfer buffer!"); + SDL_free(transferBuffer); + } + + renderer->transferBufferPool.availableBuffers[i] = transferBuffer; + renderer->transferBufferPool.availableBufferCount += 1; + } + /* Some drivers don't support D16, so we have to fall back to D32. */ vulkanResult = renderer->vkGetPhysicalDeviceImageFormatProperties(