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;
const auto details = QuerySwapchainSupport(surface, physicalDevice);
m_surfaceFormat = ChooseSurfaceFormat(details.formats);
swapchainExtent = ChooseSwapExtent(details.capabilities, getSize());
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;
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.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)
UnrecoverableError("Error attempting to create a swapchain");
sizeOutOfDate = false;
result = vkGetSwapchainImagesKHR(logicalDevice, swapchain, &image_count, nullptr);
if (result != VK_SUCCESS)
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.attachmentCount = 1;
framebufferInfo.pAttachments = attachments;
framebufferInfo.width = swapchainExtent.width;
framebufferInfo.height = swapchainExtent.height;
framebufferInfo.width = m_actualExtent.width;
framebufferInfo.height = m_actualExtent.height;
framebufferInfo.layers = 1;
result = vkCreateFramebuffer(logicalDevice, &framebufferInfo, nullptr, &m_swapchainFramebuffers[i]);
if (result != VK_SUCCESS)
@ -293,12 +291,12 @@ VkSurfaceFormatKHR SwapchainInfoVk::ChooseSurfaceFormat(const std::vector<VkSurf
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())
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.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
return actualExtent;

View File

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

View File

@ -651,7 +651,7 @@ void VulkanRenderer::Initialize(const Vector2i& size, bool mainWindow)
if (mainWindow)
{
m_mainSwapchainInfo = std::make_unique<SwapchainInfoVk>(surface, mainWindow);
SetSwapchainTargetSize(size, mainWindow);
m_mainSwapchainInfo->m_desiredExtent = size;
m_mainSwapchainInfo->Create(m_physicalDevice, m_logicalDevice);
// aquire first command buffer
@ -660,7 +660,7 @@ void VulkanRenderer::Initialize(const Vector2i& size, bool mainWindow)
else
{
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
m_padSwapchainInfo->Create(m_physicalDevice, m_logicalDevice);
}
@ -977,11 +977,6 @@ void VulkanRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool pad
SaveScreenshot(rgb_data, width, height, !padView);
}
void VulkanRenderer::SetSwapchainTargetSize(const Vector2i& size, bool mainWindow)
{
GetChainInfo(mainWindow).setSize(size);
}
static const float kQueuePriority = 1.0f;
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;
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::NewFrame();
return true;
@ -2543,18 +2538,8 @@ bool VulkanRenderer::AcquireNextSwapchainImage(bool mainWindow)
auto& chainInfo = GetChainInfo(mainWindow);
UpdateVSyncState(mainWindow);
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 (!UpdateSwapchainProperties(mainWindow))
return false;
if (chainInfo.swapchainImageIndex != -1)
return true; // image already reserved
@ -2567,23 +2552,13 @@ bool VulkanRenderer::AcquireNextSwapchainImage(bool mainWindow)
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, chainInfo.swapchain, std::numeric_limits<uint64_t>::max(), acquireSemaphore, chainInfo.m_imageAvailableFence, &chainInfo.swapchainImageIndex);
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?
{
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&) {}
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
chainInfo.m_shouldRecreate = true;
std::this_thread::yield();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
if (result == VK_ERROR_OUT_OF_DATE_KHR)
return false;
if (result != VK_ERROR_OUT_OF_DATE_KHR && result != VK_SUBOPTIMAL_KHR)
throw std::runtime_error(fmt::format("Failed to acquire next image: {}", result));
}
@ -2613,7 +2588,7 @@ void VulkanRenderer::RecreateSwapchain(bool mainWindow, bool skipCreate)
}
chainInfo.Cleanup();
chainInfo.setSize(size);
chainInfo.m_desiredExtent = size;
if(!skipCreate)
{
chainInfo.Create(m_physicalDevice, m_logicalDevice);
@ -2624,14 +2599,36 @@ void VulkanRenderer::RecreateSwapchain(bool mainWindow, bool skipCreate)
ImguiInit();
}
void VulkanRenderer::UpdateVSyncState(bool mainWindow)
bool VulkanRenderer::UpdateSwapchainProperties(bool mainWindow)
{
auto& chainInfo = GetChainInfo(mainWindow);
bool stateChanged = chainInfo.m_shouldRecreate;
const auto configValue = (VSync)GetConfig().vsync.GetValue();
if(chainInfo.m_vsyncState != configValue){
if(chainInfo.m_vsyncState != configValue)
stateChanged = true;
const bool latteBufferUsesSRGB = mainWindow ? LatteGPUState.tvBufferUsesSRGB : LatteGPUState.drcBufferUsesSRGB;
if (chainInfo.m_usesSRGB != latteBufferUsesSRGB)
stateChanged = true;
if(stateChanged)
{
try
{
RecreateSwapchain(mainWindow);
chainInfo.m_vsyncState = configValue;
}
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)
@ -2857,7 +2854,7 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
renderPassInfo.renderPass = chainInfo.m_swapchainRenderPass;
renderPassInfo.framebuffer = chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex];
renderPassInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.extent = chainInfo.swapchainExtent;
renderPassInfo.renderArea.extent = chainInfo.getExtent();
renderPassInfo.clearValueCount = 0;
VkViewport viewport{};
@ -2870,7 +2867,7 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
vkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &viewport);
VkRect2D scissor{};
scissor.extent = chainInfo.swapchainExtent;
scissor.extent = chainInfo.getExtent();
vkCmdSetScissor(m_state.currentCommandBuffer, 0, 1, &scissor);
auto descriptSet = backbufferBlit_createDescriptorSet(m_swapchainDescriptorSetLayout, texViewVk, useLinearTexFilter);

View File

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

View File

@ -61,10 +61,4 @@ void VulkanCanvas::OnResize(wxSizeEvent& event)
const wxRect refreshRect(size);
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();
}
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();
@ -921,7 +921,7 @@ void ImGui_ImplVulkan_NewFrame(VkCommandBuffer command_buffer, VkFramebuffer fra
renderPassInfo.renderPass = g_RenderPass;
renderPassInfo.framebuffer = framebuffer;
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = extend;
renderPassInfo.renderArea.extent = extent;
renderPassInfo.clearValueCount = 0;
vkCmdBeginRenderPass(command_buffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
}

View File

@ -46,7 +46,7 @@ struct ImGui_ImplVulkan_InitInfo
// Called by user code
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_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 bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture();