summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_vulkan/vk_swapchain.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp139
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