From 3a94a276da506757b8aa178b5529ac271ada0023 Mon Sep 17 00:00:00 2001 From: goeiecool9999 <7033575+goeiecool9999@users.noreply.github.com> Date: Mon, 21 Nov 2022 16:47:43 +0100 Subject: [PATCH] Vulkan: Further simplify swapchain code (#502) --- .../Latte/Renderer/Vulkan/SwapchainInfoVk.cpp | 32 ++++------ .../Latte/Renderer/Vulkan/SwapchainInfoVk.h | 5 +- .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 62 +++---------------- 3 files changed, 24 insertions(+), 75 deletions(-) diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp index 8d96acd0..d6d0d1a6 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp @@ -13,10 +13,7 @@ void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDe m_surfaceFormat = ChooseSurfaceFormat(details.formats); m_actualExtent = ChooseSwapExtent(details.capabilities); - // calculate number of swapchain presentation images - uint32_t image_count = details.capabilities.minImageCount + 1; - if (details.capabilities.maxImageCount > 0 && image_count > details.capabilities.maxImageCount) - image_count = details.capabilities.maxImageCount; + uint32_t image_count = details.capabilities.minImageCount; VkSwapchainCreateInfoKHR create_info = CreateSwapchainCreateInfo(surface, details, m_surfaceFormat, image_count, m_actualExtent); create_info.oldSwapchain = nullptr; @@ -115,22 +112,14 @@ void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDe UnrecoverableError("Failed to create semaphore for swapchain present"); } - m_acquireSemaphores.resize(m_swapchainImages.size()); - for (auto& semaphore : m_acquireSemaphores) - { - VkSemaphoreCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - if (vkCreateSemaphore(logicalDevice, &info, nullptr, &semaphore) != VK_SUCCESS) - UnrecoverableError("Failed to create semaphore for swapchain acquire"); - } - m_acquireIndex = 0; - VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; result = vkCreateFence(logicalDevice, &fenceInfo, nullptr, &m_imageAvailableFence); if (result != VK_SUCCESS) UnrecoverableError("Failed to create fence for swapchain"); + + hasDefinedSwapchainImage = false; } void SwapchainInfoVk::Cleanup() @@ -141,10 +130,6 @@ void SwapchainInfoVk::Cleanup() vkDestroySemaphore(m_logicalDevice, sem, nullptr); m_swapchainPresentSemaphores.clear(); - for (auto& itr: m_acquireSemaphores) - vkDestroySemaphore(m_logicalDevice, itr, nullptr); - m_acquireSemaphores.clear(); - if (m_swapchainRenderPass) { vkDestroyRenderPass(m_logicalDevice, m_swapchainRenderPass, nullptr); @@ -177,6 +162,11 @@ bool SwapchainInfoVk::IsValid() const return swapchain && m_imageAvailableFence; } +void SwapchainInfoVk::WaitAvailableFence() const +{ + vkWaitForFences(m_logicalDevice, 1, &m_imageAvailableFence, VK_TRUE, UINT64_MAX); +} + void SwapchainInfoVk::UnrecoverableError(const char* errMsg) { forceLog_printf("Unrecoverable error in Vulkan swapchain"); @@ -345,12 +335,12 @@ VkSwapchainCreateInfoKHR SwapchainInfoVk::CreateSwapchainCreateInfo(VkSurfaceKHR createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; const QueueFamilyIndices indices = FindQueueFamilies(surface, m_physicalDevice); - uint32_t queueFamilyIndices[] = { (uint32)indices.graphicsFamily, (uint32)indices.presentFamily }; + m_swapchainQueueFamilyIndices = { (uint32)indices.graphicsFamily, (uint32)indices.presentFamily }; if (indices.graphicsFamily != indices.presentFamily) { createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - createInfo.queueFamilyIndexCount = 2; - createInfo.pQueueFamilyIndices = queueFamilyIndices; + createInfo.queueFamilyIndexCount = m_swapchainQueueFamilyIndices.size(); + createInfo.pQueueFamilyIndices = m_swapchainQueueFamilyIndices.data(); } else createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h index 06add21a..d2d5d23e 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h @@ -34,6 +34,8 @@ struct SwapchainInfoVk bool IsValid() const; + void WaitAvailableFence() const; + static void UnrecoverableError(const char* errMsg); // todo: move this function somewhere more sensible. Not directly swapchain related @@ -76,7 +78,6 @@ struct SwapchainInfoVk Vector2i m_desiredExtent{}; VkFence m_imageAvailableFence{}; uint32 swapchainImageIndex = (uint32)-1; - uint32 m_acquireIndex = 0; // increases with every successful vkAcquireNextImageKHR // swapchain image ringbuffer (indexed by swapchainImageIndex) @@ -84,7 +85,7 @@ struct SwapchainInfoVk std::vector m_swapchainImageViews; std::vector m_swapchainFramebuffers; std::vector m_swapchainPresentSemaphores; - std::vector m_acquireSemaphores; // indexed by acquireIndex + std::array m_swapchainQueueFamilyIndices; VkRenderPass m_swapchainRenderPass = nullptr; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 6b76ac7e..401cb168 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -1665,6 +1665,7 @@ bool VulkanRenderer::ImguiBegin(bool mainWindow) draw_endRenderPass(); m_state.currentPipeline = VK_NULL_HANDLE; + chainInfo.WaitAvailableFence(); ImGui_ImplVulkan_CreateFontsTexture(m_state.currentCommandBuffer); ImGui_ImplVulkan_NewFrame(m_state.currentCommandBuffer, chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex], chainInfo.getExtent()); ImGui_UpdateWindowInformation(mainWindow); @@ -1721,6 +1722,7 @@ bool VulkanRenderer::BeginFrame(bool mainWindow) auto& chainInfo = GetChainInfo(mainWindow); + chainInfo.WaitAvailableFence(); VkClearColorValue clearColor{ 0, 0, 0, 0 }; ClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); @@ -2544,12 +2546,8 @@ bool VulkanRenderer::AcquireNextSwapchainImage(bool mainWindow) if (chainInfo.swapchainImageIndex != -1) return true; // image already reserved - vkWaitForFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence, VK_TRUE, std::numeric_limits::max()); vkResetFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence); - - auto& acquireSemaphore = chainInfo.m_acquireSemaphores[chainInfo.m_acquireIndex]; - - VkResult result = vkAcquireNextImageKHR(m_logicalDevice, chainInfo.swapchain, std::numeric_limits::max(), acquireSemaphore, chainInfo.m_imageAvailableFence, &chainInfo.swapchainImageIndex); + VkResult result = vkAcquireNextImageKHR(m_logicalDevice, chainInfo.swapchain, std::numeric_limits::max(), VK_NULL_HANDLE, chainInfo.m_imageAvailableFence, &chainInfo.swapchainImageIndex); if (result != VK_SUCCESS) { if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) @@ -2562,8 +2560,6 @@ bool VulkanRenderer::AcquireNextSwapchainImage(bool mainWindow) throw std::runtime_error(fmt::format("Failed to acquire next image: {}", result)); } - chainInfo.m_acquireIndex = (chainInfo.m_acquireIndex + 1) % chainInfo.m_acquireSemaphores.size(); - SubmitCommandBuffer(nullptr, &acquireSemaphore); return true; } @@ -2572,9 +2568,6 @@ void VulkanRenderer::RecreateSwapchain(bool mainWindow, bool skipCreate) SubmitCommandBuffer(); WaitDeviceIdle(); auto& chainInfo = GetChainInfo(mainWindow); - vkWaitForFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence, VK_TRUE, - std::chrono::duration_cast(std::chrono::milliseconds(10)).count() - ); Vector2i size; if (mainWindow) @@ -2640,27 +2633,17 @@ void VulkanRenderer::SwapBuffer(bool mainWindow) if (!chainInfo.hasDefinedSwapchainImage) { + chainInfo.WaitAvailableFence(); // set the swapchain image to a defined state VkClearColorValue clearColor{ 0, 0, 0, 0 }; ClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } - // make sure any writes to the image have finished (is this necessary? End of command buffer implicitly flushes everything?) - VkMemoryBarrier memoryBarrier{}; - memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; - memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - memoryBarrier.dstAccessMask = 0; - VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - VkPipelineStageFlags dstStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - vkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStage, dstStage, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr); - - VkSemaphore presentSemaphore = chainInfo.m_swapchainPresentSemaphores[chainInfo.swapchainImageIndex]; SubmitCommandBuffer(&presentSemaphore); // submit all command and signal semaphore cemu_assert_debug(m_numSubmittedCmdBuffers > 0); - VkPresentInfoKHR presentInfo = {}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.swapchainCount = 1; @@ -2673,37 +2656,10 @@ void VulkanRenderer::SwapBuffer(bool mainWindow) VkResult result = vkQueuePresentKHR(m_presentQueue, &presentInfo); if (result != VK_SUCCESS) { - if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) // todo: dont loop but handle error state? - { - int counter = 0; - while (true) - { - try - { - RecreateSwapchain(mainWindow); - return; - } - catch (std::exception&) - { - // loop until successful - counter++; - if (counter > 25) - { - cemuLog_log(LogType::Force, "Failed to recreate swapchain during SwapBuffer"); - cemuLog_waitForFlush(); - exit(0); - } - } - - std::this_thread::yield(); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - } - - cemuLog_log(LogType::Force, fmt::format("vkQueuePresentKHR failed with error {}", result)); - cemuLog_waitForFlush(); - - throw std::runtime_error(fmt::format("Failed to present draw command buffer: {}", result)); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) + chainInfo.m_shouldRecreate = true; + else + throw std::runtime_error(fmt::format("Failed to present image: {}", result)); } chainInfo.hasDefinedSwapchainImage = false; @@ -2745,6 +2701,7 @@ void VulkanRenderer::ClearColorbuffer(bool padView) if (chainInfo.swapchainImageIndex == -1) return; + chainInfo.WaitAvailableFence(); VkClearColorValue clearColor{ 0, 0, 0, 0 }; ClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); } @@ -2835,6 +2792,7 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu LatteTextureViewVk* texViewVk = (LatteTextureViewVk*)texView; draw_endRenderPass(); + chainInfo.WaitAvailableFence(); if (clearBackground) ClearColorbuffer(padView);