mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-26 02:54:17 +01:00
Vulkan: Further swapchain code improvements. (#473)
This commit is contained in:
parent
a0e69ffbbd
commit
4d68446f14
@ -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;
|
||||
|
@ -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{};
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user