mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-22 17:19:18 +01:00
Vulkan: Further simplify swapchain code (#502)
This commit is contained in:
parent
3f84c7fa24
commit
3a94a276da
@ -13,10 +13,7 @@ void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDe
|
|||||||
m_surfaceFormat = ChooseSurfaceFormat(details.formats);
|
m_surfaceFormat = ChooseSurfaceFormat(details.formats);
|
||||||
m_actualExtent = ChooseSwapExtent(details.capabilities);
|
m_actualExtent = ChooseSwapExtent(details.capabilities);
|
||||||
|
|
||||||
// calculate number of swapchain presentation images
|
uint32_t image_count = details.capabilities.minImageCount;
|
||||||
uint32_t image_count = details.capabilities.minImageCount + 1;
|
|
||||||
if (details.capabilities.maxImageCount > 0 && image_count > details.capabilities.maxImageCount)
|
|
||||||
image_count = details.capabilities.maxImageCount;
|
|
||||||
|
|
||||||
VkSwapchainCreateInfoKHR create_info = CreateSwapchainCreateInfo(surface, details, m_surfaceFormat, image_count, m_actualExtent);
|
VkSwapchainCreateInfoKHR create_info = CreateSwapchainCreateInfo(surface, details, m_surfaceFormat, image_count, m_actualExtent);
|
||||||
create_info.oldSwapchain = nullptr;
|
create_info.oldSwapchain = nullptr;
|
||||||
@ -115,22 +112,14 @@ void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDe
|
|||||||
UnrecoverableError("Failed to create semaphore for swapchain present");
|
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 = {};
|
VkFenceCreateInfo fenceInfo = {};
|
||||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
result = vkCreateFence(logicalDevice, &fenceInfo, nullptr, &m_imageAvailableFence);
|
result = vkCreateFence(logicalDevice, &fenceInfo, nullptr, &m_imageAvailableFence);
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
UnrecoverableError("Failed to create fence for swapchain");
|
UnrecoverableError("Failed to create fence for swapchain");
|
||||||
|
|
||||||
|
hasDefinedSwapchainImage = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwapchainInfoVk::Cleanup()
|
void SwapchainInfoVk::Cleanup()
|
||||||
@ -141,10 +130,6 @@ void SwapchainInfoVk::Cleanup()
|
|||||||
vkDestroySemaphore(m_logicalDevice, sem, nullptr);
|
vkDestroySemaphore(m_logicalDevice, sem, nullptr);
|
||||||
m_swapchainPresentSemaphores.clear();
|
m_swapchainPresentSemaphores.clear();
|
||||||
|
|
||||||
for (auto& itr: m_acquireSemaphores)
|
|
||||||
vkDestroySemaphore(m_logicalDevice, itr, nullptr);
|
|
||||||
m_acquireSemaphores.clear();
|
|
||||||
|
|
||||||
if (m_swapchainRenderPass)
|
if (m_swapchainRenderPass)
|
||||||
{
|
{
|
||||||
vkDestroyRenderPass(m_logicalDevice, m_swapchainRenderPass, nullptr);
|
vkDestroyRenderPass(m_logicalDevice, m_swapchainRenderPass, nullptr);
|
||||||
@ -177,6 +162,11 @@ bool SwapchainInfoVk::IsValid() const
|
|||||||
return swapchain && m_imageAvailableFence;
|
return swapchain && m_imageAvailableFence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SwapchainInfoVk::WaitAvailableFence() const
|
||||||
|
{
|
||||||
|
vkWaitForFences(m_logicalDevice, 1, &m_imageAvailableFence, VK_TRUE, UINT64_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
void SwapchainInfoVk::UnrecoverableError(const char* errMsg)
|
void SwapchainInfoVk::UnrecoverableError(const char* errMsg)
|
||||||
{
|
{
|
||||||
forceLog_printf("Unrecoverable error in Vulkan swapchain");
|
forceLog_printf("Unrecoverable error in Vulkan swapchain");
|
||||||
@ -345,12 +335,12 @@ VkSwapchainCreateInfoKHR SwapchainInfoVk::CreateSwapchainCreateInfo(VkSurfaceKHR
|
|||||||
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
|
||||||
const QueueFamilyIndices indices = FindQueueFamilies(surface, m_physicalDevice);
|
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)
|
if (indices.graphicsFamily != indices.presentFamily)
|
||||||
{
|
{
|
||||||
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
createInfo.queueFamilyIndexCount = 2;
|
createInfo.queueFamilyIndexCount = m_swapchainQueueFamilyIndices.size();
|
||||||
createInfo.pQueueFamilyIndices = queueFamilyIndices;
|
createInfo.pQueueFamilyIndices = m_swapchainQueueFamilyIndices.data();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
@ -34,6 +34,8 @@ struct SwapchainInfoVk
|
|||||||
|
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
|
void WaitAvailableFence() const;
|
||||||
|
|
||||||
static void UnrecoverableError(const char* errMsg);
|
static void UnrecoverableError(const char* errMsg);
|
||||||
|
|
||||||
// todo: move this function somewhere more sensible. Not directly swapchain related
|
// todo: move this function somewhere more sensible. Not directly swapchain related
|
||||||
@ -76,7 +78,6 @@ struct SwapchainInfoVk
|
|||||||
Vector2i m_desiredExtent{};
|
Vector2i m_desiredExtent{};
|
||||||
VkFence m_imageAvailableFence{};
|
VkFence m_imageAvailableFence{};
|
||||||
uint32 swapchainImageIndex = (uint32)-1;
|
uint32 swapchainImageIndex = (uint32)-1;
|
||||||
uint32 m_acquireIndex = 0; // increases with every successful vkAcquireNextImageKHR
|
|
||||||
|
|
||||||
|
|
||||||
// swapchain image ringbuffer (indexed by swapchainImageIndex)
|
// swapchain image ringbuffer (indexed by swapchainImageIndex)
|
||||||
@ -84,7 +85,7 @@ struct SwapchainInfoVk
|
|||||||
std::vector<VkImageView> m_swapchainImageViews;
|
std::vector<VkImageView> m_swapchainImageViews;
|
||||||
std::vector<VkFramebuffer> m_swapchainFramebuffers;
|
std::vector<VkFramebuffer> m_swapchainFramebuffers;
|
||||||
std::vector<VkSemaphore> m_swapchainPresentSemaphores;
|
std::vector<VkSemaphore> m_swapchainPresentSemaphores;
|
||||||
std::vector<VkSemaphore> m_acquireSemaphores; // indexed by acquireIndex
|
std::array<uint32, 2> m_swapchainQueueFamilyIndices;
|
||||||
|
|
||||||
VkRenderPass m_swapchainRenderPass = nullptr;
|
VkRenderPass m_swapchainRenderPass = nullptr;
|
||||||
|
|
||||||
|
@ -1665,6 +1665,7 @@ bool VulkanRenderer::ImguiBegin(bool mainWindow)
|
|||||||
draw_endRenderPass();
|
draw_endRenderPass();
|
||||||
m_state.currentPipeline = VK_NULL_HANDLE;
|
m_state.currentPipeline = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
chainInfo.WaitAvailableFence();
|
||||||
ImGui_ImplVulkan_CreateFontsTexture(m_state.currentCommandBuffer);
|
ImGui_ImplVulkan_CreateFontsTexture(m_state.currentCommandBuffer);
|
||||||
ImGui_ImplVulkan_NewFrame(m_state.currentCommandBuffer, chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex], chainInfo.getExtent());
|
ImGui_ImplVulkan_NewFrame(m_state.currentCommandBuffer, chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex], chainInfo.getExtent());
|
||||||
ImGui_UpdateWindowInformation(mainWindow);
|
ImGui_UpdateWindowInformation(mainWindow);
|
||||||
@ -1721,6 +1722,7 @@ bool VulkanRenderer::BeginFrame(bool mainWindow)
|
|||||||
|
|
||||||
auto& chainInfo = GetChainInfo(mainWindow);
|
auto& chainInfo = GetChainInfo(mainWindow);
|
||||||
|
|
||||||
|
chainInfo.WaitAvailableFence();
|
||||||
VkClearColorValue clearColor{ 0, 0, 0, 0 };
|
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);
|
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)
|
if (chainInfo.swapchainImageIndex != -1)
|
||||||
return true; // image already reserved
|
return true; // image already reserved
|
||||||
|
|
||||||
vkWaitForFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence, VK_TRUE, std::numeric_limits<uint64_t>::max());
|
|
||||||
vkResetFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence);
|
vkResetFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence);
|
||||||
|
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, chainInfo.swapchain, std::numeric_limits<uint64_t>::max(), VK_NULL_HANDLE, chainInfo.m_imageAvailableFence, &chainInfo.swapchainImageIndex);
|
||||||
auto& acquireSemaphore = chainInfo.m_acquireSemaphores[chainInfo.m_acquireIndex];
|
|
||||||
|
|
||||||
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, chainInfo.swapchain, std::numeric_limits<uint64_t>::max(), acquireSemaphore, chainInfo.m_imageAvailableFence, &chainInfo.swapchainImageIndex);
|
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
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));
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2572,9 +2568,6 @@ void VulkanRenderer::RecreateSwapchain(bool mainWindow, bool skipCreate)
|
|||||||
SubmitCommandBuffer();
|
SubmitCommandBuffer();
|
||||||
WaitDeviceIdle();
|
WaitDeviceIdle();
|
||||||
auto& chainInfo = GetChainInfo(mainWindow);
|
auto& chainInfo = GetChainInfo(mainWindow);
|
||||||
vkWaitForFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence, VK_TRUE,
|
|
||||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(10)).count()
|
|
||||||
);
|
|
||||||
|
|
||||||
Vector2i size;
|
Vector2i size;
|
||||||
if (mainWindow)
|
if (mainWindow)
|
||||||
@ -2640,27 +2633,17 @@ void VulkanRenderer::SwapBuffer(bool mainWindow)
|
|||||||
|
|
||||||
if (!chainInfo.hasDefinedSwapchainImage)
|
if (!chainInfo.hasDefinedSwapchainImage)
|
||||||
{
|
{
|
||||||
|
chainInfo.WaitAvailableFence();
|
||||||
// set the swapchain image to a defined state
|
// set the swapchain image to a defined state
|
||||||
VkClearColorValue clearColor{ 0, 0, 0, 0 };
|
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);
|
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];
|
VkSemaphore presentSemaphore = chainInfo.m_swapchainPresentSemaphores[chainInfo.swapchainImageIndex];
|
||||||
SubmitCommandBuffer(&presentSemaphore); // submit all command and signal semaphore
|
SubmitCommandBuffer(&presentSemaphore); // submit all command and signal semaphore
|
||||||
|
|
||||||
cemu_assert_debug(m_numSubmittedCmdBuffers > 0);
|
cemu_assert_debug(m_numSubmittedCmdBuffers > 0);
|
||||||
|
|
||||||
|
|
||||||
VkPresentInfoKHR presentInfo = {};
|
VkPresentInfoKHR presentInfo = {};
|
||||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
presentInfo.swapchainCount = 1;
|
presentInfo.swapchainCount = 1;
|
||||||
@ -2673,37 +2656,10 @@ void VulkanRenderer::SwapBuffer(bool mainWindow)
|
|||||||
VkResult result = vkQueuePresentKHR(m_presentQueue, &presentInfo);
|
VkResult result = vkQueuePresentKHR(m_presentQueue, &presentInfo);
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) // todo: dont loop but handle error state?
|
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
||||||
{
|
chainInfo.m_shouldRecreate = true;
|
||||||
int counter = 0;
|
else
|
||||||
while (true)
|
throw std::runtime_error(fmt::format("Failed to present image: {}", result));
|
||||||
{
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chainInfo.hasDefinedSwapchainImage = false;
|
chainInfo.hasDefinedSwapchainImage = false;
|
||||||
@ -2745,6 +2701,7 @@ void VulkanRenderer::ClearColorbuffer(bool padView)
|
|||||||
if (chainInfo.swapchainImageIndex == -1)
|
if (chainInfo.swapchainImageIndex == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
chainInfo.WaitAvailableFence();
|
||||||
VkClearColorValue clearColor{ 0, 0, 0, 0 };
|
VkClearColorValue clearColor{ 0, 0, 0, 0 };
|
||||||
ClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
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;
|
LatteTextureViewVk* texViewVk = (LatteTextureViewVk*)texView;
|
||||||
draw_endRenderPass();
|
draw_endRenderPass();
|
||||||
|
|
||||||
|
chainInfo.WaitAvailableFence();
|
||||||
if (clearBackground)
|
if (clearBackground)
|
||||||
ClearColorbuffer(padView);
|
ClearColorbuffer(padView);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user