From 1bcd0bd93048ed472ba12918a34d9e1d7f26bba2 Mon Sep 17 00:00:00 2001 From: "Pierre-Loup A. Griffais" Date: Mon, 27 Jan 2020 22:46:38 -0800 Subject: [PATCH] Vulkan: fix a nasty race. We could garbage-collect fences before/during their wait. --- src/rendervulkan.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp index 707607f..33b86f6 100644 --- a/src/rendervulkan.cpp +++ b/src/rendervulkan.cpp @@ -83,6 +83,7 @@ struct scratchCmdBuffer_t std::vector refs; + std::atomic haswaiter; std::atomic busy; }; @@ -1082,14 +1083,17 @@ int vulkan_init(void) return 1; } -static inline uint32_t get_command_buffer( VkCommandBuffer &cmdBuf, VkFence &fence ) +static inline uint32_t get_command_buffer( VkCommandBuffer &cmdBuf, VkFence *pFence ) { for ( uint32_t i = 0; i < k_nScratchCmdBufferCount; i++ ) { if ( g_scratchCommandBuffers[ i ].busy == false ) { cmdBuf = g_scratchCommandBuffers[ i ].cmdBuf; - fence = g_scratchCommandBuffers[ i ].fence; + if ( pFence != nullptr ) + { + *pFence = g_scratchCommandBuffers[ i ].fence; + } VkCommandBufferBeginInfo commandBufferBeginInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, @@ -1105,6 +1109,8 @@ static inline uint32_t get_command_buffer( VkCommandBuffer &cmdBuf, VkFence &fen g_scratchCommandBuffers[ i ].refs.clear(); + g_scratchCommandBuffers[ i ].haswaiter = pFence != nullptr; + g_scratchCommandBuffers[ i ].busy = true; return i; @@ -1153,7 +1159,8 @@ void vulkan_garbage_collect( void ) // Probably just differentiate "busy" and "submitted" for ( uint32_t i = 0; i < k_nScratchCmdBufferCount; i++ ) { - if ( g_scratchCommandBuffers[ i ].busy == true ) + if ( g_scratchCommandBuffers[ i ].busy == true && + g_scratchCommandBuffers[ i ].haswaiter == false ) { VkResult res = vkGetFenceStatus( device, g_scratchCommandBuffers[ i ].fence ); @@ -1215,8 +1222,7 @@ VulkanTexture_t vulkan_create_texture_from_bits( uint32_t width, uint32_t height memcpy( pUploadBuffer, bits, width * height * 4 ); VkCommandBuffer commandBuffer; - VkFence fence; - uint32_t handle = get_command_buffer( commandBuffer, fence ); + uint32_t handle = get_command_buffer( commandBuffer, nullptr ); VkBufferImageCopy region = {}; @@ -1612,7 +1618,7 @@ uint32_t vulkan_get_texture_fence( VulkanTexture_t vulkanTex ) VkCommandBuffer commandBuffer; VkFence fence; - uint32_t handle = get_command_buffer( commandBuffer, fence ); + uint32_t handle = get_command_buffer( commandBuffer, &fence ); VkBufferImageCopy region = {}; @@ -1639,7 +1645,11 @@ uint32_t vulkan_get_texture_fence( VulkanTexture_t vulkanTex ) void vulkan_wait_for_fence( uint32_t handle ) { + assert( g_scratchCommandBuffers[ handle ].busy == true && + g_scratchCommandBuffers[ handle ].haswaiter == true ); vkWaitForFences( device, 1, &g_scratchCommandBuffers[ handle ].fence, VK_TRUE, ~0 ); + + g_scratchCommandBuffers[ handle ].haswaiter = false; }