From 74c5ac984c1b2f246f6bdb8ff2783d626c021933 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Sun, 6 Mar 2022 22:20:06 -0800 Subject: [PATCH] swapchain recreate timing fix --- include/Refresh.h | 1 + src/Refresh_Driver_Vulkan.c | 261 ++++++++++++++++++------------------ 2 files changed, 134 insertions(+), 128 deletions(-) diff --git a/include/Refresh.h b/include/Refresh.h index e5640b4..ca70429 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -988,6 +988,7 @@ REFRESHAPI void Refresh_QueueDestroyGraphicsPipeline( * The area affected by the render pass. * All load, store and resolve operations are restricted * to the given rectangle. + * If NULL, a sensible default will be chosen. * colorAttachmentInfos: * A pointer to an array of Refresh_ColorAttachmentInfo structures * that contains render targets and clear values. May be NULL. diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index 0e2d247..14242fe 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -169,13 +169,6 @@ typedef enum VulkanResourceAccessType RESOURCE_ACCESS_TYPES_COUNT } VulkanResourceAccessType; -typedef enum CreateSwapchainResult -{ - CREATE_SWAPCHAIN_FAIL, - CREATE_SWAPCHAIN_SUCCESS, - CREATE_SWAPCHAIN_SURFACE_ZERO, -} CreateSwapchainResult; - /* Conversions */ static const uint8_t DEVICE_PRIORITY[] = @@ -4095,7 +4088,7 @@ static uint8_t VULKAN_INTERNAL_ChooseSwapPresentMode( return 1; } -static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( +static uint8_t VULKAN_INTERNAL_CreateSwapchain( VulkanRenderer *renderer, void *windowHandle ) { @@ -4124,7 +4117,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( "SDL_Vulkan_CreateSurface failed: %s", SDL_GetError() ); - return CREATE_SWAPCHAIN_FAIL; + return 0; } if (!VULKAN_INTERNAL_QuerySwapChainSupport( @@ -4149,7 +4142,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( } SDL_free(swapchainData); Refresh_LogError("Device does not support swap chain creation"); - return CREATE_SWAPCHAIN_FAIL; + return 0; } swapchainData->swapchainFormat = VK_FORMAT_R8G8B8A8_UNORM; @@ -4191,7 +4184,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( } SDL_free(swapchainData); Refresh_LogError("Device does not support swap chain format"); - return CREATE_SWAPCHAIN_FAIL; + return 0; } } @@ -4216,7 +4209,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( } SDL_free(swapchainData); Refresh_LogError("Device does not support swap chain present mode"); - return CREATE_SWAPCHAIN_FAIL; + return 0; } SDL_Vulkan_GetDrawableSize( @@ -4247,7 +4240,8 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( SDL_free(swapchainSupportDetails.presentModes); } SDL_free(swapchainData); - return CREATE_SWAPCHAIN_SURFACE_ZERO; + /* Not an error, just Windows minimize behavior! */ + return 0; } if (swapchainSupportDetails.capabilities.currentExtent.width != UINT32_MAX) @@ -4280,7 +4274,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( } SDL_free(swapchainData); Refresh_LogError("No fallback swapchain size available!"); - return CREATE_SWAPCHAIN_FAIL; + return 0; } } @@ -4353,7 +4347,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( ); SDL_free(swapchainData); LogVulkanResultAsError("vkCreateSwapchainKHR", vulkanResult); - return CREATE_SWAPCHAIN_FAIL; + return 0; } renderer->vkGetSwapchainImagesKHR( @@ -4376,7 +4370,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( NULL ); SDL_free(swapchainData); - return CREATE_SWAPCHAIN_FAIL; + return 0; } swapchainImages = SDL_stack_alloc(VkImage, swapchainData->imageCount); @@ -4424,7 +4418,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( SDL_free(swapchainData->textures); SDL_free(swapchainData); LogVulkanResultAsError("vkCreateImageView", vulkanResult); - return CREATE_SWAPCHAIN_FAIL; + return 0; } swapchainData->textures[i].resourceAccessType = RESOURCE_ACCESS_NONE; @@ -4480,26 +4474,16 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( renderer->swapchainDatas[renderer->swapchainDataCount] = swapchainData; renderer->swapchainDataCount += 1; - return CREATE_SWAPCHAIN_SUCCESS; + return 1; } static void VULKAN_INTERNAL_RecreateSwapchain( VulkanRenderer* renderer, void *windowHandle ) { - CreateSwapchainResult createSwapchainResult; - - VULKAN_Wait((Refresh_Renderer*)renderer); - + VULKAN_Wait((Refresh_Renderer*) renderer); VULKAN_INTERNAL_DestroySwapchain(renderer, windowHandle); - createSwapchainResult = VULKAN_INTERNAL_CreateSwapchain(renderer, windowHandle); - - if (createSwapchainResult == CREATE_SWAPCHAIN_FAIL) - { - return; - } - - VULKAN_Wait((Refresh_Renderer*)renderer); + VULKAN_INTERNAL_CreateSwapchain(renderer, windowHandle); } /* Command Buffers */ @@ -8233,13 +8217,24 @@ static void VULKAN_BeginRenderPass( renderPassBeginInfo.pNext = NULL; renderPassBeginInfo.renderPass = renderPass; renderPassBeginInfo.framebuffer = framebuffer->framebuffer; - renderPassBeginInfo.renderArea.extent.width = renderArea->w; - renderPassBeginInfo.renderArea.extent.height = renderArea->h; - renderPassBeginInfo.renderArea.offset.x = renderArea->x; - renderPassBeginInfo.renderArea.offset.y = renderArea->y; renderPassBeginInfo.pClearValues = clearValues; renderPassBeginInfo.clearValueCount = clearCount; + if (renderArea != NULL) + { + renderPassBeginInfo.renderArea.extent.width = renderArea->w; + renderPassBeginInfo.renderArea.extent.height = renderArea->h; + renderPassBeginInfo.renderArea.offset.x = renderArea->x; + renderPassBeginInfo.renderArea.offset.y = renderArea->y; + } + else + { + renderPassBeginInfo.renderArea.extent.width = framebufferWidth; + renderPassBeginInfo.renderArea.extent.height = framebufferHeight; + renderPassBeginInfo.renderArea.offset.x = 0; + renderPassBeginInfo.renderArea.offset.y = 0; + } + renderer->vkCmdBeginRenderPass( vulkanCommandBuffer->commandBuffer, &renderPassBeginInfo, @@ -8935,6 +8930,25 @@ static Refresh_CommandBuffer* VULKAN_AcquireCommandBuffer( return (Refresh_CommandBuffer*) commandBuffer; } +static VulkanSwapchainData* VULKAN_INTERNAL_FetchSwapchainData( + VulkanRenderer *renderer, + void *windowHandle +) { + VulkanSwapchainData *swapchainData = NULL; + + swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); + + if (swapchainData == NULL) + { + if (VULKAN_INTERNAL_CreateSwapchain(renderer, windowHandle)) + { + swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); + } + } + + return swapchainData; +} + static Refresh_Texture* VULKAN_AcquireSwapchainTexture( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, @@ -8943,35 +8957,39 @@ static Refresh_Texture* VULKAN_AcquireSwapchainTexture( VulkanRenderer *renderer = (VulkanRenderer*) driverData; VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; uint32_t swapchainImageIndex; - VulkanSwapchainData *swapchainData = NULL; - CreateSwapchainResult createSwapchainResult = 0; - uint8_t validSwapchainExists = 1; + VulkanSwapchainData *swapchainData; VkResult acquireResult = VK_SUCCESS; VulkanTexture *swapchainTexture = NULL; VulkanPresentData *presentData; - swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); + swapchainData = VULKAN_INTERNAL_FetchSwapchainData(renderer, windowHandle); if (swapchainData == NULL) { - createSwapchainResult = VULKAN_INTERNAL_CreateSwapchain(renderer, windowHandle); - - if (createSwapchainResult == CREATE_SWAPCHAIN_FAIL) - { - validSwapchainExists = 0; - } - else if (createSwapchainResult == CREATE_SWAPCHAIN_SURFACE_ZERO) - { - validSwapchainExists = 0; - } - else - { - swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); - } + return NULL; } - if (validSwapchainExists) + acquireResult = renderer->vkAcquireNextImageKHR( + renderer->logicalDevice, + swapchainData->swapchain, + UINT64_MAX, + swapchainData->imageAvailableSemaphore, + VK_NULL_HANDLE, + &swapchainImageIndex + ); + + /* Swapchain is suboptimal, let's try to recreate */ + if (acquireResult == VK_SUBOPTIMAL_KHR) { + VULKAN_INTERNAL_RecreateSwapchain(renderer, windowHandle); + + swapchainData = VULKAN_INTERNAL_FetchSwapchainData(renderer, windowHandle); + + if (swapchainData == NULL) + { + return NULL; + } + acquireResult = renderer->vkAcquireNextImageKHR( renderer->logicalDevice, swapchainData->swapchain, @@ -8981,84 +8999,71 @@ static Refresh_Texture* VULKAN_AcquireSwapchainTexture( &swapchainImageIndex ); - /* Swapchain is suboptimal, let's try to recreate */ - if (acquireResult == VK_SUBOPTIMAL_KHR) + if (acquireResult != VK_SUCCESS) { - VULKAN_INTERNAL_RecreateSwapchain(renderer, windowHandle); - - acquireResult = renderer->vkAcquireNextImageKHR( - renderer->logicalDevice, - swapchainData->swapchain, - UINT64_MAX, - swapchainData->imageAvailableSemaphore, - VK_NULL_HANDLE, - &swapchainImageIndex - ); - } - - if (acquireResult == VK_SUCCESS) - { - swapchainTexture = &swapchainData->textures[swapchainImageIndex]; - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - vulkanCommandBuffer->commandBuffer, - RESOURCE_ACCESS_COLOR_ATTACHMENT_WRITE, - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - 0, - swapchainTexture->image, - &swapchainTexture->resourceAccessType - ); - - /* Set up present struct */ - - if (vulkanCommandBuffer->presentDataCount == vulkanCommandBuffer->presentDataCapacity) - { - vulkanCommandBuffer->presentDataCapacity += 1; - vulkanCommandBuffer->presentDatas = SDL_realloc( - vulkanCommandBuffer->presentDatas, - vulkanCommandBuffer->presentDataCapacity * sizeof(VkPresentInfoKHR) - ); - } - - presentData = &vulkanCommandBuffer->presentDatas[vulkanCommandBuffer->presentDataCount]; - vulkanCommandBuffer->presentDataCount += 1; - - presentData->swapchainData = swapchainData; - presentData->swapchainImageIndex = swapchainImageIndex; - - /* Set up present semaphores */ - - if (vulkanCommandBuffer->waitSemaphoreCount == vulkanCommandBuffer->waitSemaphoreCapacity) - { - vulkanCommandBuffer->waitSemaphoreCapacity += 1; - vulkanCommandBuffer->waitSemaphores = SDL_realloc( - vulkanCommandBuffer->waitSemaphores, - vulkanCommandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore) - ); - } - - vulkanCommandBuffer->waitSemaphores[vulkanCommandBuffer->waitSemaphoreCount] = swapchainData->imageAvailableSemaphore; - vulkanCommandBuffer->waitSemaphoreCount += 1; - - if (vulkanCommandBuffer->signalSemaphoreCount == vulkanCommandBuffer->signalSemaphoreCapacity) - { - vulkanCommandBuffer->signalSemaphoreCapacity += 1; - vulkanCommandBuffer->signalSemaphores = SDL_realloc( - vulkanCommandBuffer->signalSemaphores, - vulkanCommandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore) - ); - } - - vulkanCommandBuffer->signalSemaphores[vulkanCommandBuffer->signalSemaphoreCount] = swapchainData->renderFinishedSemaphore; - vulkanCommandBuffer->signalSemaphoreCount += 1; + return NULL; } } + swapchainTexture = &swapchainData->textures[swapchainImageIndex]; + + VULKAN_INTERNAL_ImageMemoryBarrier( + renderer, + vulkanCommandBuffer->commandBuffer, + RESOURCE_ACCESS_COLOR_ATTACHMENT_WRITE, + VK_IMAGE_ASPECT_COLOR_BIT, + 0, + 1, + 0, + 1, + 0, + swapchainTexture->image, + &swapchainTexture->resourceAccessType + ); + + /* Set up present struct */ + + if (vulkanCommandBuffer->presentDataCount == vulkanCommandBuffer->presentDataCapacity) + { + vulkanCommandBuffer->presentDataCapacity += 1; + vulkanCommandBuffer->presentDatas = SDL_realloc( + vulkanCommandBuffer->presentDatas, + vulkanCommandBuffer->presentDataCapacity * sizeof(VkPresentInfoKHR) + ); + } + + presentData = &vulkanCommandBuffer->presentDatas[vulkanCommandBuffer->presentDataCount]; + vulkanCommandBuffer->presentDataCount += 1; + + presentData->swapchainData = swapchainData; + presentData->swapchainImageIndex = swapchainImageIndex; + + /* Set up present semaphores */ + + if (vulkanCommandBuffer->waitSemaphoreCount == vulkanCommandBuffer->waitSemaphoreCapacity) + { + vulkanCommandBuffer->waitSemaphoreCapacity += 1; + vulkanCommandBuffer->waitSemaphores = SDL_realloc( + vulkanCommandBuffer->waitSemaphores, + vulkanCommandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore) + ); + } + + vulkanCommandBuffer->waitSemaphores[vulkanCommandBuffer->waitSemaphoreCount] = swapchainData->imageAvailableSemaphore; + vulkanCommandBuffer->waitSemaphoreCount += 1; + + if (vulkanCommandBuffer->signalSemaphoreCount == vulkanCommandBuffer->signalSemaphoreCapacity) + { + vulkanCommandBuffer->signalSemaphoreCapacity += 1; + vulkanCommandBuffer->signalSemaphores = SDL_realloc( + vulkanCommandBuffer->signalSemaphores, + vulkanCommandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore) + ); + } + + vulkanCommandBuffer->signalSemaphores[vulkanCommandBuffer->signalSemaphoreCount] = swapchainData->renderFinishedSemaphore; + vulkanCommandBuffer->signalSemaphoreCount += 1; + return (Refresh_Texture*) swapchainTexture; } @@ -10337,7 +10342,7 @@ static Refresh_Device* VULKAN_CreateDevice( renderer->swapchainDataCapacity * sizeof(VulkanSwapchainData*) ); - if (VULKAN_INTERNAL_CreateSwapchain(renderer, presentationParameters->deviceWindowHandle) != CREATE_SWAPCHAIN_SUCCESS) + if (!VULKAN_INTERNAL_CreateSwapchain(renderer, presentationParameters->deviceWindowHandle)) { Refresh_LogError("Failed to create swapchain"); return NULL;