Vulkan: Further swapchain code improvements. (#473)

This commit is contained in:
goeiecool9999 2022-11-11 08:14:38 +01:00 committed by GitHub
parent a0e69ffbbd
commit 4d68446f14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 58 additions and 78 deletions

View File

@ -11,14 +11,14 @@ void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDe
m_logicalDevice = logicalDevice; m_logicalDevice = logicalDevice;
const auto details = QuerySwapchainSupport(surface, physicalDevice); const auto details = QuerySwapchainSupport(surface, physicalDevice);
m_surfaceFormat = ChooseSurfaceFormat(details.formats); m_surfaceFormat = ChooseSurfaceFormat(details.formats);
swapchainExtent = ChooseSwapExtent(details.capabilities, getSize()); m_actualExtent = ChooseSwapExtent(details.capabilities);
// calculate number of swapchain presentation images // calculate number of swapchain presentation images
uint32_t image_count = details.capabilities.minImageCount + 1; uint32_t image_count = details.capabilities.minImageCount + 1;
if (details.capabilities.maxImageCount > 0 && image_count > details.capabilities.maxImageCount) if (details.capabilities.maxImageCount > 0 && image_count > details.capabilities.maxImageCount)
image_count = details.capabilities.maxImageCount; image_count = details.capabilities.maxImageCount;
VkSwapchainCreateInfoKHR create_info = CreateSwapchainCreateInfo(surface, details, m_surfaceFormat, image_count, swapchainExtent); VkSwapchainCreateInfoKHR create_info = CreateSwapchainCreateInfo(surface, details, m_surfaceFormat, image_count, m_actualExtent);
create_info.oldSwapchain = nullptr; create_info.oldSwapchain = nullptr;
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
@ -26,8 +26,6 @@ void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDe
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
UnrecoverableError("Error attempting to create a swapchain"); UnrecoverableError("Error attempting to create a swapchain");
sizeOutOfDate = false;
result = vkGetSwapchainImagesKHR(logicalDevice, swapchain, &image_count, nullptr); result = vkGetSwapchainImagesKHR(logicalDevice, swapchain, &image_count, nullptr);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
UnrecoverableError("Error attempting to retrieve the count of swapchain images"); UnrecoverableError("Error attempting to retrieve the count of swapchain images");
@ -101,8 +99,8 @@ void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDe
framebufferInfo.renderPass = m_swapchainRenderPass; framebufferInfo.renderPass = m_swapchainRenderPass;
framebufferInfo.attachmentCount = 1; framebufferInfo.attachmentCount = 1;
framebufferInfo.pAttachments = attachments; framebufferInfo.pAttachments = attachments;
framebufferInfo.width = swapchainExtent.width; framebufferInfo.width = m_actualExtent.width;
framebufferInfo.height = swapchainExtent.height; framebufferInfo.height = m_actualExtent.height;
framebufferInfo.layers = 1; framebufferInfo.layers = 1;
result = vkCreateFramebuffer(logicalDevice, &framebufferInfo, nullptr, &m_swapchainFramebuffers[i]); result = vkCreateFramebuffer(logicalDevice, &framebufferInfo, nullptr, &m_swapchainFramebuffers[i]);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
@ -293,12 +291,12 @@ VkSurfaceFormatKHR SwapchainInfoVk::ChooseSurfaceFormat(const std::vector<VkSurf
return formats[0]; return formats[0];
} }
VkExtent2D SwapchainInfoVk::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, const Vector2i& size) const VkExtent2D SwapchainInfoVk::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) const
{ {
if (capabilities.currentExtent.width != std::numeric_limits<uint32>::max()) if (capabilities.currentExtent.width != std::numeric_limits<uint32>::max())
return capabilities.currentExtent; return capabilities.currentExtent;
VkExtent2D actualExtent = { (uint32)size.x, (uint32)size.y }; VkExtent2D actualExtent = { (uint32)m_desiredExtent.x, (uint32)m_desiredExtent.y };
actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
return actualExtent; return actualExtent;

View File

@ -42,20 +42,14 @@ struct SwapchainInfoVk
VkPresentModeKHR ChoosePresentMode(const std::vector<VkPresentModeKHR>& modes); VkPresentModeKHR ChoosePresentMode(const std::vector<VkPresentModeKHR>& modes);
VkSurfaceFormatKHR ChooseSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats) const; VkSurfaceFormatKHR ChooseSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats) const;
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, const Vector2i& size) const; VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) const;
VkSwapchainCreateInfoKHR CreateSwapchainCreateInfo(VkSurfaceKHR surface, const SwapchainSupportDetails& swapchainSupport, const VkSurfaceFormatKHR& surfaceFormat, uint32 imageCount, const VkExtent2D& extent); VkSwapchainCreateInfoKHR CreateSwapchainCreateInfo(VkSurfaceKHR surface, const SwapchainSupportDetails& swapchainSupport, const VkSurfaceFormatKHR& surfaceFormat, uint32 imageCount, const VkExtent2D& extent);
void setSize(const Vector2i& newSize) VkExtent2D getExtent() const
{ {
desiredExtent = newSize; return m_actualExtent;
sizeOutOfDate = true;
}
const Vector2i& getSize() const
{
return desiredExtent;
} }
SwapchainInfoVk(VkSurfaceKHR surface, bool mainWindow) SwapchainInfoVk(VkSurfaceKHR surface, bool mainWindow)
@ -69,8 +63,9 @@ struct SwapchainInfoVk
bool mainWindow{}; bool mainWindow{};
bool sizeOutOfDate{}; bool m_shouldRecreate = false;
bool m_usesSRGB = false; bool m_usesSRGB = false;
VSync m_vsyncState = VSync::Immediate;
bool hasDefinedSwapchainImage{}; // indicates if the swapchain image is in a defined state bool hasDefinedSwapchainImage{}; // indicates if the swapchain image is in a defined state
VkPhysicalDevice m_physicalDevice{}; VkPhysicalDevice m_physicalDevice{};
@ -78,11 +73,10 @@ struct SwapchainInfoVk
VkSurfaceKHR surface{}; VkSurfaceKHR surface{};
VkSurfaceFormatKHR m_surfaceFormat{}; VkSurfaceFormatKHR m_surfaceFormat{};
VkSwapchainKHR swapchain{}; VkSwapchainKHR swapchain{};
VkExtent2D swapchainExtent{}; 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 uint32 m_acquireIndex = 0; // increases with every successful vkAcquireNextImageKHR
VSync m_vsyncState = VSync::Immediate;
// swapchain image ringbuffer (indexed by swapchainImageIndex) // swapchain image ringbuffer (indexed by swapchainImageIndex)
@ -94,8 +88,6 @@ struct SwapchainInfoVk
VkRenderPass m_swapchainRenderPass = nullptr; VkRenderPass m_swapchainRenderPass = nullptr;
private: private:
Vector2i desiredExtent; VkExtent2D m_actualExtent{};
}; };

View File

@ -651,7 +651,7 @@ void VulkanRenderer::Initialize(const Vector2i& size, bool mainWindow)
if (mainWindow) if (mainWindow)
{ {
m_mainSwapchainInfo = std::make_unique<SwapchainInfoVk>(surface, mainWindow); m_mainSwapchainInfo = std::make_unique<SwapchainInfoVk>(surface, mainWindow);
SetSwapchainTargetSize(size, mainWindow); m_mainSwapchainInfo->m_desiredExtent = size;
m_mainSwapchainInfo->Create(m_physicalDevice, m_logicalDevice); m_mainSwapchainInfo->Create(m_physicalDevice, m_logicalDevice);
// aquire first command buffer // aquire first command buffer
@ -660,7 +660,7 @@ void VulkanRenderer::Initialize(const Vector2i& size, bool mainWindow)
else else
{ {
m_padSwapchainInfo = std::make_unique<SwapchainInfoVk>(surface, mainWindow); m_padSwapchainInfo = std::make_unique<SwapchainInfoVk>(surface, mainWindow);
SetSwapchainTargetSize(size, mainWindow); m_padSwapchainInfo->m_desiredExtent = size;
// todo: figure out a way to exclusively create swapchain on main LatteThread // todo: figure out a way to exclusively create swapchain on main LatteThread
m_padSwapchainInfo->Create(m_physicalDevice, m_logicalDevice); m_padSwapchainInfo->Create(m_physicalDevice, m_logicalDevice);
} }
@ -977,11 +977,6 @@ void VulkanRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool pad
SaveScreenshot(rgb_data, width, height, !padView); SaveScreenshot(rgb_data, width, height, !padView);
} }
void VulkanRenderer::SetSwapchainTargetSize(const Vector2i& size, bool mainWindow)
{
GetChainInfo(mainWindow).setSize(size);
}
static const float kQueuePriority = 1.0f; static const float kQueuePriority = 1.0f;
std::vector<VkDeviceQueueCreateInfo> VulkanRenderer::CreateQueueCreateInfos(const std::set<sint32>& uniqueQueueFamilies) const std::vector<VkDeviceQueueCreateInfo> VulkanRenderer::CreateQueueCreateInfos(const std::set<sint32>& uniqueQueueFamilies) const
@ -1671,7 +1666,7 @@ bool VulkanRenderer::ImguiBegin(bool mainWindow)
m_state.currentPipeline = VK_NULL_HANDLE; m_state.currentPipeline = VK_NULL_HANDLE;
ImGui_ImplVulkan_CreateFontsTexture(m_state.currentCommandBuffer); ImGui_ImplVulkan_CreateFontsTexture(m_state.currentCommandBuffer);
ImGui_ImplVulkan_NewFrame(m_state.currentCommandBuffer, chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex], chainInfo.swapchainExtent); ImGui_ImplVulkan_NewFrame(m_state.currentCommandBuffer, chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex], chainInfo.getExtent());
ImGui_UpdateWindowInformation(mainWindow); ImGui_UpdateWindowInformation(mainWindow);
ImGui::NewFrame(); ImGui::NewFrame();
return true; return true;
@ -2543,18 +2538,8 @@ bool VulkanRenderer::AcquireNextSwapchainImage(bool mainWindow)
auto& chainInfo = GetChainInfo(mainWindow); auto& chainInfo = GetChainInfo(mainWindow);
UpdateVSyncState(mainWindow); if (!UpdateSwapchainProperties(mainWindow))
return false;
const bool latteBufferUsesSRGB = mainWindow ? LatteGPUState.tvBufferUsesSRGB : LatteGPUState.drcBufferUsesSRGB;
if (chainInfo.sizeOutOfDate || chainInfo.m_usesSRGB != latteBufferUsesSRGB)
{
try
{
RecreateSwapchain(mainWindow);
chainInfo.m_usesSRGB = latteBufferUsesSRGB;
}
catch (std::exception&) { cemu_assert_debug(false); }
}
if (chainInfo.swapchainImageIndex != -1) if (chainInfo.swapchainImageIndex != -1)
return true; // image already reserved return true; // image already reserved
@ -2567,24 +2552,14 @@ bool VulkanRenderer::AcquireNextSwapchainImage(bool mainWindow)
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, chainInfo.swapchain, std::numeric_limits<uint64_t>::max(), acquireSemaphore, chainInfo.m_imageAvailableFence, &chainInfo.swapchainImageIndex); 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)
{ {
while (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) // todo: handle error state correctly. Looping doesnt always make sense? if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
{ chainInfo.m_shouldRecreate = true;
try
{
RecreateSwapchain(mainWindow);
if (vkWaitForFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence, VK_TRUE, 0) == VK_SUCCESS)
vkResetFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence);
result = vkAcquireNextImageKHR(m_logicalDevice, chainInfo.swapchain, std::numeric_limits<uint64_t>::max(), acquireSemaphore, chainInfo.m_imageAvailableFence, &chainInfo.swapchainImageIndex);
if (result == VK_SUCCESS)
return true;
}
catch (std::exception&) {}
std::this_thread::yield(); if (result == VK_ERROR_OUT_OF_DATE_KHR)
std::this_thread::sleep_for(std::chrono::milliseconds(1)); return false;
}
throw std::runtime_error(fmt::format("Failed to acquire next image: {}", result)); if (result != VK_ERROR_OUT_OF_DATE_KHR && result != VK_SUBOPTIMAL_KHR)
throw std::runtime_error(fmt::format("Failed to acquire next image: {}", result));
} }
chainInfo.m_acquireIndex = (chainInfo.m_acquireIndex + 1) % chainInfo.m_acquireSemaphores.size(); chainInfo.m_acquireIndex = (chainInfo.m_acquireIndex + 1) % chainInfo.m_acquireSemaphores.size();
@ -2613,7 +2588,7 @@ void VulkanRenderer::RecreateSwapchain(bool mainWindow, bool skipCreate)
} }
chainInfo.Cleanup(); chainInfo.Cleanup();
chainInfo.setSize(size); chainInfo.m_desiredExtent = size;
if(!skipCreate) if(!skipCreate)
{ {
chainInfo.Create(m_physicalDevice, m_logicalDevice); chainInfo.Create(m_physicalDevice, m_logicalDevice);
@ -2624,14 +2599,36 @@ void VulkanRenderer::RecreateSwapchain(bool mainWindow, bool skipCreate)
ImguiInit(); ImguiInit();
} }
void VulkanRenderer::UpdateVSyncState(bool mainWindow) bool VulkanRenderer::UpdateSwapchainProperties(bool mainWindow)
{ {
auto& chainInfo = GetChainInfo(mainWindow); auto& chainInfo = GetChainInfo(mainWindow);
bool stateChanged = chainInfo.m_shouldRecreate;
const auto configValue = (VSync)GetConfig().vsync.GetValue(); const auto configValue = (VSync)GetConfig().vsync.GetValue();
if(chainInfo.m_vsyncState != configValue){ if(chainInfo.m_vsyncState != configValue)
RecreateSwapchain(mainWindow); stateChanged = true;
chainInfo.m_vsyncState = configValue;
const bool latteBufferUsesSRGB = mainWindow ? LatteGPUState.tvBufferUsesSRGB : LatteGPUState.drcBufferUsesSRGB;
if (chainInfo.m_usesSRGB != latteBufferUsesSRGB)
stateChanged = true;
if(stateChanged)
{
try
{
RecreateSwapchain(mainWindow);
}
catch (std::exception&)
{
cemu_assert_debug(false);
return false;
}
} }
chainInfo.m_shouldRecreate = false;
chainInfo.m_vsyncState = configValue;
chainInfo.m_usesSRGB = latteBufferUsesSRGB;
return true;
} }
void VulkanRenderer::SwapBuffer(bool mainWindow) void VulkanRenderer::SwapBuffer(bool mainWindow)
@ -2857,7 +2854,7 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
renderPassInfo.renderPass = chainInfo.m_swapchainRenderPass; renderPassInfo.renderPass = chainInfo.m_swapchainRenderPass;
renderPassInfo.framebuffer = chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex]; renderPassInfo.framebuffer = chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex];
renderPassInfo.renderArea.offset = { 0, 0 }; renderPassInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.extent = chainInfo.swapchainExtent; renderPassInfo.renderArea.extent = chainInfo.getExtent();
renderPassInfo.clearValueCount = 0; renderPassInfo.clearValueCount = 0;
VkViewport viewport{}; VkViewport viewport{};
@ -2870,7 +2867,7 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
vkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &viewport); vkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &viewport);
VkRect2D scissor{}; VkRect2D scissor{};
scissor.extent = chainInfo.swapchainExtent; scissor.extent = chainInfo.getExtent();
vkCmdSetScissor(m_state.currentCommandBuffer, 0, 1, &scissor); vkCmdSetScissor(m_state.currentCommandBuffer, 0, 1, &scissor);
auto descriptSet = backbufferBlit_createDescriptorSet(m_swapchainDescriptorSetLayout, texViewVk, useLinearTexFilter); auto descriptSet = backbufferBlit_createDescriptorSet(m_swapchainDescriptorSetLayout, texViewVk, useLinearTexFilter);

View File

@ -191,7 +191,6 @@ public:
bool IsPadWindowActive() override; bool IsPadWindowActive() override;
void HandleScreenshotRequest(LatteTextureView* texView, bool padView) override; void HandleScreenshotRequest(LatteTextureView* texView, bool padView) override;
void SetSwapchainTargetSize(const Vector2i& size, bool mainWindow);
void QueryMemoryInfo(); void QueryMemoryInfo();
void QueryAvailableFormats(); void QueryAvailableFormats();
@ -485,7 +484,7 @@ private:
static bool CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info); static bool CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info);
static std::vector<const char*> CheckInstanceExtensionSupport(FeatureControl& info); static std::vector<const char*> CheckInstanceExtensionSupport(FeatureControl& info);
void UpdateVSyncState(bool mainWindow); bool UpdateSwapchainProperties(bool mainWindow);
void SwapBuffer(bool mainWindow); void SwapBuffer(bool mainWindow);
VkDescriptorSetLayout m_swapchainDescriptorSetLayout; VkDescriptorSetLayout m_swapchainDescriptorSetLayout;

View File

@ -61,10 +61,4 @@ void VulkanCanvas::OnResize(wxSizeEvent& event)
const wxRect refreshRect(size); const wxRect refreshRect(size);
RefreshRect(refreshRect, false); RefreshRect(refreshRect, false);
if (g_renderer == nullptr)
return;
auto vulkan_renderer = VulkanRenderer::GetInstance();
vulkan_renderer->SetSwapchainTargetSize({size.x, size.y}, m_is_main_window);
} }

View File

@ -912,7 +912,7 @@ void ImGui_ImplVulkan_Shutdown()
ImGui_ImplVulkan_DestroyDeviceObjects(); ImGui_ImplVulkan_DestroyDeviceObjects();
} }
void ImGui_ImplVulkan_NewFrame(VkCommandBuffer command_buffer, VkFramebuffer framebuffer, VkExtent2D& extend) void ImGui_ImplVulkan_NewFrame(VkCommandBuffer command_buffer, VkFramebuffer framebuffer, VkExtent2D extent)
{ {
auto& io = ImGui::GetIO(); auto& io = ImGui::GetIO();
@ -921,7 +921,7 @@ void ImGui_ImplVulkan_NewFrame(VkCommandBuffer command_buffer, VkFramebuffer fra
renderPassInfo.renderPass = g_RenderPass; renderPassInfo.renderPass = g_RenderPass;
renderPassInfo.framebuffer = framebuffer; renderPassInfo.framebuffer = framebuffer;
renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = extend; renderPassInfo.renderArea.extent = extent;
renderPassInfo.clearValueCount = 0; renderPassInfo.clearValueCount = 0;
vkCmdBeginRenderPass(command_buffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(command_buffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
} }

View File

@ -46,7 +46,7 @@ struct ImGui_ImplVulkan_InitInfo
// Called by user code // Called by user code
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass); IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(VkCommandBuffer command_buffer, VkFramebuffer framebuffer, VkExtent2D& extend); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(VkCommandBuffer command_buffer, VkFramebuffer framebuffer, VkExtent2D extent);
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer); IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer); IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture(); IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture();