From 6e86945dc848b5c1f6788adb6c6ca9588e5b1b1c Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Fri, 18 Jul 2025 00:22:10 +0200 Subject: [PATCH] add experimental flags for present mode and fps limit --- include/config/config.hpp | 12 ++++++++++-- src/config/config.cpp | 11 ++++++++++- src/context.cpp | 1 + src/hooks.cpp | 25 +++++++++++++++++++++---- src/main.cpp | 9 +++++++++ 5 files changed, 51 insertions(+), 7 deletions(-) diff --git a/include/config/config.hpp b/include/config/config.hpp index c46ff7c..2ffa67a 100644 --- a/include/config/config.hpp +++ b/include/config/config.hpp @@ -1,10 +1,13 @@ #pragma once -#include +#include + +#include #include +#include +#include #include #include -#include namespace Config { @@ -26,6 +29,11 @@ namespace Config { /// Whether HDR is enabled bool hdr{false}; + /// Experimental flag for overriding the synchronization method. + VkPresentModeKHR e_present; + /// Experimental flag for limiting the framerate of DXVK games. + uint32_t e_fps_limit; + /// Atomic property to check if the configuration is valid or outdated. std::shared_ptr valid; }; diff --git a/src/config/config.cpp b/src/config/config.cpp index f551bb3..589850f 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -1,6 +1,7 @@ #include "config/config.hpp" #include "common/exception.hpp" +#include #include #include #include @@ -209,7 +210,7 @@ bool Config::updateConfig(const std::string& file) { // parse global configuration const toml::value globalTable = toml::find_or_default(toml, "global"); - const Configuration global{ + Configuration global{ .enable = toml::find_or(globalTable, "enable", false), .dll = toml::find_or(globalTable, "dll", std::string()), .env = parse_env(toml::find_or(globalTable, "env", std::string())), @@ -217,6 +218,10 @@ bool Config::updateConfig(const std::string& file) { .flowScale = toml::find_or(globalTable, "flow_scale", 1.0F), .performance = toml::find_or(globalTable, "performance_mode", false), .hdr = toml::find_or(globalTable, "hdr_mode", false), + .e_present = into_present( + toml::find_or(globalTable, "experimental_present_mode", ""), + VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR), + .e_fps_limit = toml::find_or(globalTable, "experimental_fps_limit", 0U), .valid = globalConf.valid // use the same validity flag }; @@ -249,6 +254,10 @@ bool Config::updateConfig(const std::string& file) { .flowScale = toml::find_or(gameTable, "flow_scale", global.flowScale), .performance = toml::find_or(gameTable, "performance_mode", global.performance), .hdr = toml::find_or(gameTable, "hdr_mode", global.hdr), + .e_present = into_present( + toml::find_or(gameTable, "experimental_present_mode", ""), + global.e_present), + .e_fps_limit = toml::find_or(gameTable, "experimental_fps_limit", global.e_fps_limit), .valid = global.valid // only need a single validity flag }; diff --git a/src/context.cpp b/src/context.cpp index 481b7b4..080e6e8 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -51,6 +51,7 @@ LsContext::LsContext(const Hooks::DeviceInfo& info, VkSwapchainKHR swapchain, std::cerr << " Flow Scale: " << conf.flowScale << '\n'; std::cerr << " Performance Mode: " << (conf.performance ? "Enabled" : "Disabled") << '\n'; std::cerr << " HDR Mode: " << (conf.hdr ? "Enabled" : "Disabled") << '\n'; + if (conf.e_present != 2) std::cerr << " ! Present Mode: " << conf.e_present << '\n'; } // we could take the format from the swapchain, // but honestly this is safer. diff --git a/src/hooks.cpp b/src/hooks.cpp index 88e9427..c663d40 100644 --- a/src/hooks.cpp +++ b/src/hooks.cpp @@ -107,6 +107,7 @@ namespace { std::unordered_map swapchains; std::unordered_map swapchainToDeviceTable; + std::unordered_map swapchainToPresent; /// /// Adjust swapchain creation parameters and create a swapchain context. @@ -148,8 +149,8 @@ namespace { createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - // enforce vsync - createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; + // enforce present mode + createInfo.presentMode = Config::activeConf.e_present; // retire potential old swapchain if (pCreateInfo->oldSwapchain) { @@ -163,6 +164,8 @@ namespace { return res; // can't be caused by lsfg-vk (yet) try { + swapchainToPresent.emplace(*pSwapchain, createInfo.presentMode); + // get all swapchain images uint32_t imageCount{}; res = Layer::ovkGetSwapchainImagesKHR(device, *pSwapchain, &imageCount, nullptr); @@ -228,7 +231,16 @@ namespace { } auto& swapchain = it3->second; - // enforce vsync | NOLINTBEGIN + // find present mode + auto it4 = swapchainToPresent.find(*pPresentInfo->pSwapchains); + if (it4 == swapchainToPresent.end()) { + Utils::logLimitN("swapMap", 5, + "Swapchain present mode not found in map"); + return Layer::ovkQueuePresentKHR(queue, pPresentInfo); + } + auto& present = it4->second; + + // enforce present mode | NOLINTBEGIN #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" const VkSwapchainPresentModeInfoEXT* presentModeInfo = @@ -237,7 +249,7 @@ namespace { if (presentModeInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT) { for (size_t i = 0; i < presentModeInfo->swapchainCount; i++) const_cast(presentModeInfo->pPresentModes)[i] = - VK_PRESENT_MODE_FIFO_KHR; + present; } presentModeInfo = reinterpret_cast(presentModeInfo->pNext); @@ -252,6 +264,10 @@ namespace { if (!conf.valid->load(std::memory_order_relaxed)) return VK_ERROR_OUT_OF_DATE_KHR; + // ensure present mode is still valid + if (present != conf.e_present) + return VK_ERROR_OUT_OF_DATE_KHR; + // skip if disabled if (!conf.enable) return Layer::ovkQueuePresentKHR(queue, pPresentInfo); @@ -280,6 +296,7 @@ namespace { const VkAllocationCallbacks* pAllocator) noexcept { swapchains.erase(swapchain); swapchainToDeviceTable.erase(swapchain); + swapchainToPresent.erase(swapchain); Layer::ovkDestroySwapchainKHR(device, swapchain, pAllocator); } } diff --git a/src/main.cpp b/src/main.cpp index 8c4118a..6d96f95 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,6 +46,15 @@ namespace { std::cerr << " Flow Scale: " << conf.flowScale << '\n'; std::cerr << " Performance Mode: " << (conf.performance ? "Enabled" : "Disabled") << '\n'; std::cerr << " HDR Mode: " << (conf.hdr ? "Enabled" : "Disabled") << '\n'; + if (conf.e_present != 2) std::cerr << " ! Present Mode: " << conf.e_present << '\n'; + if (conf.e_fps_limit > 0) std::cerr << " ! FPS Limit: " << conf.e_fps_limit << '\n'; + + // update environment variables + unsetenv("MESA_VK_WSI_PRESENT_MODE"); // NOLINT + for (const auto& [key, value] : conf.env) + setenv(key.c_str(), value.c_str(), 1); // NOLINT + if (conf.e_fps_limit > 0) + setenv("DXVK_FRAME_RATE", std::to_string(conf.e_fps_limit).c_str(), 1); // NOLINT // load shaders try {