From 54986fb368c2c0dd3e67eb456fd7afb589d14e55 Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Tue, 10 Mar 2026 16:14:29 -0600 Subject: [PATCH 1/6] Update vsync param restriction to allow new modes --- src/vulkan.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/vulkan.cpp b/src/vulkan.cpp index ffadf255ac..1ae9127c47 100644 --- a/src/vulkan.cpp +++ b/src/vulkan.cpp @@ -1584,13 +1584,19 @@ static VkResult overlay_CreateSwapchainKHR( struct device_data *device_data = FIND(struct device_data, device); const auto& params = device_data->instance->params; - if (params.vsync < 4) { - VkPresentModeKHR target_present_mode = HUDElements.presentModes[params.vsync]; - if (is_present_mode_supported(device_data->physical_device, createInfo.surface, target_present_mode)) { - createInfo.presentMode = target_present_mode; - } - else { - SPDLOG_WARN("Present mode is not supported: {}", HUDElements.presentModeMap[target_present_mode]); + if ((int)params.vsync != -1) { + if (params.vsync < HUDElements.presentModes.size()) { + VkPresentModeKHR target_present_mode = HUDElements.presentModes[params.vsync]; + if (is_present_mode_supported(device_data->physical_device, createInfo.surface, target_present_mode)) { + createInfo.presentMode = target_present_mode; + } + else { + SPDLOG_WARN("Present mode is not supported: {}", HUDElements.presentModeMap[target_present_mode]); + } + } else { + SPDLOG_WARN( + "Ignoring out of range requested present mode: {} of (0 .. {})", + params.vsync, HUDElements.presentModes.size() - 1); } } From 997b17355dbc1b2a5a518b9349d53f66a9ee077e Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Sat, 14 Mar 2026 13:33:53 -0600 Subject: [PATCH 2/6] Fix Vulkan extension handling in overlay_CreateDevice The previous code modified an `enabled_extensions` vector in a loop but it had no effect because the modified vector was never reattached to a VkDeviceCreateInfo for the device creation call. This commit fixes the problem by appropriately creating a patched VkDeviceCreateInfo with the modified `enabled_extensions` vector. The loop logic is also refactored for clarity. --- src/vulkan.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/vulkan.cpp b/src/vulkan.cpp index 1ae9127c47..bfc0b4a212 100644 --- a/src/vulkan.cpp +++ b/src/vulkan.cpp @@ -23,6 +23,7 @@ #ifdef _WIN32 #include #endif +#include #include #include #include @@ -1857,27 +1858,31 @@ static VkResult overlay_CreateDevice( std::vector available_extensions(extension_count); instance_data->pd_vtable.EnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extension_count, available_extensions.data()); + auto has_extension = [](const auto& list, const char *name) { + return std::any_of(list.begin(), list.end(), [&](const auto& e) { + return e == std::string_view(name); + }); + }; + - bool can_get_driver_info = instance_data->api_version < VK_API_VERSION_1_1 ? false : true; + bool can_get_driver_info = false; - // VK_KHR_driver_properties became core in 1.2 - if (instance_data->api_version < VK_API_VERSION_1_2 && can_get_driver_info) { - for (auto& extension : available_extensions) { - if (extension.extensionName == std::string(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) { - for (auto& enabled : enabled_extensions) { - if (enabled == std::string(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) - goto DONT; + for (auto& extension : available_extensions) { + if (extension.extensionName == std::string_view(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) { + can_get_driver_info = true; + if (instance_data->api_version < VK_API_VERSION_1_2) { + if (!has_extension(enabled_extensions, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) { + enabled_extensions.push_back(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME); } - enabled_extensions.push_back(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME); - DONT: - goto FOUND; } } - can_get_driver_info = false; - FOUND:; } - VkResult result = fpCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice); + VkDeviceCreateInfo pCreateInfoPatched = *pCreateInfo; + pCreateInfoPatched.ppEnabledExtensionNames = enabled_extensions.data(); + pCreateInfoPatched.enabledExtensionCount = (uint32_t) enabled_extensions.size(); + + VkResult result = fpCreateDevice(physicalDevice, &pCreateInfoPatched, pAllocator, pDevice); if (result != VK_SUCCESS) return result; struct device_data *device_data = new_device_data(*pDevice, instance_data); From b4befe454af53340e38882af39f6ca648e7a1005 Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Tue, 10 Mar 2026 16:08:21 -0600 Subject: [PATCH 3/6] vulkan-headers: update from 1.3.283 to 1.4.345 This commit uses a local wrap for vulkan-headers 1.4.345 corresponding to an upstream PR for wrapdb which is not yet merged. --- .../packagefiles/vulkan-headers/meson.build | 15 +++++++++++++++ subprojects/vulkan-headers.wrap | 16 ++++++---------- 2 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 subprojects/packagefiles/vulkan-headers/meson.build diff --git a/subprojects/packagefiles/vulkan-headers/meson.build b/subprojects/packagefiles/vulkan-headers/meson.build new file mode 100644 index 0000000000..e5a5814c45 --- /dev/null +++ b/subprojects/packagefiles/vulkan-headers/meson.build @@ -0,0 +1,15 @@ +project( + 'vulkan-headers', + 'c', + license: 'Apache-2.0', + version: '1.4.345', + meson_version: '>=0.56.0', +) + +vulkan_api_xml = files('registry/vk.xml') + +vulkan_headers_dep = declare_dependency( + include_directories: include_directories('include'), +) + +meson.override_dependency('vulkanheaders', vulkan_headers_dep) diff --git a/subprojects/vulkan-headers.wrap b/subprojects/vulkan-headers.wrap index 938818f77d..bcf0870670 100644 --- a/subprojects/vulkan-headers.wrap +++ b/subprojects/vulkan-headers.wrap @@ -1,13 +1,9 @@ [wrap-file] -directory = Vulkan-Headers-1.3.283 -source_url = https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.3.283.tar.gz -source_filename = vulkan-headers-1.3.283.tar.gz -source_hash = a76ff77815012c76abc9811215c2167128a73a697bcc23948e858d1f7dd54a85 -patch_filename = vulkan-headers_1.3.283-1_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/vulkan-headers_1.3.283-1/get_patch -patch_hash = 00e30d35117ae90a19b5b8878746fceaf31b41778b817ca9e6b3ae6063be8233 -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/vulkan-headers_1.3.283-1/vulkan-headers-1.3.283.tar.gz -wrapdb_version = 1.3.283-1 +directory = Vulkan-Headers-1.4.345 +source_url = https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.4.345.tar.gz +source_filename = vulkan-headers-1.4.345.tar.gz +source_hash = 99e19205df172c33229f18b5574c9258bc73ea229ec7d6b04daa357b2430f6c8 +patch_directory = vulkan-headers [provide] -vulkanheaders = vulkan_headers_dep +dependency_names = vulkanheaders From 5c6fc6ec268c6e206b0186b639f5dceb88b90e23 Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Sat, 14 Mar 2026 13:40:46 -0600 Subject: [PATCH 4/6] Enable FIFO Latest Ready if supported This just enables the corresponding extension so that the present mode is exposed as available if supported. --- src/vulkan.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vulkan.cpp b/src/vulkan.cpp index bfc0b4a212..2d2386f34d 100644 --- a/src/vulkan.cpp +++ b/src/vulkan.cpp @@ -1876,6 +1876,11 @@ static VkResult overlay_CreateDevice( } } } + if (extension.extensionName == std::string_view(VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME)) { + if (!has_extension(enabled_extensions, VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME)) { + enabled_extensions.push_back(VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME); + } + } } VkDeviceCreateInfo pCreateInfoPatched = *pCreateInfo; From 428f7077d9bbe8f09264c9080b07b52a5dec3a79 Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Wed, 11 Mar 2026 10:43:50 -0600 Subject: [PATCH 5/6] Support VK_PRESENT_MODE_FIFO_LATEST_READY_KHR This commit adds support for setting the Vulkan present mode to VK_PRESENT_MODE_FIFO_LATEST_READY_KHR by specifying vsync=6. --- src/hud_elements.cpp | 2 +- src/hud_elements.h | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hud_elements.cpp b/src/hud_elements.cpp index e9e365dca5..e39427c1f4 100644 --- a/src/hud_elements.cpp +++ b/src/hud_elements.cpp @@ -1713,7 +1713,7 @@ void HudElements::present_mode() { ImguiNextColumnOrNewRow(); - right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.5f, "%s\n", HUDElements.get_present_mode().c_str()); + right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.75f, "%s\n", HUDElements.get_present_mode().c_str()); ImGui::PopFont(); } diff --git a/src/hud_elements.h b/src/hud_elements.h index 70deb51151..ea753c2141 100644 --- a/src/hud_elements.h +++ b/src/hud_elements.h @@ -151,13 +151,14 @@ class HudElements{ void TextColored(ImVec4 col, const char *fmt, ...); - std::array presentModes = { + std::array presentModes = { VK_PRESENT_MODE_FIFO_RELAXED_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, - VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR}; + VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, + VK_PRESENT_MODE_FIFO_LATEST_READY_KHR}; std::map presentModeMap = { {VK_PRESENT_MODE_IMMEDIATE_KHR, "IMMEDIATE"}, @@ -165,7 +166,8 @@ class HudElements{ {VK_PRESENT_MODE_FIFO_KHR, "FIFO"}, {VK_PRESENT_MODE_FIFO_RELAXED_KHR, "FIFO Relaxed"}, {VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, "DEMAND"}, - {VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, "CONTINUOUS"} + {VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, "CONTINUOUS"}, + {VK_PRESENT_MODE_FIFO_LATEST_READY_KHR, "FIFO Latest Ready"}, }; VkPresentModeKHR cur_present_mode; From 0d9cc8cc2b536c31896ecedba376479289ad8f0d Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Wed, 11 Mar 2026 10:44:54 -0600 Subject: [PATCH 6/6] Update README for Vulkan present modes --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 680d3478e8..f17a3c4716 100644 --- a/README.md +++ b/README.md @@ -497,10 +497,13 @@ Because comma is also used as option delimiter and needs to be escaped for value ### Vulkan Vsync -- `0` = Adaptive VSync (FIFO_RELAXED_KHR) +- `0` = Adaptive VSync (FIFO_RELAXED_KHR) (Tear-free when keeping pace, tears on missed Vblanks to minimize latency.) - `1` = Off (IMMEDIATE_KHR) -- `2` = Mailbox (VSync with uncapped FPS) (MAILBOX_KHR) +- `2` = Mailbox (MAILBOX_KHR) (VSync with uncapped FPS. Tear-free, low latency, no pacing guarantees.) - `3` = On (FIFO_KHR) +- `4` = (SHARED_DEMAND_REFRESH_KHR) (Shared image update, demand-driven refresh. Tearing, low-latency, no pacing guarantees. Rarely used.) +- `5` = (SHARED_CONTINUOUS_REFRESH_KHR) (Shared image update, continuous refresh. Tearing, low-latency, no pacing guarantees. Rarely used.) +- `6` = FIFO Latest Ready (FIFO_LATEST_READY_KHR) (VSync with uncapped FPS. Tear-free, low latency, improved pacing versus MAILBOX_KHR.) Not all vulkan vsync options may be supported on your device, you can check what your device supports here [vulkan.gpuinfo.org](https://vulkan.gpuinfo.org/listsurfacepresentmodes.php?platform=linux)