enhancement(nodeps): remove toml11 dependency

This commit is contained in:
PancakeTAS 2025-08-21 01:40:01 +02:00 committed by Pancake
parent bfebf9b27e
commit f8526a1fe3
13 changed files with 18074 additions and 251 deletions

3
.gitmodules vendored
View file

@ -1,6 +1,3 @@
[submodule "thirdparty/pe-parse"] [submodule "thirdparty/pe-parse"]
path = thirdparty/pe-parse path = thirdparty/pe-parse
url = https://github.com/trailofbits/pe-parse url = https://github.com/trailofbits/pe-parse
[submodule "thirdparty/toml11"]
path = thirdparty/toml11
url = https://github.com/ToruNiina/toml11

View file

@ -13,7 +13,6 @@ add_compile_options(-fPIC
-Wno-unused-template) -Wno-unused-template)
add_subdirectory(thirdparty/pe-parse/pe-parser-library EXCLUDE_FROM_ALL) add_subdirectory(thirdparty/pe-parse/pe-parser-library EXCLUDE_FROM_ALL)
add_subdirectory(thirdparty/toml11 EXCLUDE_FROM_ALL)
add_subdirectory(framegen) add_subdirectory(framegen)
if(LSFGVK_EXCESS_DEBUG) if(LSFGVK_EXCESS_DEBUG)
@ -41,14 +40,12 @@ set_target_properties(lsfg-vk PROPERTIES
CXX_STANDARD 20 CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON) CXX_STANDARD_REQUIRED ON)
target_include_directories(lsfg-vk target_include_directories(lsfg-vk
PUBLIC include/thirdparty
PUBLIC include) PUBLIC include)
target_link_libraries(lsfg-vk PUBLIC target_link_libraries(lsfg-vk PUBLIC
pe-parse toml11 pe-parse
lsfg-vk-framegen) lsfg-vk-framegen)
get_target_property(TOML11_INCLUDE_DIRS toml11 INTERFACE_INCLUDE_DIRECTORIES)
target_include_directories(lsfg-vk SYSTEM PRIVATE ${TOML11_INCLUDE_DIRS})
# diagnostics # diagnostics
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set_target_properties(lsfg-vk PROPERTIES set_target_properties(lsfg-vk PROPERTIES

View file

@ -9,15 +9,21 @@
namespace Config { namespace Config {
/// lsfg-vk configuration /// Global lsfg-vk configuration.
struct Configuration { struct GlobalConfiguration {
/// Whether lsfg-vk should be loaded in the first place.
bool enable{false};
/// Path to Lossless.dll. /// Path to Lossless.dll.
std::string dll; std::string dll;
/// Whether FP16 is force-disabled /// Whether FP16 is force-disabled
bool no_fp16{false}; bool no_fp16{false};
/// Path to the configuration file.
std::filesystem::path config_file;
/// File timestamp of the configuration file
std::chrono::time_point<std::chrono::file_clock> timestamp;
};
/// Per-application lsfg-vk configuration.
struct GameConfiguration {
/// The frame generation muliplier /// The frame generation muliplier
size_t multiplier{2}; size_t multiplier{2};
/// The internal flow scale factor /// The internal flow scale factor
@ -28,35 +34,34 @@ namespace Config {
bool hdr{false}; bool hdr{false};
/// Experimental flag for overriding the synchronization method. /// Experimental flag for overriding the synchronization method.
VkPresentModeKHR e_present; VkPresentModeKHR e_present{ VK_PRESENT_MODE_FIFO_KHR };
/// Path to the configuration file.
std::filesystem::path config_file;
/// File timestamp of the configuration file
std::chrono::time_point<std::chrono::file_clock> timestamp;
}; };
/// Active configuration. Must be set in main.cpp. /// Global configuration.
extern Configuration activeConf; extern GlobalConfiguration globalConf;
/// Currently active configuration.
extern std::optional<GameConfiguration> currentConf;
/// ///
/// Read the configuration file while preserving the previous configuration /// Read the configuration file while preserving the previous configuration
/// in case of an error. /// in case of an error.
/// ///
/// @param file The path to the configuration file. /// @param file The path to the configuration file.
/// @param name The preset to activate
/// ///
/// @throws std::runtime_error if an error occurs while loading the configuration file. /// @throws std::runtime_error if an error occurs while loading the configuration file.
/// ///
void updateConfig(const std::string& file); void updateConfig(
const std::string& file,
const std::pair<std::string, std::string>& name
);
/// ///
/// Get the configuration for a game. /// Check if the configuration file is still up-to-date
/// ///
/// @param name The name of the executable to fetch. /// @return Whether the configuration is up-to-date or not.
/// @return The configuration for the game or global configuration.
/// ///
/// @throws std::runtime_error if the configuration is invalid. bool checkStatus();
///
Configuration getConfig(const std::pair<std::string, std::string>& name);
} }

17880
include/thirdparty/toml.hpp vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,16 +1,14 @@
#include "config/config.hpp" #include "config/config.hpp"
#include "common/exception.hpp" #include "common/exception.hpp"
#include "config/default_conf.hpp" #include "config/default_conf.hpp"
#include "utils/utils.hpp"
#include <vulkan/vulkan_core.h> #define TOML_ENABLE_FORMATTERS 0 // NOLINT
#include <toml11/find.hpp>
#include <toml11/parser.hpp>
#include <toml.hpp> #include <toml.hpp>
#include <unordered_map> #include <vulkan/vulkan_core.h>
#include <filesystem> #include <filesystem>
#include <algorithm>
#include <exception> #include <exception>
#include <stdexcept> #include <stdexcept>
#include <iostream> #include <iostream>
@ -18,16 +16,14 @@
#include <fstream> #include <fstream>
#include <cstdlib> #include <cstdlib>
#include <utility> #include <utility>
#include <chrono>
#include <thread>
#include <string> #include <string>
using namespace Config; using namespace Config;
namespace { GlobalConfiguration Config::globalConf{};
Configuration globalConf{}; std::optional<GameConfiguration> Config::currentConf{};
std::optional<std::unordered_map<std::string, Configuration>> gameConfs;
}
Configuration Config::activeConf{};
namespace { namespace {
/// Turn a string into a VkPresentModeKHR enum value. /// Turn a string into a VkPresentModeKHR enum value.
@ -42,7 +38,30 @@ namespace {
} }
} }
void Config::updateConfig(const std::string& file) { void Config::updateConfig(
const std::string& file,
const std::pair<std::string, std::string>& name) {
// process unchecked legacy environment variables
if (std::getenv("LSFG_LEGACY")) {
const char* dll = std::getenv("LSFG_DLL_PATH");
if (dll) globalConf.dll = std::string(dll);
currentConf.emplace();
const char* multiplier = std::getenv("LSFG_MULTIPLIER");
if (multiplier) currentConf->multiplier = std::stoul(multiplier);
const char* flow_scale = std::getenv("LSFG_FLOW_SCALE");
if (flow_scale) currentConf->flowScale = std::stof(flow_scale);
const char* performance = std::getenv("LSFG_PERFORMANCE_MODE");
if (performance) currentConf->performance = std::string(performance) == "1";
const char* hdr = std::getenv("LSFG_HDR_MODE");
if (hdr) currentConf->hdr = std::string(hdr) == "1";
const char* e_present = std::getenv("LSFG_EXPERIMENTAL_PRESENT_MODE");
if (e_present) currentConf->e_present = into_present(std::string(e_present));
return;
}
// ensure configuration file exists
if (!std::filesystem::exists(file)) { if (!std::filesystem::exists(file)) {
std::cerr << "lsfg-vk: Placing default configuration file at " << file << '\n'; std::cerr << "lsfg-vk: Placing default configuration file at " << file << '\n';
const auto parent = std::filesystem::path(file).parent_path(); const auto parent = std::filesystem::path(file).parent_path();
@ -58,105 +77,97 @@ void Config::updateConfig(const std::string& file) {
} }
// parse config file // parse config file
std::optional<toml::value> parsed; toml::table config{};
try { try {
parsed.emplace(toml::parse(file)); config = toml::parse_file(file);
if (!parsed->contains("version"))
throw std::runtime_error("Configuration file is missing 'version' field"); const auto* version = config.get_as<toml::value<int64_t>>("version");
if (parsed->at("version").as_integer() != 1) if (!version || *version != 1)
throw std::runtime_error("Configuration file version is not supported, expected 1"); throw std::runtime_error("Configuration file version is not supported, expected 1");
} catch (const std::exception& e) { } catch (const std::exception& e) {
throw LSFG::rethrowable_error("Unable to parse configuration file", e); throw LSFG::rethrowable_error("Unable to parse configuration file", e);
} }
auto& toml = *parsed;
// parse global configuration // parse global configuration
const toml::value globalTable = toml::find_or_default<toml::table>(toml, "global"); Config::globalConf = {
const Configuration global{
.dll = toml::find_or(globalTable, "dll", std::string()),
.no_fp16 = toml::find_or(globalTable, "no_fp16", false),
.config_file = file, .config_file = file,
.timestamp = std::filesystem::last_write_time(file) .timestamp = std::filesystem::last_write_time(file)
}; };
if (const auto* global = config.get_as<toml::table>("global")) {
// validate global configuration if (const auto* val = global->get_as<toml::value<std::string>>("dll"))
if (global.multiplier < 2) globalConf.dll = val->get();
throw std::runtime_error("Global Multiplier cannot be less than 2"); if (const auto* val = global->get_as<toml::value<bool>>("no_fp16"))
if (global.flowScale < 0.25F || global.flowScale > 1.0F) globalConf.no_fp16 = val->get();
throw std::runtime_error("Flow scale must be between 0.25 and 1.0"); }
// parse game-specific configuration // parse game-specific configuration
std::unordered_map<std::string, Configuration> games; std::optional<GameConfiguration> gameConf;
const toml::value gamesList = toml::find_or_default<toml::array>(toml, "game"); if (const auto* games = config["game"].as_array()) {
for (const auto& gameTable : gamesList.as_array()) { for (auto&& elem : *games) {
if (!gameTable.is_table()) if (!elem.is_table())
throw std::runtime_error("Invalid game configuration entry"); throw std::runtime_error("Invalid game configuration entry");
if (!gameTable.contains("exe")) const auto* game = elem.as_table();
throw std::runtime_error("Game override missing 'exe' field");
const std::string exe = toml::find<std::string>(gameTable, "exe"); const auto* exe = game->at("exe").value_or("?");
Configuration game{ if (!name.first.ends_with(exe) && name.second != exe)
.enable = true, continue;
.dll = global.dll,
.no_fp16 = global.no_fp16,
.multiplier = toml::find_or(gameTable, "multiplier", 2U),
.flowScale = toml::find_or(gameTable, "flow_scale", 1.0F),
.performance = toml::find_or(gameTable, "performance_mode", false),
.hdr = toml::find_or(gameTable, "hdr_mode", false),
.e_present = into_present(toml::find_or(gameTable, "experimental_present_mode", "")),
.config_file = file,
.timestamp = global.timestamp
};
// validate the configuration gameConf = Config::currentConf;
if (game.multiplier < 1) if (!gameConf.has_value()) gameConf.emplace();
throw std::runtime_error("Multiplier cannot be less than 1");
if (game.flowScale < 0.25F || game.flowScale > 1.0F) if (const auto* val = game->get_as<toml::value<int64_t>>("multiplier"))
throw std::runtime_error("Flow scale must be between 0.25 and 1.0"); gameConf->multiplier = static_cast<size_t>(val->get());
games[exe] = std::move(game); if (const auto* val = game->get_as<toml::value<double>>("flow_scale"))
gameConf->flowScale = static_cast<float>(val->get());
if (const auto* val = game->get_as<toml::value<bool>>("performance_mode"))
gameConf->performance = val->get();
if (const auto* val = game->get_as<toml::value<bool>>("hdr_mode"))
gameConf->hdr = val->get();
if (const auto* val = game->get_as<toml::value<std::string>>("experimental_present_mode"))
gameConf->e_present = into_present(val->get());
break;
}
} }
// store configurations if (!gameConf.has_value()) {
globalConf = global; Config::currentConf.reset();
gameConfs = std::move(games); std::cout << "lsfg-vk: Configuration entry disappeared, disabling.\n";
} return;
Configuration Config::getConfig(const std::pair<std::string, std::string>& name) {
// process legacy environment variables
if (std::getenv("LSFG_LEGACY")) {
Configuration conf{
.enable = true,
.multiplier = 2,
.flowScale = 1.0F,
.e_present = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR
};
const char* dll = std::getenv("LSFG_DLL_PATH");
if (dll) conf.dll = std::string(dll);
const char* multiplier = std::getenv("LSFG_MULTIPLIER");
if (multiplier) conf.multiplier = std::stoul(multiplier);
const char* flow_scale = std::getenv("LSFG_FLOW_SCALE");
if (flow_scale) conf.flowScale = std::stof(flow_scale);
const char* performance = std::getenv("LSFG_PERFORMANCE_MODE");
if (performance) conf.performance = std::string(performance) == "1";
const char* hdr = std::getenv("LSFG_HDR_MODE");
if (hdr) conf.hdr = std::string(hdr) == "1";
const char* e_present = std::getenv("LSFG_EXPERIMENTAL_PRESENT_MODE");
if (e_present) conf.e_present = into_present(std::string(e_present));
return conf;
} }
// process new configuration system Config::currentConf = *gameConf;
if (!gameConfs.has_value())
return globalConf;
const auto& games = *gameConfs; // print updated config info
auto it = std::ranges::find_if(games, [&name](const auto& pair) { std::cerr << "lsfg-vk: Loaded configuration for " << name.first << ":\n";
return name.first.ends_with(pair.first) || (name.second == pair.first); if (!globalConf.dll.empty()) std::cerr << " Using DLL from: " << globalConf.dll << '\n';
}); if (globalConf.no_fp16) std::cerr << " FP16 Acceleration: Force-disabled\n";
if (it != games.end()) std::cerr << " Multiplier: " << gameConf->multiplier << '\n';
return it->second; std::cerr << " Flow Scale: " << gameConf->flowScale << '\n';
std::cerr << " Performance Mode: " << (gameConf->performance ? "Enabled" : "Disabled") << '\n';
return globalConf; std::cerr << " HDR Mode: " << (gameConf->hdr ? "Enabled" : "Disabled") << '\n';
if (gameConf->e_present != 2) std::cerr << " ! Present Mode: " << gameConf->e_present << '\n';
}
bool Config::checkStatus() {
// check if config is up-to-date
auto& globalConf = Config::globalConf;
if (globalConf.config_file.empty())
return true;
if (!std::filesystem::exists(globalConf.config_file))
return true; // ignore deletion
if (std::filesystem::last_write_time(globalConf.config_file) == globalConf.timestamp)
return true;
// reload config
std::cerr << "lsfg-vk: Rereading configuration, as it is no longer valid.\n";
std::this_thread::sleep_for(std::chrono::milliseconds(73));
try {
Config::updateConfig(Utils::getConfigFile(), Utils::getProcessName());
} catch (const std::exception& e) {
std::cerr << "lsfg-vk: Failed to update configuration, continuing using old:\n";
std::cerr << "- " << e.what() << '\n';
}
return false;
} }

View file

@ -10,58 +10,23 @@
#include <lsfg_3_1.hpp> #include <lsfg_3_1.hpp>
#include <lsfg_3_1p.hpp> #include <lsfg_3_1p.hpp>
#include <filesystem> #include <stdexcept>
#include <exception>
#include <iostream>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <vector> #include <vector>
#include <chrono>
#include <memory> #include <memory>
#include <string> #include <string>
#include <thread>
#include <array> #include <array>
LsContext::LsContext(const Hooks::DeviceInfo& info, VkSwapchainKHR swapchain, LsContext::LsContext(const Hooks::DeviceInfo& info, VkSwapchainKHR swapchain,
VkExtent2D extent, const std::vector<VkImage>& swapchainImages) VkExtent2D extent, const std::vector<VkImage>& swapchainImages)
: swapchain(swapchain), swapchainImages(swapchainImages), : swapchain(swapchain), swapchainImages(swapchainImages),
extent(extent) { extent(extent) {
// get updated configuration if (!Config::currentConf.has_value())
auto& conf = Config::activeConf; throw std::runtime_error("No configuration set");
if (!conf.config_file.empty() auto& globalConf = Config::globalConf;
&& ( auto& conf = *Config::currentConf;
!std::filesystem::exists(conf.config_file)
|| conf.timestamp != std::filesystem::last_write_time(conf.config_file)
)) {
std::cerr << "lsfg-vk: Rereading configuration, as it is no longer valid.\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// reread configuration
const std::string file = Utils::getConfigFile();
const auto name = Utils::getProcessName();
try {
Config::updateConfig(file);
conf = Config::getConfig(name);
} catch (const std::exception& e) {
std::cerr << "lsfg-vk: Failed to update configuration, continuing using old:\n";
std::cerr << "- " << e.what() << '\n';
}
LSFG_3_1P::finalize();
LSFG_3_1::finalize();
// print config
std::cerr << "lsfg-vk: Reloaded configuration for " << name.first << ":\n";
if (!conf.dll.empty()) std::cerr << " Using DLL from: " << conf.dll << '\n';
if (conf.no_fp16) std::cerr << " FP16 Acceleration: Force-disabled\n";
std::cerr << " Multiplier: " << conf.multiplier << '\n';
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.multiplier <= 1) return;
}
// we could take the format from the swapchain, // we could take the format from the swapchain,
// but honestly this is safer. // but honestly this is safer.
const VkFormat format = conf.hdr const VkFormat format = conf.hdr
@ -99,7 +64,7 @@ LsContext::LsContext(const Hooks::DeviceInfo& info, VkSwapchainKHR swapchain,
lsfgInitialize( lsfgInitialize(
Utils::getDeviceUUID(info.physicalDevice), Utils::getDeviceUUID(info.physicalDevice),
conf.hdr, 1.0F / conf.flowScale, conf.multiplier - 1, conf.hdr, 1.0F / conf.flowScale, conf.multiplier - 1,
conf.no_fp16, globalConf.no_fp16,
Extract::getShader Extract::getShader
); );
@ -126,7 +91,10 @@ LsContext::LsContext(const Hooks::DeviceInfo& info, VkSwapchainKHR swapchain,
VkResult LsContext::present(const Hooks::DeviceInfo& info, const void* pNext, VkQueue queue, VkResult LsContext::present(const Hooks::DeviceInfo& info, const void* pNext, VkQueue queue,
const std::vector<VkSemaphore>& gameRenderSemaphores, uint32_t presentIdx) { const std::vector<VkSemaphore>& gameRenderSemaphores, uint32_t presentIdx) {
const auto& conf = Config::activeConf; if (!Config::currentConf.has_value())
throw std::runtime_error("No configuration set");
auto& conf = *Config::currentConf;
auto& pass = this->passInfos.at(this->frameIdx % 8); auto& pass = this->passInfos.at(this->frameIdx % 8);
// 1. copy swapchain image to frame_0/frame_1 // 1. copy swapchain image to frame_0/frame_1

View file

@ -99,7 +99,7 @@ namespace {
std::string getDllPath() { std::string getDllPath() {
// overriden path // overriden path
std::string dllPath = Config::activeConf.dll; std::string dllPath = Config::globalConf.dll;
if (!dllPath.empty()) if (!dllPath.empty())
return dllPath; return dllPath;
// home based paths // home based paths

View file

@ -8,7 +8,6 @@
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
#include <unordered_map> #include <unordered_map>
#include <filesystem>
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#include <exception> #include <exception>
@ -107,7 +106,6 @@ namespace {
std::unordered_map<VkSwapchainKHR, LsContext> swapchains; std::unordered_map<VkSwapchainKHR, LsContext> swapchains;
std::unordered_map<VkSwapchainKHR, VkDevice> swapchainToDeviceTable; std::unordered_map<VkSwapchainKHR, VkDevice> swapchainToDeviceTable;
std::unordered_map<VkSwapchainKHR, VkPresentModeKHR> swapchainToPresent;
/// ///
/// Adjust swapchain creation parameters and create a swapchain context. /// Adjust swapchain creation parameters and create a swapchain context.
@ -117,6 +115,21 @@ namespace {
const VkSwapchainCreateInfoKHR* pCreateInfo, const VkSwapchainCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator, const VkAllocationCallbacks* pAllocator,
VkSwapchainKHR* pSwapchain) noexcept { VkSwapchainKHR* pSwapchain) noexcept {
// retire potential old swapchain
if (pCreateInfo->oldSwapchain) {
swapchains.erase(pCreateInfo->oldSwapchain);
swapchainToDeviceTable.erase(pCreateInfo->oldSwapchain);
}
// ensure configuration is up to date
Config::checkStatus();
// return early if disabled
if (!Config::currentConf.has_value() || Config::currentConf->multiplier <= 1)
return Layer::ovkCreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
auto& conf = Config::currentConf;
// find device // find device
auto it = deviceToInfo.find(device); auto it = deviceToInfo.find(device);
if (it == deviceToInfo.end()) { if (it == deviceToInfo.end()) {
@ -150,13 +163,7 @@ namespace {
createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
// enforce present mode // enforce present mode
createInfo.presentMode = Config::activeConf.e_present; createInfo.presentMode = conf->e_present;
// retire potential old swapchain
if (pCreateInfo->oldSwapchain) {
swapchains.erase(pCreateInfo->oldSwapchain);
swapchainToDeviceTable.erase(pCreateInfo->oldSwapchain);
}
// create swapchain // create swapchain
auto res = Layer::ovkCreateSwapchainKHR(device, &createInfo, pAllocator, pSwapchain); auto res = Layer::ovkCreateSwapchainKHR(device, &createInfo, pAllocator, pSwapchain);
@ -164,8 +171,6 @@ namespace {
return res; // can't be caused by lsfg-vk (yet) return res; // can't be caused by lsfg-vk (yet)
try { try {
swapchainToPresent.emplace(*pSwapchain, createInfo.presentMode);
// get all swapchain images // get all swapchain images
uint32_t imageCount{}; uint32_t imageCount{};
res = Layer::ovkGetSwapchainImagesKHR(device, *pSwapchain, &imageCount, nullptr); res = Layer::ovkGetSwapchainImagesKHR(device, *pSwapchain, &imageCount, nullptr);
@ -205,6 +210,16 @@ namespace {
VkResult myvkQueuePresentKHR( VkResult myvkQueuePresentKHR(
VkQueue queue, VkQueue queue,
const VkPresentInfoKHR* pPresentInfo) noexcept { const VkPresentInfoKHR* pPresentInfo) noexcept {
// ensure configuration is up to date
if (!Config::checkStatus())
return VK_ERROR_OUT_OF_DATE_KHR;
// return early if disabled
if (!Config::currentConf.has_value() || Config::currentConf->multiplier <= 1)
return Layer::ovkQueuePresentKHR(queue, pPresentInfo);
auto& conf = Config::currentConf;
// find swapchain device // find swapchain device
auto it = swapchainToDeviceTable.find(*pPresentInfo->pSwapchains); auto it = swapchainToDeviceTable.find(*pPresentInfo->pSwapchains);
if (it == swapchainToDeviceTable.end()) { if (it == swapchainToDeviceTable.end()) {
@ -212,34 +227,28 @@ namespace {
"Swapchain not found in map"); "Swapchain not found in map");
return Layer::ovkQueuePresentKHR(queue, pPresentInfo); return Layer::ovkQueuePresentKHR(queue, pPresentInfo);
} }
Utils::resetLimitN("swapMap");
// find device info // find device info
auto it2 = deviceToInfo.find(it->second); auto it2 = deviceToInfo.find(it->second);
if (it2 == deviceToInfo.end()) { if (it2 == deviceToInfo.end()) {
Utils::logLimitN("swapMap", 5, Utils::logLimitN("deviceMap", 5,
"Device not found in map"); "Device not found in map");
return Layer::ovkQueuePresentKHR(queue, pPresentInfo); return Layer::ovkQueuePresentKHR(queue, pPresentInfo);
} }
Utils::resetLimitN("deviceMap");
auto& deviceInfo = it2->second; auto& deviceInfo = it2->second;
// find swapchain context // find swapchain context
auto it3 = swapchains.find(*pPresentInfo->pSwapchains); auto it3 = swapchains.find(*pPresentInfo->pSwapchains);
if (it3 == swapchains.end()) { if (it3 == swapchains.end()) {
Utils::logLimitN("swapMap", 5, Utils::logLimitN("swapCtxMap", 5,
"Swapchain context not found in map"); "Swapchain context not found in map");
return Layer::ovkQueuePresentKHR(queue, pPresentInfo); return Layer::ovkQueuePresentKHR(queue, pPresentInfo);
} }
Utils::resetLimitN("swapCtxMap");
auto& swapchain = it3->second; auto& swapchain = it3->second;
// 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 // enforce present mode | NOLINTBEGIN
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
@ -249,7 +258,7 @@ namespace {
if (presentModeInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT) { if (presentModeInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT) {
for (size_t i = 0; i < presentModeInfo->swapchainCount; i++) for (size_t i = 0; i < presentModeInfo->swapchainCount; i++)
const_cast<VkPresentModeKHR*>(presentModeInfo->pPresentModes)[i] = const_cast<VkPresentModeKHR*>(presentModeInfo->pPresentModes)[i] =
present; conf->e_present;
} }
presentModeInfo = presentModeInfo =
reinterpret_cast<const VkSwapchainPresentModeInfoEXT*>(presentModeInfo->pNext); reinterpret_cast<const VkSwapchainPresentModeInfoEXT*>(presentModeInfo->pNext);
@ -259,27 +268,6 @@ namespace {
// NOLINTEND | present the next frame // NOLINTEND | present the next frame
VkResult res{}; // might return VK_SUBOPTIMAL_KHR VkResult res{}; // might return VK_SUBOPTIMAL_KHR
try { try {
// ensure config is valid
auto& conf = Config::activeConf;
if (!conf.config_file.empty()
&& (
!std::filesystem::exists(conf.config_file)
|| conf.timestamp != std::filesystem::last_write_time(conf.config_file)
)) {
Layer::ovkQueuePresentKHR(queue, pPresentInfo);
return VK_ERROR_OUT_OF_DATE_KHR;
}
// ensure present mode is still valid
if (present != conf.e_present) {
Layer::ovkQueuePresentKHR(queue, pPresentInfo);
return VK_ERROR_OUT_OF_DATE_KHR;
}
// skip if disabled
if (conf.multiplier <= 1)
return Layer::ovkQueuePresentKHR(queue, pPresentInfo);
// present the swapchain // present the swapchain
std::vector<VkSemaphore> semaphores(pPresentInfo->waitSemaphoreCount); std::vector<VkSemaphore> semaphores(pPresentInfo->waitSemaphoreCount);
std::copy_n(pPresentInfo->pWaitSemaphores, semaphores.size(), semaphores.data()); std::copy_n(pPresentInfo->pWaitSemaphores, semaphores.size(), semaphores.data());
@ -304,7 +292,6 @@ namespace {
const VkAllocationCallbacks* pAllocator) noexcept { const VkAllocationCallbacks* pAllocator) noexcept {
swapchains.erase(swapchain); swapchains.erase(swapchain);
swapchainToDeviceTable.erase(swapchain); swapchainToDeviceTable.erase(swapchain);
swapchainToPresent.erase(swapchain);
Layer::ovkDestroySwapchainKHR(device, swapchain, pAllocator); Layer::ovkDestroySwapchainKHR(device, swapchain, pAllocator);
} }
} }

View file

@ -9,6 +9,7 @@
#include <unordered_map> #include <unordered_map>
#include <exception> #include <exception>
#include <iostream> #include <iostream>
#include <cstdlib>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
@ -103,7 +104,7 @@ namespace {
"Failed to get instance function pointer for vkCreateInstance"); "Failed to get instance function pointer for vkCreateInstance");
// NOLINTEND | skip initialization if the layer is disabled // NOLINTEND | skip initialization if the layer is disabled
if (!Config::activeConf.enable) { if (!Config::currentConf.has_value() || std::getenv("LSFG_BENCHMARK")) {
auto res = next_vkCreateInstance(pCreateInfo, pAllocator, pInstance); auto res = next_vkCreateInstance(pCreateInfo, pAllocator, pInstance);
initInstanceFunc(*pInstance, "vkCreateDevice", &next_vkCreateDevice); initInstanceFunc(*pInstance, "vkCreateDevice", &next_vkCreateDevice);
return res; return res;
@ -182,7 +183,7 @@ namespace {
next_vSetDeviceLoaderData = layerDesc2->u.pfnSetDeviceLoaderData; next_vSetDeviceLoaderData = layerDesc2->u.pfnSetDeviceLoaderData;
// NOLINTEND | skip initialization if the layer is disabled // NOLINTEND | skip initialization if the layer is disabled
if (!Config::activeConf.enable) if (!Config::currentConf.has_value() || std::getenv("LSFG_BENCHMARK"))
return next_vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice); return next_vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
// create device // create device
@ -262,7 +263,7 @@ PFN_vkVoidFunction layer_vkGetInstanceProcAddr(VkInstance instance, const char*
return it->second; return it->second;
it = Hooks::hooks.find(name); it = Hooks::hooks.find(name);
if (it != Hooks::hooks.end() && Config::activeConf.enable) if (it != Hooks::hooks.end() && (Config::currentConf.has_value() && !std::getenv("LSFG_BENCHMARK")))
return it->second; return it->second;
return next_vkGetInstanceProcAddr(instance, pName); return next_vkGetInstanceProcAddr(instance, pName);
@ -275,7 +276,7 @@ PFN_vkVoidFunction layer_vkGetDeviceProcAddr(VkDevice device, const char* pName)
return it->second; return it->second;
it = Hooks::hooks.find(name); it = Hooks::hooks.find(name);
if (it != Hooks::hooks.end() && Config::activeConf.enable) if (it != Hooks::hooks.end() && (Config::currentConf.has_value() && !std::getenv("LSFG_BENCHMARK")))
return it->second; return it->second;
return next_vkGetDeviceProcAddr(device, pName); return next_vkGetDeviceProcAddr(device, pName);

View file

@ -18,41 +18,17 @@ namespace {
std::cerr << std::unitbuf; std::cerr << std::unitbuf;
// read configuration // read configuration
const std::string file = Utils::getConfigFile();
try { try {
Config::updateConfig(file); Config::updateConfig(Utils::getConfigFile(), Utils::getProcessName());
} catch (const std::exception& e) { } catch (const std::exception& e) {
std::cerr << "lsfg-vk: An error occured while trying to parse the configuration, IGNORING:\n"; std::cerr << "lsfg-vk: An error occured while trying to parse the configuration, IGNORING:\n";
std::cerr << "- " << e.what() << '\n'; std::cerr << "- " << e.what() << '\n';
return; // default configuration will unload return;
}
const auto name = Utils::getProcessName();
try {
Config::activeConf = Config::getConfig(name);
} catch (const std::exception& e) {
std::cerr << "lsfg-vk: The configuration for " << name.first << " is invalid, IGNORING:\n";
std::cerr << e.what() << '\n';
return; // default configuration will unload
} }
// exit silently if not enabled // exit silently if not enabled
auto& conf = Config::activeConf; if (!Config::currentConf.has_value())
if (!conf.enable && name.second != "benchmark") return;
return; // default configuration will unload
// print config
std::cerr << "lsfg-vk: Loaded configuration for " << name.first << ":\n";
if (!conf.dll.empty()) std::cerr << " Using DLL from: " << conf.dll << '\n';
if (conf.no_fp16) std::cerr << " FP16 Acceleration: Force-disabled\n";
std::cerr << " Multiplier: " << conf.multiplier << '\n';
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';
// remove mesa var in favor of config
unsetenv("MESA_VK_WSI_PRESENT_MODE"); // NOLINT
// load shaders // load shaders
try { try {
@ -105,6 +81,5 @@ namespace {
} }
}); });
benchmark.detach(); benchmark.detach();
conf.enable = false;
} }
} }

View file

@ -19,7 +19,10 @@
using namespace Benchmark; using namespace Benchmark;
void Benchmark::run(uint32_t width, uint32_t height) { void Benchmark::run(uint32_t width, uint32_t height) {
const auto& conf = Config::activeConf; if (!Config::currentConf.has_value())
_exit(1); // not possible
const auto& globalConf = Config::globalConf;
const auto& conf = *Config::currentConf;
auto* lsfgInitialize = LSFG_3_1::initialize; auto* lsfgInitialize = LSFG_3_1::initialize;
auto* lsfgCreateContext = LSFG_3_1::createContext; auto* lsfgCreateContext = LSFG_3_1::createContext;
@ -41,7 +44,7 @@ void Benchmark::run(uint32_t width, uint32_t height) {
lsfgInitialize( lsfgInitialize(
deviceUUID, // some magic number if not given deviceUUID, // some magic number if not given
conf.hdr, 1.0F / conf.flowScale, conf.multiplier - 1, conf.hdr, 1.0F / conf.flowScale, conf.multiplier - 1,
conf.no_fp16, globalConf.no_fp16,
Extract::getShader Extract::getShader
); );
const int32_t ctx = lsfgCreateContext(-1, -1, {}, const int32_t ctx = lsfgCreateContext(-1, -1, {},

View file

@ -209,17 +209,17 @@ void Utils::resetLimitN(const std::string& id) noexcept {
} }
std::pair<std::string, std::string> Utils::getProcessName() { std::pair<std::string, std::string> Utils::getProcessName() {
// check override first // check benchmark flag
const char* process_name = std::getenv("LSFG_PROCESS");
if (process_name && *process_name != '\0')
return { process_name, process_name };
// then check benchmark flag
const char* benchmark_flag = std::getenv("LSFG_BENCHMARK"); const char* benchmark_flag = std::getenv("LSFG_BENCHMARK");
if (benchmark_flag) if (benchmark_flag)
return { "benchmark", "benchmark" }; return { "benchmark", "benchmark" };
std::array<char, 4096> exe{}; std::array<char, 4096> exe{};
// then check override
const char* process_name = std::getenv("LSFG_PROCESS");
if (process_name && *process_name != '\0')
return { process_name, process_name };
// find executed binary // find executed binary
const ssize_t exe_len = readlink("/proc/self/exe", exe.data(), exe.size() - 1); const ssize_t exe_len = readlink("/proc/self/exe", exe.data(), exe.size() - 1);
if (exe_len <= 0) if (exe_len <= 0)

1
thirdparty/toml11 vendored

@ -1 +0,0 @@
Subproject commit be08ba2be2a964edcdb3d3e3ea8d100abc26f286