vk_swapchain: Use certain modes for unlocked

Uses mailbox, then immediate for unlocked framerate depending on
support for either. Also adds support for FIFO_RELAXED.

This function now assumes vsync_mode was originially configured to a value
that the driver supports.

vk_swapchain: ChooseSwapPresentMode determines updates

Simplifies swapchain a bit and allows us to change the present mode
during guest runtime.

vk_swapchain: Fix MSVC error

vk_swapchain: Enforce available present modes

Some frontends don't check the value of vsync_mode before comitting it.
Just as well, since a driver update or misconfiguration could problems
in the swap chain.

vk_swapchain: Silence warnings

Silences GCC warnings implicit-fallthrough and shadow, which apparently
are not enabled on clang.
merge-requests/60/head
lat9nq 2023-05-01 20:31:22 +07:00
parent a090a380be
commit 952b271092
2 changed files with 53 additions and 29 deletions

@ -14,6 +14,7 @@
#include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/renderer_vulkan/vk_swapchain.h"
#include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
#include "vulkan/vulkan_core.h"
namespace Vulkan { namespace Vulkan {
@ -33,24 +34,47 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats)
return found != formats.end() ? *found : formats[0]; return found != formats.end() ? *found : formats[0];
} }
VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) { static constexpr VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox,
// Mailbox (triple buffering) doesn't lock the application like FIFO (vsync) bool has_fifo_relaxed) {
// Mailbox doesn't lock the application like FIFO (vsync)
// FIFO present mode locks the framerate to the monitor's refresh rate // FIFO present mode locks the framerate to the monitor's refresh rate
const bool has_mailbox = Settings::VSyncMode setting = [has_imm, has_mailbox]() {
std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != modes.end(); // Choose Mailbox or Immediate if unlocked and those modes are supported
const bool has_imm = const auto mode = Settings::values.vsync_mode.GetValue();
std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR) != modes.end(); if (Settings::values.use_speed_limit.GetValue()) {
const Settings::VSyncMode mode = Settings::values.vsync_mode.GetValue(); return mode;
}
if (mode == Settings::VSyncMode::Immediate && has_imm) { switch (mode) {
LOG_INFO(Render_Vulkan, "Using swap present mode Immediate"); case Settings::VSyncMode::FIFO:
return VK_PRESENT_MODE_IMMEDIATE_KHR; case Settings::VSyncMode::FIFORelaxed:
} else if (mode == Settings::VSyncMode::Mailbox && has_mailbox) { if (has_mailbox) {
LOG_INFO(Render_Vulkan, "Using swap present mode Mailbox"); return Settings::VSyncMode::Mailbox;
return VK_PRESENT_MODE_MAILBOX_KHR; } else if (has_imm) {
return Settings::VSyncMode::Immediate;
}
[[fallthrough]];
default:
return mode;
}
}();
if ((setting == Settings::VSyncMode::Mailbox && !has_mailbox) ||
(setting == Settings::VSyncMode::Immediate && !has_imm) ||
(setting == Settings::VSyncMode::FIFORelaxed && !has_fifo_relaxed)) {
setting = Settings::VSyncMode::FIFO;
}
switch (setting) {
case Settings::VSyncMode::Immediate:
return VK_PRESENT_MODE_IMMEDIATE_KHR;
case Settings::VSyncMode::Mailbox:
return VK_PRESENT_MODE_MAILBOX_KHR;
case Settings::VSyncMode::FIFO:
return VK_PRESENT_MODE_FIFO_KHR;
case Settings::VSyncMode::FIFORelaxed:
return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
default:
return VK_PRESENT_MODE_FIFO_KHR;
} }
LOG_INFO(Render_Vulkan, "Using swap present mode FIFO");
return VK_PRESENT_MODE_FIFO_KHR;
} }
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height) { VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height) {
@ -168,11 +192,17 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) { void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) {
const auto physical_device{device.GetPhysical()}; const auto physical_device{device.GetPhysical()};
const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; const auto formats{physical_device.GetSurfaceFormatsKHR(surface)};
const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)}; const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface);
has_mailbox = std::find(present_modes.begin(), present_modes.end(),
VK_PRESENT_MODE_MAILBOX_KHR) != present_modes.end();
has_imm = std::find(present_modes.begin(), present_modes.end(),
VK_PRESENT_MODE_IMMEDIATE_KHR) != present_modes.end();
has_fifo_relaxed = std::find(present_modes.begin(), present_modes.end(),
VK_PRESENT_MODE_FIFO_RELAXED_KHR) != present_modes.end();
const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)}; const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)};
surface_format = ChooseSwapSurfaceFormat(formats); surface_format = ChooseSwapSurfaceFormat(formats);
present_mode = ChooseSwapPresentMode(present_modes); present_mode = ChooseSwapPresentMode(has_imm, has_mailbox, has_fifo_relaxed);
u32 requested_image_count{capabilities.minImageCount + 1}; u32 requested_image_count{capabilities.minImageCount + 1};
// Ensure Triple buffering if possible. // Ensure Triple buffering if possible.
@ -233,7 +263,6 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo
extent = swapchain_ci.imageExtent; extent = swapchain_ci.imageExtent;
current_srgb = srgb; current_srgb = srgb;
current_fps_unlocked = !Settings::values.use_speed_limit.GetValue();
images = swapchain.GetImages(); images = swapchain.GetImages();
image_count = static_cast<u32>(images.size()); image_count = static_cast<u32>(images.size());
@ -255,14 +284,9 @@ void Swapchain::Destroy() {
swapchain.reset(); swapchain.reset();
} }
bool Swapchain::HasFpsUnlockChanged() const {
return current_fps_unlocked != !Settings::values.use_speed_limit.GetValue();
}
bool Swapchain::NeedsPresentModeUpdate() const { bool Swapchain::NeedsPresentModeUpdate() const {
// Mailbox present mode is the ideal for all scenarios. If it is not available, const auto requested_mode = ChooseSwapPresentMode(has_imm, has_mailbox, has_fifo_relaxed);
// A different present mode is needed to support unlocked FPS above the monitor's refresh rate. return present_mode != requested_mode;
return present_mode != VK_PRESENT_MODE_MAILBOX_KHR && HasFpsUnlockChanged();
} }
} // namespace Vulkan } // namespace Vulkan

@ -116,8 +116,6 @@ private:
void Destroy(); void Destroy();
bool HasFpsUnlockChanged() const;
bool NeedsPresentModeUpdate() const; bool NeedsPresentModeUpdate() const;
const VkSurfaceKHR surface; const VkSurfaceKHR surface;
@ -142,9 +140,11 @@ private:
VkExtent2D extent{}; VkExtent2D extent{};
VkPresentModeKHR present_mode{}; VkPresentModeKHR present_mode{};
VkSurfaceFormatKHR surface_format{}; VkSurfaceFormatKHR surface_format{};
bool has_imm{false};
bool has_mailbox{false};
bool has_fifo_relaxed{false};
bool current_srgb{}; bool current_srgb{};
bool current_fps_unlocked{};
bool is_outdated{}; bool is_outdated{};
bool is_suboptimal{}; bool is_suboptimal{};
}; };