From 052a04e610a38936b0e7d6100a8af8c8b90f7a4d Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Thu, 17 Sep 2026 02:20:40 -0400 Subject: [PATCH] Correcting some bugs on the vulkan async presentation thread --- .../renderer_vulkan/renderer_vulkan.cpp | 6 +++-- .../renderer_vulkan/vk_present_manager.cpp | 26 ++++++++++++++++++- .../renderer_vulkan/vk_present_manager.h | 10 ++++++- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 4fd4c0233b..27ca531186 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -217,13 +217,15 @@ void RendererVulkan::Composite(std::span framebu scheduler.RequestOutsideRenderPassOperationContext(); blit_swapchain.DrawToFrame(device, rasterizer, frame, framebuffers, - render_window.GetFramebufferLayout(), swapchain.GetImageCount(), + render_window.GetFramebufferLayout(), + present_manager.SwapchainImageCount(), swapchain.GetImageViewFormat()); #ifdef HAS_LSFG void(frame_gen.WantedGenerations(present_manager.MaxExtraFrames())); - frame_gen.Process(device, frame, swapchain.GetImageFormat(), GuestExtent(framebuffers)); + frame_gen.Process(device, frame, present_manager.SwapchainImageFormat(), + GuestExtent(framebuffers)); const size_t generated_frames = frame_gen.GeneratedFrameCount(); for (size_t generation = 0; generation < generated_frames; ++generation) { diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index d173a3ba5f..9298764546 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -23,6 +23,7 @@ namespace Vulkan { namespace { constexpr size_t MAX_FRAMES_IN_FLIGHT = 7; +constexpr u32 MAX_PRESENT_ATTEMPTS = 3; #ifdef HAS_LSFG static_assert(MAX_FRAMES_IN_FLIGHT <= LSFG_MAX_TARGETS); #endif @@ -372,12 +373,33 @@ void PresentManager::SetImageCount() { #else image_count = std::min(swapchain.GetImageCount(), MAX_FRAMES_IN_FLIGHT); #endif + swapchain_image_count = swapchain.GetImageCount(); + swapchain_image_format = swapchain.GetImageFormat(); +} + +void PresentManager::DiscardFrame(Frame* frame) { + static constexpr VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + const VkSemaphore render_ready = *frame->render_ready; + const VkSubmitInfo submit_info{ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = nullptr, + .waitSemaphoreCount = 1U, + .pWaitSemaphores = &render_ready, + .pWaitDstStageMask = &wait_stage, + .commandBufferCount = 0U, + .pCommandBuffers = nullptr, + .signalSemaphoreCount = 0U, + .pSignalSemaphores = nullptr, + }; + + std::scoped_lock submit_lock{scheduler.submit_mutex}; + void(device.GetGraphicsQueue().Submit(submit_info, *frame->present_done)); } void PresentManager::CopyToSwapchain(Frame* frame) { bool requires_recreation = false; - while (true) { + for (u32 attempt = 0; attempt < MAX_PRESENT_ATTEMPTS; ++attempt) { try { // Recreate surface and swapchain if needed. if (requires_recreation) { @@ -397,6 +419,8 @@ void PresentManager::CopyToSwapchain(Frame* frame) { requires_recreation = true; } } + + DiscardFrame(frame); } void PresentManager::CopyToSwapchainImpl(Frame* frame) { diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index 4741c55e61..ab2b76f10f 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -68,6 +69,9 @@ public: /// How many additional frames can be queued without stalling the render thread [[nodiscard]] size_t MaxExtraFrames() const; + [[nodiscard]] std::size_t SwapchainImageCount() const { return swapchain_image_count; } + [[nodiscard]] VkFormat SwapchainImageFormat() const { return swapchain_image_format; } + private: void PresentThread(std::stop_token token); @@ -77,6 +81,8 @@ private: void RecreateSwapchain(Frame* frame); + void DiscardFrame(Frame* frame); + void SetImageCount(); private: @@ -100,7 +106,9 @@ private: bool blit_supported; bool storage_supported; bool use_present_thread; - std::size_t image_count{}; + std::atomic image_count{}; + std::atomic swapchain_image_count{}; + std::atomic swapchain_image_format{}; }; } // namespace Vulkan