diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index d3bc073..34e4564 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -1352,11 +1352,18 @@ typedef struct VulkanRenderer VkQueue computeQueue; VkQueue transferQueue; - VkFence inFlightFence; VkSemaphore transferFinishedSemaphore; VkSemaphore imageAvailableSemaphore; VkSemaphore renderFinishedSemaphore; + VkFence *availableFences; + uint32_t availableFenceCount; + uint32_t availableFenceCapacity; + + VkFence *usedFences; + uint32_t usedFenceCount; + uint32_t usedFenceCapacity; + VulkanCommandBuffer **submittedCommandBuffers; uint32_t submittedCommandBufferCount; uint32_t submittedCommandBufferCapacity; @@ -1403,6 +1410,7 @@ typedef struct VulkanRenderer SDL_mutex *allocatorLock; SDL_mutex *disposeLock; SDL_mutex *boundBufferLock; + SDL_mutex *submitLock; /* Deferred destroy storage */ @@ -4522,11 +4530,23 @@ static void VULKAN_DestroyDevice( NULL ); - renderer->vkDestroyFence( - renderer->logicalDevice, - renderer->inFlightFence, - NULL - ); + for (i = 0; i < renderer->availableFenceCount; i += 1) + { + renderer->vkDestroyFence( + renderer->logicalDevice, + renderer->availableFences[i], + NULL + ); + } + + for (i = 0; i < renderer->usedFenceCount; i += 1) + { + renderer->vkDestroyFence( + renderer->logicalDevice, + renderer->usedFences[i], + NULL + ); + } for (i = 0; i < NUM_COMMAND_POOL_BUCKETS; i += 1) { @@ -4707,6 +4727,7 @@ static void VULKAN_DestroyDevice( SDL_DestroyMutex(renderer->allocatorLock); SDL_DestroyMutex(renderer->disposeLock); SDL_DestroyMutex(renderer->boundBufferLock); + SDL_DestroyMutex(renderer->submitLock); SDL_free(renderer->buffersInUse); @@ -8436,6 +8457,103 @@ static void VULKAN_INTERNAL_ResetCommandBuffer( commandPool->inactiveCommandBufferCount += 1; } +/* Fence management */ + +static VkFence VULKAN_INTERNAL_AcquireFence( + VulkanRenderer *renderer +) { + VkFenceCreateInfo fenceCreateInfo; + VkFence fence; + VkResult fenceCreateResult; + + if (renderer->availableFenceCount == 0) + { + fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceCreateInfo.pNext = NULL; + fenceCreateInfo.flags = 0; + + fenceCreateResult = renderer->vkCreateFence( + renderer->logicalDevice, + &fenceCreateInfo, + NULL, + &renderer->availableFences[0] + ); + + if (fenceCreateResult != VK_SUCCESS) + { + LogVulkanResultAsError("vkCreateFence", fenceCreateResult); + return VK_NULL_HANDLE; + } + + renderer->availableFenceCount += 1; + } + + fence = renderer->availableFences[renderer->availableFenceCount - 1]; + renderer->availableFenceCount -= 1; + + if (renderer->usedFenceCount >= renderer->usedFenceCapacity) + { + renderer->usedFenceCapacity *= 2; + renderer->usedFences = SDL_realloc( + renderer->usedFences, + renderer->usedFenceCapacity * sizeof(VkFence) + ); + } + + renderer->usedFences[renderer->usedFenceCount] = fence; + renderer->usedFenceCount += 1; + + return fence; +} + +static void VULKAN_INTERNAL_ResetUsedFences( + VulkanRenderer *renderer +) { + uint32_t i; + + /* Prepare the command buffer fence for submission */ + renderer->vkResetFences( + renderer->logicalDevice, + renderer->usedFenceCount, + renderer->usedFences + ); + + /* Used fences are now available */ + if (renderer->usedFenceCount + renderer->availableFenceCount >= renderer->availableFenceCapacity) + { + renderer->availableFenceCapacity = renderer->usedFenceCount + renderer->availableFenceCount; + renderer->availableFences = SDL_realloc( + renderer->availableFences, + renderer->availableFenceCapacity * sizeof(VkFence) + ); + } + + for (i = 0; i < renderer->usedFenceCount; i += 1) + { + renderer->availableFences[renderer->availableFenceCount] = renderer->usedFences[i]; + renderer->availableFenceCount += 1; + } + renderer->usedFenceCount = 0; +} + +/* Submission structure */ + +static void VULKAN_Wait( + Refresh_Renderer *driverData +) { + VulkanRenderer *renderer = (VulkanRenderer*) driverData; + + renderer->vkWaitForFences( + renderer->logicalDevice, + renderer->usedFenceCount, + renderer->usedFences, + VK_TRUE, + UINT64_MAX + ); + + VULKAN_INTERNAL_ResetUsedFences(renderer); +} + static void VULKAN_Submit( Refresh_Renderer *driverData, uint32_t commandBufferCount, @@ -8448,12 +8566,15 @@ static void VULKAN_Submit( VkCommandBuffer *commandBuffers; uint32_t i; uint8_t present = 0; + VkFence fence; VkPipelineStageFlags waitStages[2]; VkSemaphore waitSemaphores[2]; uint32_t waitSemaphoreCount = 0; VkPresentInfoKHR presentInfo; + SDL_LockMutex(renderer->submitLock); + commandBuffers = SDL_stack_alloc(VkCommandBuffer, commandBufferCount); for (i = 0; i < commandBufferCount; i += 1) @@ -8496,8 +8617,8 @@ static void VULKAN_Submit( /* Wait for the previous submission to complete */ vulkanResult = renderer->vkWaitForFences( renderer->logicalDevice, - 1, - &renderer->inFlightFence, + renderer->usedFenceCount, + renderer->usedFences, VK_TRUE, UINT64_MAX ); @@ -8523,12 +8644,16 @@ static void VULKAN_Submit( } renderer->submittedCommandBufferCount = 0; - /* Prepare the command buffer fence for submission */ - renderer->vkResetFences( - renderer->logicalDevice, - 1, - &renderer->inFlightFence - ); + VULKAN_INTERNAL_ResetUsedFences(renderer); + } + + /* Acquire a fence */ + fence = VULKAN_INTERNAL_AcquireFence(renderer); + + if (fence == VK_NULL_HANDLE) + { + Refresh_LogError("Failed to acquire fence!"); + return; } /* Submit the commands, finally. */ @@ -8536,7 +8661,7 @@ static void VULKAN_Submit( renderer->graphicsQueue, 1, &submitInfo, - present ? renderer->inFlightFence : VK_NULL_HANDLE + fence ); if (vulkanResult != VK_SUCCESS) @@ -8590,20 +8715,8 @@ static void VULKAN_Submit( renderer->swapChainImageAcquired = 0; SDL_stack_free(commandBuffers); -} -static void VULKAN_Wait( - Refresh_Renderer *driverData -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - - renderer->vkWaitForFences( - renderer->logicalDevice, - 1, - &renderer->inFlightFence, - VK_TRUE, - UINT64_MAX - ); + SDL_UnlockMutex(renderer->submitLock); } /* External interop */ @@ -9291,8 +9404,7 @@ static Refresh_Device* VULKAN_INTERNAL_CreateDevice( VkResult vulkanResult; uint32_t i; - /* Variables: Create fence and semaphores */ - VkFenceCreateInfo fenceInfo; + /* Variables: Create semaphores */ VkSemaphoreCreateInfo semaphoreInfo; /* Variables: Descriptor set layouts */ @@ -9333,13 +9445,9 @@ static Refresh_Device* VULKAN_INTERNAL_CreateDevice( renderer->swapChainImageAcquired = 0; /* - * Create fence and semaphores + * Create semaphores */ - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.pNext = NULL; - fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphoreInfo.pNext = NULL; semaphoreInfo.flags = 0; @@ -9383,24 +9491,22 @@ static Refresh_Device* VULKAN_INTERNAL_CreateDevice( return NULL; } - vulkanResult = renderer->vkCreateFence( - renderer->logicalDevice, - &fenceInfo, - NULL, - &renderer->inFlightFence - ); - - if (vulkanResult != VK_SUCCESS) - { - LogVulkanResultAsError("vkCreateFence", vulkanResult); - return NULL; - } - /* Threading */ renderer->allocatorLock = SDL_CreateMutex(); renderer->disposeLock = SDL_CreateMutex(); renderer->boundBufferLock = SDL_CreateMutex(); + renderer->submitLock = SDL_CreateMutex(); + + /* Create fence lists */ + + renderer->availableFenceCount = 0; + renderer->availableFenceCapacity = 4; + renderer->availableFences = SDL_malloc(renderer->availableFenceCapacity * sizeof(VkFence)); + + renderer->usedFenceCount = 0; + renderer->usedFenceCapacity = 4; + renderer->usedFences = SDL_malloc(renderer->usedFenceCapacity * sizeof(VkFence)); /* * Create submitted command buffer list