diff options
Diffstat (limited to 'src/video_core/renderer_vulkan')
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_scheduler.cpp | 19 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_scheduler.h | 7 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_swapchain.cpp | 29 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_swapchain.h | 11 |
5 files changed, 47 insertions, 21 deletions
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 9ff0a28cd..adb6b7a3b 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -149,7 +149,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); swapchain.Create(layout.width, layout.height, is_srgb); }; - if (swapchain.IsSubOptimal() || swapchain.HasColorSpaceChanged(is_srgb)) { + if (swapchain.NeedsRecreation(is_srgb)) { recreate_swapchain(); } bool is_outdated; diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 1d438787a..0c11c814f 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -43,17 +43,10 @@ VKScheduler::VKScheduler(const Device& device_, StateTracker& state_tracker_) command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} { AcquireNewChunk(); AllocateWorkerCommandBuffer(); - worker_thread = std::thread(&VKScheduler::WorkerThread, this); + worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(token); }); } -VKScheduler::~VKScheduler() { - { - std::lock_guard lock{work_mutex}; - quit = true; - } - work_cv.notify_all(); - worker_thread.join(); -} +VKScheduler::~VKScheduler() = default; void VKScheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { SubmitExecution(signal_semaphore, wait_semaphore); @@ -135,7 +128,7 @@ bool VKScheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) { return true; } -void VKScheduler::WorkerThread() { +void VKScheduler::WorkerThread(std::stop_token stop_token) { Common::SetCurrentThreadName("yuzu:VulkanWorker"); do { if (work_queue.empty()) { @@ -144,8 +137,8 @@ void VKScheduler::WorkerThread() { std::unique_ptr<CommandChunk> work; { std::unique_lock lock{work_mutex}; - work_cv.wait(lock, [this] { return !work_queue.empty() || quit; }); - if (quit) { + work_cv.wait(lock, stop_token, [this] { return !work_queue.empty(); }); + if (stop_token.stop_requested()) { continue; } work = std::move(work_queue.front()); @@ -158,7 +151,7 @@ void VKScheduler::WorkerThread() { } std::lock_guard reserve_lock{reserve_mutex}; chunk_reserve.push_back(std::move(work)); - } while (!quit); + } while (!stop_token.stop_requested()); } void VKScheduler::AllocateWorkerCommandBuffer() { diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 759ed5a48..bd22e4e83 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -187,7 +187,7 @@ private: GraphicsPipeline* graphics_pipeline = nullptr; }; - void WorkerThread(); + void WorkerThread(std::stop_token stop_token); void AllocateWorkerCommandBuffer(); @@ -212,7 +212,7 @@ private: vk::CommandBuffer current_cmdbuf; std::unique_ptr<CommandChunk> chunk; - std::thread worker_thread; + std::jthread worker_thread; State state; @@ -224,9 +224,8 @@ private: std::vector<std::unique_ptr<CommandChunk>> chunk_reserve; std::mutex reserve_mutex; std::mutex work_mutex; - std::condition_variable work_cv; + std::condition_variable_any work_cv; std::condition_variable wait_cv; - std::atomic_bool quit{}; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index aadf03cb0..8972a6921 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -9,6 +9,7 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "common/settings.h" #include "core/core.h" #include "core/frontend/framebuffer_layout.h" #include "video_core/renderer_vulkan/vk_scheduler.h" @@ -36,8 +37,19 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats) VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) { // Mailbox doesn't lock the application like fifo (vsync), prefer it - const auto found = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); - return found != modes.end() ? *found : VK_PRESENT_MODE_FIFO_KHR; + const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); + if (found_mailbox != modes.end()) { + return VK_PRESENT_MODE_MAILBOX_KHR; + } + if (Settings::values.disable_fps_limit.GetValue()) { + // FIFO present mode locks the framerate to the monitor's refresh rate, + // Find an alternative to surpass this limitation if FPS is unlocked. + const auto found_imm = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR); + if (found_imm != modes.end()) { + return VK_PRESENT_MODE_IMMEDIATE_KHR; + } + } + return VK_PRESENT_MODE_FIFO_KHR; } VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height) { @@ -143,7 +155,7 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)}; const VkSurfaceFormatKHR surface_format{ChooseSwapSurfaceFormat(formats)}; - const VkPresentModeKHR present_mode{ChooseSwapPresentMode(present_modes)}; + present_mode = ChooseSwapPresentMode(present_modes); u32 requested_image_count{capabilities.minImageCount + 1}; if (capabilities.maxImageCount > 0 && requested_image_count > capabilities.maxImageCount) { @@ -196,6 +208,7 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, extent = swapchain_ci.imageExtent; current_srgb = srgb; + current_fps_unlocked = Settings::values.disable_fps_limit.GetValue(); images = swapchain.GetImages(); image_count = static_cast<u32>(images.size()); @@ -248,4 +261,14 @@ void VKSwapchain::Destroy() { swapchain.reset(); } +bool VKSwapchain::HasFpsUnlockChanged() const { + return current_fps_unlocked != Settings::values.disable_fps_limit.GetValue(); +} + +bool VKSwapchain::NeedsPresentModeUpdate() const { + // Mailbox present mode is the ideal for all scenarios. If it is not available, + // A different present mode is needed to support unlocked FPS above the monitor's refresh rate. + return present_mode != VK_PRESENT_MODE_MAILBOX_KHR && HasFpsUnlockChanged(); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index 5bce41e21..61a6d959e 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h @@ -33,6 +33,11 @@ public: /// Presents the rendered image to the swapchain. void Present(VkSemaphore render_semaphore); + /// Returns true when the swapchain needs to be recreated. + bool NeedsRecreation(bool is_srgb) const { + return HasColorSpaceChanged(is_srgb) || IsSubOptimal() || NeedsPresentModeUpdate(); + } + /// Returns true when the color space has changed. bool HasColorSpaceChanged(bool is_srgb) const { return current_srgb != is_srgb; @@ -84,6 +89,10 @@ private: void Destroy(); + bool HasFpsUnlockChanged() const; + + bool NeedsPresentModeUpdate() const; + const VkSurfaceKHR surface; const Device& device; VKScheduler& scheduler; @@ -102,8 +111,10 @@ private: VkFormat image_view_format{}; VkExtent2D extent{}; + VkPresentModeKHR present_mode{}; bool current_srgb{}; + bool current_fps_unlocked{}; bool is_outdated{}; bool is_suboptimal{}; }; |
