Skip to content

Commit 3a94a27

Browse files
Vulkan: Further simplify swapchain code (#502)
1 parent 3f84c7f commit 3a94a27

File tree

3 files changed

+24
-75
lines changed

3 files changed

+24
-75
lines changed

src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDe
1313
m_surfaceFormat = ChooseSurfaceFormat(details.formats);
1414
m_actualExtent = ChooseSwapExtent(details.capabilities);
1515

16-
// calculate number of swapchain presentation images
17-
uint32_t image_count = details.capabilities.minImageCount + 1;
18-
if (details.capabilities.maxImageCount > 0 && image_count > details.capabilities.maxImageCount)
19-
image_count = details.capabilities.maxImageCount;
16+
uint32_t image_count = details.capabilities.minImageCount;
2017

2118
VkSwapchainCreateInfoKHR create_info = CreateSwapchainCreateInfo(surface, details, m_surfaceFormat, image_count, m_actualExtent);
2219
create_info.oldSwapchain = nullptr;
@@ -115,22 +112,14 @@ void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDe
115112
UnrecoverableError("Failed to create semaphore for swapchain present");
116113
}
117114

118-
m_acquireSemaphores.resize(m_swapchainImages.size());
119-
for (auto& semaphore : m_acquireSemaphores)
120-
{
121-
VkSemaphoreCreateInfo info = {};
122-
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
123-
if (vkCreateSemaphore(logicalDevice, &info, nullptr, &semaphore) != VK_SUCCESS)
124-
UnrecoverableError("Failed to create semaphore for swapchain acquire");
125-
}
126-
m_acquireIndex = 0;
127-
128115
VkFenceCreateInfo fenceInfo = {};
129116
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
130117
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
131118
result = vkCreateFence(logicalDevice, &fenceInfo, nullptr, &m_imageAvailableFence);
132119
if (result != VK_SUCCESS)
133120
UnrecoverableError("Failed to create fence for swapchain");
121+
122+
hasDefinedSwapchainImage = false;
134123
}
135124

136125
void SwapchainInfoVk::Cleanup()
@@ -141,10 +130,6 @@ void SwapchainInfoVk::Cleanup()
141130
vkDestroySemaphore(m_logicalDevice, sem, nullptr);
142131
m_swapchainPresentSemaphores.clear();
143132

144-
for (auto& itr: m_acquireSemaphores)
145-
vkDestroySemaphore(m_logicalDevice, itr, nullptr);
146-
m_acquireSemaphores.clear();
147-
148133
if (m_swapchainRenderPass)
149134
{
150135
vkDestroyRenderPass(m_logicalDevice, m_swapchainRenderPass, nullptr);
@@ -177,6 +162,11 @@ bool SwapchainInfoVk::IsValid() const
177162
return swapchain && m_imageAvailableFence;
178163
}
179164

165+
void SwapchainInfoVk::WaitAvailableFence() const
166+
{
167+
vkWaitForFences(m_logicalDevice, 1, &m_imageAvailableFence, VK_TRUE, UINT64_MAX);
168+
}
169+
180170
void SwapchainInfoVk::UnrecoverableError(const char* errMsg)
181171
{
182172
forceLog_printf("Unrecoverable error in Vulkan swapchain");
@@ -345,12 +335,12 @@ VkSwapchainCreateInfoKHR SwapchainInfoVk::CreateSwapchainCreateInfo(VkSurfaceKHR
345335
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
346336

347337
const QueueFamilyIndices indices = FindQueueFamilies(surface, m_physicalDevice);
348-
uint32_t queueFamilyIndices[] = { (uint32)indices.graphicsFamily, (uint32)indices.presentFamily };
338+
m_swapchainQueueFamilyIndices = { (uint32)indices.graphicsFamily, (uint32)indices.presentFamily };
349339
if (indices.graphicsFamily != indices.presentFamily)
350340
{
351341
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
352-
createInfo.queueFamilyIndexCount = 2;
353-
createInfo.pQueueFamilyIndices = queueFamilyIndices;
342+
createInfo.queueFamilyIndexCount = m_swapchainQueueFamilyIndices.size();
343+
createInfo.pQueueFamilyIndices = m_swapchainQueueFamilyIndices.data();
354344
}
355345
else
356346
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;

src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ struct SwapchainInfoVk
3434

3535
bool IsValid() const;
3636

37+
void WaitAvailableFence() const;
38+
3739
static void UnrecoverableError(const char* errMsg);
3840

3941
// todo: move this function somewhere more sensible. Not directly swapchain related
@@ -76,15 +78,14 @@ struct SwapchainInfoVk
7678
Vector2i m_desiredExtent{};
7779
VkFence m_imageAvailableFence{};
7880
uint32 swapchainImageIndex = (uint32)-1;
79-
uint32 m_acquireIndex = 0; // increases with every successful vkAcquireNextImageKHR
8081

8182

8283
// swapchain image ringbuffer (indexed by swapchainImageIndex)
8384
std::vector<VkImage> m_swapchainImages;
8485
std::vector<VkImageView> m_swapchainImageViews;
8586
std::vector<VkFramebuffer> m_swapchainFramebuffers;
8687
std::vector<VkSemaphore> m_swapchainPresentSemaphores;
87-
std::vector<VkSemaphore> m_acquireSemaphores; // indexed by acquireIndex
88+
std::array<uint32, 2> m_swapchainQueueFamilyIndices;
8889

8990
VkRenderPass m_swapchainRenderPass = nullptr;
9091

src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp

Lines changed: 10 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,7 @@ bool VulkanRenderer::ImguiBegin(bool mainWindow)
16651665
draw_endRenderPass();
16661666
m_state.currentPipeline = VK_NULL_HANDLE;
16671667

1668+
chainInfo.WaitAvailableFence();
16681669
ImGui_ImplVulkan_CreateFontsTexture(m_state.currentCommandBuffer);
16691670
ImGui_ImplVulkan_NewFrame(m_state.currentCommandBuffer, chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex], chainInfo.getExtent());
16701671
ImGui_UpdateWindowInformation(mainWindow);
@@ -1721,6 +1722,7 @@ bool VulkanRenderer::BeginFrame(bool mainWindow)
17211722

17221723
auto& chainInfo = GetChainInfo(mainWindow);
17231724

1725+
chainInfo.WaitAvailableFence();
17241726
VkClearColorValue clearColor{ 0, 0, 0, 0 };
17251727
ClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
17261728

@@ -2544,12 +2546,8 @@ bool VulkanRenderer::AcquireNextSwapchainImage(bool mainWindow)
25442546
if (chainInfo.swapchainImageIndex != -1)
25452547
return true; // image already reserved
25462548

2547-
vkWaitForFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence, VK_TRUE, std::numeric_limits<uint64_t>::max());
25482549
vkResetFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence);
2549-
2550-
auto& acquireSemaphore = chainInfo.m_acquireSemaphores[chainInfo.m_acquireIndex];
2551-
2552-
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, chainInfo.swapchain, std::numeric_limits<uint64_t>::max(), acquireSemaphore, chainInfo.m_imageAvailableFence, &chainInfo.swapchainImageIndex);
2550+
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, chainInfo.swapchain, std::numeric_limits<uint64_t>::max(), VK_NULL_HANDLE, chainInfo.m_imageAvailableFence, &chainInfo.swapchainImageIndex);
25532551
if (result != VK_SUCCESS)
25542552
{
25552553
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
@@ -2562,8 +2560,6 @@ bool VulkanRenderer::AcquireNextSwapchainImage(bool mainWindow)
25622560
throw std::runtime_error(fmt::format("Failed to acquire next image: {}", result));
25632561
}
25642562

2565-
chainInfo.m_acquireIndex = (chainInfo.m_acquireIndex + 1) % chainInfo.m_acquireSemaphores.size();
2566-
SubmitCommandBuffer(nullptr, &acquireSemaphore);
25672563
return true;
25682564
}
25692565

@@ -2572,9 +2568,6 @@ void VulkanRenderer::RecreateSwapchain(bool mainWindow, bool skipCreate)
25722568
SubmitCommandBuffer();
25732569
WaitDeviceIdle();
25742570
auto& chainInfo = GetChainInfo(mainWindow);
2575-
vkWaitForFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence, VK_TRUE,
2576-
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(10)).count()
2577-
);
25782571

25792572
Vector2i size;
25802573
if (mainWindow)
@@ -2640,27 +2633,17 @@ void VulkanRenderer::SwapBuffer(bool mainWindow)
26402633

26412634
if (!chainInfo.hasDefinedSwapchainImage)
26422635
{
2636+
chainInfo.WaitAvailableFence();
26432637
// set the swapchain image to a defined state
26442638
VkClearColorValue clearColor{ 0, 0, 0, 0 };
26452639
ClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
26462640
}
26472641

2648-
// make sure any writes to the image have finished (is this necessary? End of command buffer implicitly flushes everything?)
2649-
VkMemoryBarrier memoryBarrier{};
2650-
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
2651-
memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2652-
memoryBarrier.dstAccessMask = 0;
2653-
VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2654-
VkPipelineStageFlags dstStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
2655-
vkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStage, dstStage, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
2656-
2657-
26582642
VkSemaphore presentSemaphore = chainInfo.m_swapchainPresentSemaphores[chainInfo.swapchainImageIndex];
26592643
SubmitCommandBuffer(&presentSemaphore); // submit all command and signal semaphore
26602644

26612645
cemu_assert_debug(m_numSubmittedCmdBuffers > 0);
26622646

2663-
26642647
VkPresentInfoKHR presentInfo = {};
26652648
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
26662649
presentInfo.swapchainCount = 1;
@@ -2673,37 +2656,10 @@ void VulkanRenderer::SwapBuffer(bool mainWindow)
26732656
VkResult result = vkQueuePresentKHR(m_presentQueue, &presentInfo);
26742657
if (result != VK_SUCCESS)
26752658
{
2676-
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) // todo: dont loop but handle error state?
2677-
{
2678-
int counter = 0;
2679-
while (true)
2680-
{
2681-
try
2682-
{
2683-
RecreateSwapchain(mainWindow);
2684-
return;
2685-
}
2686-
catch (std::exception&)
2687-
{
2688-
// loop until successful
2689-
counter++;
2690-
if (counter > 25)
2691-
{
2692-
cemuLog_log(LogType::Force, "Failed to recreate swapchain during SwapBuffer");
2693-
cemuLog_waitForFlush();
2694-
exit(0);
2695-
}
2696-
}
2697-
2698-
std::this_thread::yield();
2699-
std::this_thread::sleep_for(std::chrono::milliseconds(1));
2700-
}
2701-
}
2702-
2703-
cemuLog_log(LogType::Force, fmt::format("vkQueuePresentKHR failed with error {}", result));
2704-
cemuLog_waitForFlush();
2705-
2706-
throw std::runtime_error(fmt::format("Failed to present draw command buffer: {}", result));
2659+
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
2660+
chainInfo.m_shouldRecreate = true;
2661+
else
2662+
throw std::runtime_error(fmt::format("Failed to present image: {}", result));
27072663
}
27082664

27092665
chainInfo.hasDefinedSwapchainImage = false;
@@ -2745,6 +2701,7 @@ void VulkanRenderer::ClearColorbuffer(bool padView)
27452701
if (chainInfo.swapchainImageIndex == -1)
27462702
return;
27472703

2704+
chainInfo.WaitAvailableFence();
27482705
VkClearColorValue clearColor{ 0, 0, 0, 0 };
27492706
ClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
27502707
}
@@ -2835,6 +2792,7 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
28352792
LatteTextureViewVk* texViewVk = (LatteTextureViewVk*)texView;
28362793
draw_endRenderPass();
28372794

2795+
chainInfo.WaitAvailableFence();
28382796
if (clearBackground)
28392797
ClearColorbuffer(padView);
28402798

0 commit comments

Comments
 (0)