diff options
Diffstat (limited to 'src/video_core/renderer_vulkan/vk_swapchain.cpp')
-rw-r--r-- | src/video_core/renderer_vulkan/vk_swapchain.cpp | 139 |
1 files changed, 74 insertions, 65 deletions
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 85fdce6e5..1e80ce463 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -14,6 +14,7 @@ #include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_wrapper.h" +#include "vulkan/vulkan_core.h" namespace Vulkan { @@ -33,23 +34,47 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats) return found != formats.end() ? *found : formats[0]; } -VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) { - // Mailbox (triple buffering) doesn't lock the application like fifo (vsync), - // prefer it if vsync option is not selected - const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); - if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Borderless && - found_mailbox != modes.end() && !Settings::values.use_vsync.GetValue()) { - return VK_PRESENT_MODE_MAILBOX_KHR; - } - if (!Settings::values.use_speed_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; +static constexpr VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox, + 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 + Settings::VSyncMode setting = [has_imm, has_mailbox]() { + // Choose Mailbox or Immediate if unlocked and those modes are supported + const auto mode = Settings::values.vsync_mode.GetValue(); + if (Settings::values.use_speed_limit.GetValue()) { + return mode; + } + switch (mode) { + case Settings::VSyncMode::FIFO: + case Settings::VSyncMode::FIFORelaxed: + if (has_mailbox) { + return Settings::VSyncMode::Mailbox; + } 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; } - return VK_PRESENT_MODE_FIFO_KHR; } VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height) { @@ -65,6 +90,18 @@ VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 wi return extent; } +VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& capabilities) { + if (capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) { + return VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + } else if (capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) { + return VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + } else { + LOG_ERROR(Render_Vulkan, "Unknown composite alpha flags value {:#x}", + capabilities.supportedCompositeAlpha); + return VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + } +} + } // Anonymous namespace Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, @@ -87,18 +124,16 @@ void Swapchain::Create(u32 width_, u32 height_, bool srgb) { return; } - device.GetLogical().WaitIdle(); Destroy(); CreateSwapchain(capabilities, srgb); CreateSemaphores(); - CreateImageViews(); resource_ticks.clear(); resource_ticks.resize(image_count); } -void Swapchain::AcquireNextImage() { +bool Swapchain::AcquireNextImage() { const VkResult result = device.GetLogical().AcquireNextImageKHR( *swapchain, std::numeric_limits<u64>::max(), *present_semaphores[frame_index], VK_NULL_HANDLE, &image_index); @@ -115,8 +150,11 @@ void Swapchain::AcquireNextImage() { LOG_ERROR(Render_Vulkan, "vkAcquireNextImageKHR returned {}", vk::ToString(result)); break; } + scheduler.Wait(resource_ticks[image_index]); resource_ticks[image_index] = scheduler.CurrentTick(); + + return is_suboptimal || is_outdated; } void Swapchain::Present(VkSemaphore render_semaphore) { @@ -131,6 +169,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) { .pImageIndices = &image_index, .pResults = nullptr, }; + std::scoped_lock lock{scheduler.submit_mutex}; switch (const VkResult result = present_queue.Present(present_info)) { case VK_SUCCESS: break; @@ -153,10 +192,17 @@ void Swapchain::Present(VkSemaphore render_semaphore) { void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) { const auto physical_device{device.GetPhysical()}; 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 VkSurfaceFormatKHR surface_format{ChooseSwapSurfaceFormat(formats)}; - present_mode = ChooseSwapPresentMode(present_modes); + const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)}; + surface_format = ChooseSwapSurfaceFormat(formats); + present_mode = ChooseSwapPresentMode(has_imm, has_mailbox, has_fifo_relaxed); u32 requested_image_count{capabilities.minImageCount + 1}; // Ensure Triple buffering if possible. @@ -180,12 +226,12 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo .imageColorSpace = surface_format.colorSpace, .imageExtent = {}, .imageArrayLayers = 1, - .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, .preTransform = capabilities.currentTransform, - .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .compositeAlpha = alpha_flags, .presentMode = present_mode, .clipped = VK_FALSE, .oldSwapchain = nullptr, @@ -217,7 +263,6 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo extent = swapchain_ci.imageExtent; current_srgb = srgb; - current_fps_unlocked = !Settings::values.use_speed_limit.GetValue(); images = swapchain.GetImages(); image_count = static_cast<u32>(images.size()); @@ -228,56 +273,20 @@ void Swapchain::CreateSemaphores() { present_semaphores.resize(image_count); std::ranges::generate(present_semaphores, [this] { return device.GetLogical().CreateSemaphore(); }); -} - -void Swapchain::CreateImageViews() { - VkImageViewCreateInfo ci{ - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .image = {}, - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = image_view_format, - .components = - { - .r = VK_COMPONENT_SWIZZLE_IDENTITY, - .g = VK_COMPONENT_SWIZZLE_IDENTITY, - .b = VK_COMPONENT_SWIZZLE_IDENTITY, - .a = VK_COMPONENT_SWIZZLE_IDENTITY, - }, - .subresourceRange = - { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - - image_views.resize(image_count); - for (std::size_t i = 0; i < image_count; i++) { - ci.image = images[i]; - image_views[i] = device.GetLogical().CreateImageView(ci); - } + render_semaphores.resize(image_count); + std::ranges::generate(render_semaphores, + [this] { return device.GetLogical().CreateSemaphore(); }); } void Swapchain::Destroy() { frame_index = 0; present_semaphores.clear(); - framebuffers.clear(); - image_views.clear(); swapchain.reset(); } -bool Swapchain::HasFpsUnlockChanged() const { - return current_fps_unlocked != !Settings::values.use_speed_limit.GetValue(); -} - bool Swapchain::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(); + const auto requested_mode = ChooseSwapPresentMode(has_imm, has_mailbox, has_fifo_relaxed); + return present_mode != requested_mode; } } // namespace Vulkan |