mirror of
				https://github.com/PancakeTAS/lsfg-vk.git
				synced 2025-10-30 07:01:10 +00:00 
			
		
		
		
	Merge 2eec75e258 into 0a6455a381
				
					
				
			This commit is contained in:
		
						commit
						5c90229bf4
					
				
					 18 changed files with 24199 additions and 259 deletions
				
			
		
							
								
								
									
										6
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							|  | @ -1,9 +1,3 @@ | |||
| [submodule "thirdparty/pe-parse"] | ||||
| 	path = thirdparty/pe-parse | ||||
| 	url = https://github.com/trailofbits/pe-parse | ||||
| [submodule "thirdparty/toml11"] | ||||
| 	path = thirdparty/toml11 | ||||
| 	url = https://github.com/ToruNiina/toml11 | ||||
| [submodule "thirdparty/volk"] | ||||
| 	path = thirdparty/volk | ||||
| 	url = https://github.com/zeux/volk | ||||
|  |  | |||
|  | @ -13,8 +13,6 @@ add_compile_options(-fPIC | |||
|     -Wno-unused-template) | ||||
| 
 | ||||
| add_subdirectory(thirdparty/pe-parse/pe-parser-library EXCLUDE_FROM_ALL) | ||||
| add_subdirectory(thirdparty/toml11 EXCLUDE_FROM_ALL) | ||||
| add_subdirectory(thirdparty/volk EXCLUDE_FROM_ALL) | ||||
| add_subdirectory(framegen) | ||||
| 
 | ||||
| if(LSFGVK_EXCESS_DEBUG) | ||||
|  | @ -41,15 +39,14 @@ add_library(lsfg-vk SHARED ${SOURCES}) | |||
| set_target_properties(lsfg-vk PROPERTIES | ||||
|     CXX_STANDARD 20 | ||||
|     CXX_STANDARD_REQUIRED ON) | ||||
| target_include_directories(lsfg-vk SYSTEM | ||||
|     PUBLIC include/thirdparty) | ||||
| target_include_directories(lsfg-vk | ||||
|     PUBLIC include) | ||||
| target_link_libraries(lsfg-vk PUBLIC | ||||
|     pe-parse toml11 | ||||
|     pe-parse | ||||
|     lsfg-vk-framegen) | ||||
| 
 | ||||
| get_target_property(TOML11_INCLUDE_DIRS toml11 INTERFACE_INCLUDE_DIRECTORIES) | ||||
| target_include_directories(lsfg-vk SYSTEM PRIVATE ${TOML11_INCLUDE_DIRS}) | ||||
| 
 | ||||
| # diagnostics | ||||
| if(CMAKE_BUILD_TYPE STREQUAL "Debug") | ||||
|     set_target_properties(lsfg-vk PROPERTIES | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ endif() | |||
| 
 | ||||
| project(lsfg-vk-framegen | ||||
|     DESCRIPTION "Lossless Scaling Frame Generation Backend" | ||||
|     LANGUAGES CXX) | ||||
|     LANGUAGES C CXX) | ||||
| 
 | ||||
| file(GLOB SOURCES | ||||
|     "src/common/*.cpp" | ||||
|  | @ -29,6 +29,7 @@ file(GLOB SOURCES | |||
|     "v3.1p_src/shaders/*.cpp" | ||||
|     "v3.1p_src/utils/*.cpp" | ||||
|     "v3.1p_src/*.cpp" | ||||
|     "src/thirdparty/*.c" | ||||
| ) | ||||
| 
 | ||||
| add_library(lsfg-vk-framegen STATIC ${SOURCES}) | ||||
|  | @ -37,13 +38,13 @@ add_library(lsfg-vk-framegen STATIC ${SOURCES}) | |||
| set_target_properties(lsfg-vk-framegen PROPERTIES | ||||
|     CXX_STANDARD 20 | ||||
|     CXX_STANDARD_REQUIRED ON) | ||||
| target_include_directories(lsfg-vk-framegen SYSTEM | ||||
|     PUBLIC include/thirdparty) | ||||
| target_include_directories(lsfg-vk-framegen | ||||
|     PUBLIC include | ||||
|     PUBLIC public | ||||
|     PRIVATE v3.1_include | ||||
|     PRIVATE v3.1p_include) | ||||
| target_link_libraries(lsfg-vk-framegen | ||||
|     PUBLIC volk) | ||||
| 
 | ||||
| # diagnostics | ||||
| if(CMAKE_BUILD_TYPE STREQUAL "Debug") | ||||
|  |  | |||
							
								
								
									
										2647
									
								
								framegen/include/thirdparty/volk.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2647
									
								
								framegen/include/thirdparty/volk.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										3468
									
								
								framegen/src/thirdparty/volk.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3468
									
								
								framegen/src/thirdparty/volk.c
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -9,15 +9,21 @@ | |||
| 
 | ||||
| namespace Config { | ||||
| 
 | ||||
|     /// lsfg-vk configuration
 | ||||
|     struct Configuration { | ||||
|         /// Whether lsfg-vk should be loaded in the first place.
 | ||||
|         bool enable{false}; | ||||
|     /// Global lsfg-vk configuration.
 | ||||
|     struct GlobalConfiguration { | ||||
|         /// Path to Lossless.dll.
 | ||||
|         std::string dll; | ||||
|         /// Whether FP16 is force-disabled
 | ||||
|         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
 | ||||
|         size_t multiplier{2}; | ||||
|         /// The internal flow scale factor
 | ||||
|  | @ -28,35 +34,34 @@ namespace Config { | |||
|         bool hdr{false}; | ||||
| 
 | ||||
|         /// 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.
 | ||||
|     extern Configuration activeConf; | ||||
|     /// Global configuration.
 | ||||
|     extern GlobalConfiguration globalConf; | ||||
|     /// Currently active configuration.
 | ||||
|     extern std::optional<GameConfiguration> currentConf; | ||||
| 
 | ||||
|     ///
 | ||||
|     /// Read the configuration file while preserving the previous configuration
 | ||||
|     /// in case of an error.
 | ||||
|     ///
 | ||||
|     /// @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.
 | ||||
|     ///
 | ||||
|     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 The configuration for the game or global configuration.
 | ||||
|     /// @return Whether the configuration is up-to-date or not.
 | ||||
|     ///
 | ||||
|     /// @throws std::runtime_error if the configuration is invalid.
 | ||||
|     ///
 | ||||
|     Configuration getConfig(const std::pair<std::string, std::string>& name); | ||||
|     bool checkStatus(); | ||||
| 
 | ||||
| } | ||||
|  |  | |||
							
								
								
									
										17880
									
								
								include/thirdparty/toml.hpp
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17880
									
								
								include/thirdparty/toml.hpp
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,33 +1,30 @@ | |||
| #include "config/config.hpp" | ||||
| #include "common/exception.hpp" | ||||
| 
 | ||||
| #include "config/default_conf.hpp" | ||||
| #include "utils/utils.hpp" | ||||
| 
 | ||||
| #include <vulkan/vulkan_core.h> | ||||
| #include <toml11/find.hpp> | ||||
| #include <toml11/parser.hpp> | ||||
| #define TOML_ENABLE_FORMATTERS 0 // NOLINT
 | ||||
| #include <toml.hpp> | ||||
| 
 | ||||
| #include <unordered_map> | ||||
| #include <vulkan/vulkan_core.h> | ||||
| 
 | ||||
| #include <filesystem> | ||||
| #include <algorithm> | ||||
| #include <exception> | ||||
| #include <stdexcept> | ||||
| #include <iostream> | ||||
| #include <optional> | ||||
| #include <fstream> | ||||
| #include <cstdint> | ||||
| #include <cstdlib> | ||||
| #include <utility> | ||||
| #include <chrono> | ||||
| #include <thread> | ||||
| #include <string> | ||||
| 
 | ||||
| using namespace Config; | ||||
| 
 | ||||
| namespace { | ||||
|     Configuration globalConf{}; | ||||
|     std::optional<std::unordered_map<std::string, Configuration>> gameConfs; | ||||
| } | ||||
| 
 | ||||
| Configuration Config::activeConf{}; | ||||
| GlobalConfiguration Config::globalConf{}; | ||||
| std::optional<GameConfiguration> Config::currentConf{}; | ||||
| 
 | ||||
| namespace { | ||||
|     /// Turn a string into a VkPresentModeKHR enum value.
 | ||||
|  | @ -42,7 +39,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)) { | ||||
|         std::cerr << "lsfg-vk: Placing default configuration file at " << file << '\n'; | ||||
|         const auto parent = std::filesystem::path(file).parent_path(); | ||||
|  | @ -58,105 +78,97 @@ void Config::updateConfig(const std::string& file) { | |||
|     } | ||||
| 
 | ||||
|     // parse config file
 | ||||
|     std::optional<toml::value> parsed; | ||||
|     toml::table config{}; | ||||
|     try { | ||||
|         parsed.emplace(toml::parse(file)); | ||||
|         if (!parsed->contains("version")) | ||||
|             throw std::runtime_error("Configuration file is missing 'version' field"); | ||||
|         if (parsed->at("version").as_integer() != 1) | ||||
|         config = toml::parse_file(file); | ||||
| 
 | ||||
|         const auto* version = config.get_as<toml::value<int64_t>>("version"); | ||||
|         if (!version || *version != 1) | ||||
|             throw std::runtime_error("Configuration file version is not supported, expected 1"); | ||||
|     } catch (const std::exception& e) { | ||||
|         throw LSFG::rethrowable_error("Unable to parse configuration file", e); | ||||
|     } | ||||
|     auto& toml = *parsed; | ||||
| 
 | ||||
|     // parse global configuration
 | ||||
|     const toml::value globalTable = toml::find_or_default<toml::table>(toml, "global"); | ||||
|     const Configuration global{ | ||||
|         .dll =     toml::find_or(globalTable, "dll", std::string()), | ||||
|         .no_fp16 = toml::find_or(globalTable, "no_fp16", false), | ||||
|     Config::globalConf = { | ||||
|         .config_file = file, | ||||
|         .timestamp = std::filesystem::last_write_time(file) | ||||
|     }; | ||||
| 
 | ||||
|     // validate global configuration
 | ||||
|     if (global.multiplier < 2) | ||||
|         throw std::runtime_error("Global Multiplier cannot be less than 2"); | ||||
|     if (global.flowScale < 0.25F || global.flowScale > 1.0F) | ||||
|         throw std::runtime_error("Flow scale must be between 0.25 and 1.0"); | ||||
|     if (const auto* global = config.get_as<toml::table>("global")) { | ||||
|         if (const auto* val = global->get_as<toml::value<std::string>>("dll")) | ||||
|             globalConf.dll = val->get(); | ||||
|         if (const auto* val = global->get_as<toml::value<bool>>("no_fp16")) | ||||
|             globalConf.no_fp16 = val->get(); | ||||
|     } | ||||
| 
 | ||||
|     // parse game-specific configuration
 | ||||
|     std::unordered_map<std::string, Configuration> games; | ||||
|     const toml::value gamesList = toml::find_or_default<toml::array>(toml, "game"); | ||||
|     for (const auto& gameTable : gamesList.as_array()) { | ||||
|         if (!gameTable.is_table()) | ||||
|             throw std::runtime_error("Invalid game configuration entry"); | ||||
|         if (!gameTable.contains("exe")) | ||||
|             throw std::runtime_error("Game override missing 'exe' field"); | ||||
|     std::optional<GameConfiguration> gameConf; | ||||
|     if (const auto* games = config["game"].as_array()) { | ||||
|         for (auto&& elem : *games) { | ||||
|             if (!elem.is_table()) | ||||
|                 throw std::runtime_error("Invalid game configuration entry"); | ||||
|             const auto* game = elem.as_table(); | ||||
| 
 | ||||
|         const std::string exe = toml::find<std::string>(gameTable, "exe"); | ||||
|         Configuration game{ | ||||
|             .enable = true, | ||||
|             .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 | ||||
|         }; | ||||
|             const auto* exe = game->at("exe").value_or("?"); | ||||
|             if (!name.first.ends_with(exe) && name.second != exe) | ||||
|                 continue; | ||||
| 
 | ||||
|         // validate the configuration
 | ||||
|         if (game.multiplier < 1) | ||||
|             throw std::runtime_error("Multiplier cannot be less than 1"); | ||||
|         if (game.flowScale < 0.25F || game.flowScale > 1.0F) | ||||
|             throw std::runtime_error("Flow scale must be between 0.25 and 1.0"); | ||||
|         games[exe] = std::move(game); | ||||
|             gameConf = Config::currentConf; | ||||
|             if (!gameConf.has_value()) gameConf.emplace(); | ||||
| 
 | ||||
|             if (const auto* val = game->get_as<toml::value<int64_t>>("multiplier")) | ||||
|                 gameConf->multiplier = static_cast<size_t>(val->get()); | ||||
|             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
 | ||||
|     globalConf = global; | ||||
|     gameConfs = std::move(games); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
|     if (!gameConf.has_value()) { | ||||
|         Config::currentConf.reset(); | ||||
|         std::cerr << "lsfg-vk: Configuration entry disappeared, disabling.\n"; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // process new configuration system
 | ||||
|     if (!gameConfs.has_value()) | ||||
|         return globalConf; | ||||
|     Config::currentConf = *gameConf; | ||||
| 
 | ||||
|     const auto& games = *gameConfs; | ||||
|     auto it = std::ranges::find_if(games, [&name](const auto& pair) { | ||||
|         return name.first.ends_with(pair.first) || (name.second == pair.first); | ||||
|     }); | ||||
|     if (it != games.end()) | ||||
|         return it->second; | ||||
| 
 | ||||
|     return globalConf; | ||||
|     // print updated config info
 | ||||
|     std::cerr << "lsfg-vk: Loaded configuration for " << name.first << ":\n"; | ||||
|     if (!globalConf.dll.empty()) std::cerr << "  Using DLL from: " << globalConf.dll << '\n'; | ||||
|     if (globalConf.no_fp16) std::cerr << "  FP16 Acceleration: Force-disabled\n"; | ||||
|     std::cerr << "  Multiplier: " << gameConf->multiplier << '\n'; | ||||
|     std::cerr << "  Flow Scale: " << gameConf->flowScale << '\n'; | ||||
|     std::cerr << "  Performance Mode: " << (gameConf->performance ? "Enabled" : "Disabled") << '\n'; | ||||
|     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; | ||||
| } | ||||
|  |  | |||
|  | @ -10,58 +10,23 @@ | |||
| #include <lsfg_3_1.hpp> | ||||
| #include <lsfg_3_1p.hpp> | ||||
| 
 | ||||
| #include <filesystem> | ||||
| #include <exception> | ||||
| #include <iostream> | ||||
| #include <stdexcept> | ||||
| #include <cstdint> | ||||
| #include <cstdlib> | ||||
| #include <vector> | ||||
| #include <chrono> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <thread> | ||||
| #include <array> | ||||
| 
 | ||||
| LsContext::LsContext(const Hooks::DeviceInfo& info, VkSwapchainKHR swapchain, | ||||
|         VkExtent2D extent, const std::vector<VkImage>& swapchainImages) | ||||
|         : swapchain(swapchain), swapchainImages(swapchainImages), | ||||
|           extent(extent) { | ||||
|     // get updated configuration
 | ||||
|     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) | ||||
|             )) { | ||||
|         std::cerr << "lsfg-vk: Rereading configuration, as it is no longer valid.\n"; | ||||
|         std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||||
|     if (!Config::currentConf.has_value()) | ||||
|         throw std::runtime_error("No configuration set"); | ||||
|     auto& globalConf = Config::globalConf; | ||||
|     auto& conf = *Config::currentConf; | ||||
| 
 | ||||
|         // 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,
 | ||||
|     // but honestly this is safer.
 | ||||
|     const VkFormat format = conf.hdr | ||||
|  | @ -99,7 +64,7 @@ LsContext::LsContext(const Hooks::DeviceInfo& info, VkSwapchainKHR swapchain, | |||
|     lsfgInitialize( | ||||
|         Utils::getDeviceUUID(info.physicalDevice), | ||||
|         conf.hdr, 1.0F / conf.flowScale, conf.multiplier - 1, | ||||
|         conf.no_fp16, | ||||
|         globalConf.no_fp16, | ||||
|         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, | ||||
|         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); | ||||
| 
 | ||||
|     // 1. copy swapchain image to frame_0/frame_1
 | ||||
|  |  | |||
|  | @ -99,7 +99,7 @@ namespace { | |||
| 
 | ||||
|     std::string getDllPath() { | ||||
|         // overriden path
 | ||||
|         std::string dllPath = Config::activeConf.dll; | ||||
|         std::string dllPath = Config::globalConf.dll; | ||||
|         if (!dllPath.empty()) | ||||
|             return dllPath; | ||||
|         // home based paths
 | ||||
|  |  | |||
|  | @ -8,7 +8,6 @@ | |||
| #include <vulkan/vulkan_core.h> | ||||
| 
 | ||||
| #include <unordered_map> | ||||
| #include <filesystem> | ||||
| #include <stdexcept> | ||||
| #include <algorithm> | ||||
| #include <exception> | ||||
|  | @ -107,7 +106,6 @@ namespace { | |||
| 
 | ||||
|     std::unordered_map<VkSwapchainKHR, LsContext> swapchains; | ||||
|     std::unordered_map<VkSwapchainKHR, VkDevice> swapchainToDeviceTable; | ||||
|     std::unordered_map<VkSwapchainKHR, VkPresentModeKHR> swapchainToPresent; | ||||
| 
 | ||||
|     ///
 | ||||
|     /// Adjust swapchain creation parameters and create a swapchain context.
 | ||||
|  | @ -117,6 +115,21 @@ namespace { | |||
|             const VkSwapchainCreateInfoKHR* pCreateInfo, | ||||
|             const VkAllocationCallbacks* pAllocator, | ||||
|             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
 | ||||
|         auto it = deviceToInfo.find(device); | ||||
|         if (it == deviceToInfo.end()) { | ||||
|  | @ -150,13 +163,7 @@ namespace { | |||
|         createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; | ||||
| 
 | ||||
|         // enforce present mode
 | ||||
|         createInfo.presentMode = Config::activeConf.e_present; | ||||
| 
 | ||||
|         // retire potential old swapchain
 | ||||
|         if (pCreateInfo->oldSwapchain) { | ||||
|             swapchains.erase(pCreateInfo->oldSwapchain); | ||||
|             swapchainToDeviceTable.erase(pCreateInfo->oldSwapchain); | ||||
|         } | ||||
|         createInfo.presentMode = conf->e_present; | ||||
| 
 | ||||
|         // create swapchain
 | ||||
|         auto res = Layer::ovkCreateSwapchainKHR(device, &createInfo, pAllocator, pSwapchain); | ||||
|  | @ -164,8 +171,6 @@ 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); | ||||
|  | @ -205,6 +210,16 @@ namespace { | |||
|     VkResult myvkQueuePresentKHR( | ||||
|             VkQueue queue, | ||||
|             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
 | ||||
|         auto it = swapchainToDeviceTable.find(*pPresentInfo->pSwapchains); | ||||
|         if (it == swapchainToDeviceTable.end()) { | ||||
|  | @ -212,34 +227,28 @@ namespace { | |||
|                 "Swapchain not found in map"); | ||||
|             return Layer::ovkQueuePresentKHR(queue, pPresentInfo); | ||||
|         } | ||||
|         Utils::resetLimitN("swapMap"); | ||||
| 
 | ||||
|         // find device info
 | ||||
|         auto it2 = deviceToInfo.find(it->second); | ||||
|         if (it2 == deviceToInfo.end()) { | ||||
|             Utils::logLimitN("swapMap", 5, | ||||
|             Utils::logLimitN("deviceMap", 5, | ||||
|                 "Device not found in map"); | ||||
|             return Layer::ovkQueuePresentKHR(queue, pPresentInfo); | ||||
|         } | ||||
|         Utils::resetLimitN("deviceMap"); | ||||
|         auto& deviceInfo = it2->second; | ||||
| 
 | ||||
|         // find swapchain context
 | ||||
|         auto it3 = swapchains.find(*pPresentInfo->pSwapchains); | ||||
|         if (it3 == swapchains.end()) { | ||||
|             Utils::logLimitN("swapMap", 5, | ||||
|             Utils::logLimitN("swapCtxMap", 5, | ||||
|                 "Swapchain context not found in map"); | ||||
|             return Layer::ovkQueuePresentKHR(queue, pPresentInfo); | ||||
|         } | ||||
|         Utils::resetLimitN("swapCtxMap"); | ||||
|         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
 | ||||
|         #pragma clang diagnostic push | ||||
|         #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" | ||||
|  | @ -249,7 +258,7 @@ namespace { | |||
|             if (presentModeInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT) { | ||||
|                 for (size_t i = 0; i < presentModeInfo->swapchainCount; i++) | ||||
|                     const_cast<VkPresentModeKHR*>(presentModeInfo->pPresentModes)[i] = | ||||
|                         present; | ||||
|                         conf->e_present; | ||||
|             } | ||||
|             presentModeInfo = | ||||
|                 reinterpret_cast<const VkSwapchainPresentModeInfoEXT*>(presentModeInfo->pNext); | ||||
|  | @ -259,27 +268,6 @@ namespace { | |||
|         // NOLINTEND | present the next frame
 | ||||
|         VkResult res{}; // might return VK_SUBOPTIMAL_KHR
 | ||||
|         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
 | ||||
|             std::vector<VkSemaphore> semaphores(pPresentInfo->waitSemaphoreCount); | ||||
|             std::copy_n(pPresentInfo->pWaitSemaphores, semaphores.size(), semaphores.data()); | ||||
|  | @ -304,7 +292,6 @@ namespace { | |||
|             const VkAllocationCallbacks* pAllocator) noexcept { | ||||
|         swapchains.erase(swapchain); | ||||
|         swapchainToDeviceTable.erase(swapchain); | ||||
|         swapchainToPresent.erase(swapchain); | ||||
|         Layer::ovkDestroySwapchainKHR(device, swapchain, pAllocator); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include <unordered_map> | ||||
| #include <exception> | ||||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
| 
 | ||||
|  | @ -103,7 +104,7 @@ namespace { | |||
|                     "Failed to get instance function pointer for vkCreateInstance"); | ||||
| 
 | ||||
|             // 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); | ||||
|                 initInstanceFunc(*pInstance, "vkCreateDevice", &next_vkCreateDevice); | ||||
|                 return res; | ||||
|  | @ -182,7 +183,7 @@ namespace { | |||
|             next_vSetDeviceLoaderData = layerDesc2->u.pfnSetDeviceLoaderData; | ||||
| 
 | ||||
|             // 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); | ||||
| 
 | ||||
|             // create device
 | ||||
|  | @ -262,7 +263,7 @@ PFN_vkVoidFunction layer_vkGetInstanceProcAddr(VkInstance instance, const char* | |||
|         return it->second; | ||||
| 
 | ||||
|     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 next_vkGetInstanceProcAddr(instance, pName); | ||||
|  | @ -275,7 +276,7 @@ PFN_vkVoidFunction layer_vkGetDeviceProcAddr(VkDevice device, const char* pName) | |||
|         return it->second; | ||||
| 
 | ||||
|     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 next_vkGetDeviceProcAddr(device, pName); | ||||
|  |  | |||
							
								
								
									
										33
									
								
								src/main.cpp
									
										
									
									
									
								
							
							
						
						
									
										33
									
								
								src/main.cpp
									
										
									
									
									
								
							|  | @ -18,41 +18,17 @@ namespace { | |||
|         std::cerr << std::unitbuf; | ||||
| 
 | ||||
|         // read configuration
 | ||||
|         const std::string file = Utils::getConfigFile(); | ||||
|         try { | ||||
|             Config::updateConfig(file); | ||||
|             Config::updateConfig(Utils::getConfigFile(), Utils::getProcessName()); | ||||
|         } catch (const std::exception& e) { | ||||
|             std::cerr << "lsfg-vk: An error occured while trying to parse the configuration, IGNORING:\n"; | ||||
|             std::cerr << "- " << e.what() << '\n'; | ||||
|             return; // default configuration will unload
 | ||||
|         } | ||||
| 
 | ||||
|         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
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // exit silently if not enabled
 | ||||
|         auto& conf = Config::activeConf; | ||||
|         if (!conf.enable && name.second != "benchmark") | ||||
|             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
 | ||||
|         if (!Config::currentConf.has_value()) | ||||
|             return; | ||||
| 
 | ||||
|         // load shaders
 | ||||
|         try { | ||||
|  | @ -105,6 +81,5 @@ namespace { | |||
|             } | ||||
|         }); | ||||
|         benchmark.detach(); | ||||
|         conf.enable = false; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -19,7 +19,10 @@ | |||
| using namespace Benchmark; | ||||
| 
 | ||||
| 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* lsfgCreateContext = LSFG_3_1::createContext; | ||||
|  | @ -41,7 +44,7 @@ void Benchmark::run(uint32_t width, uint32_t height) { | |||
|     lsfgInitialize( | ||||
|         deviceUUID, // some magic number if not given
 | ||||
|         conf.hdr, 1.0F / conf.flowScale, conf.multiplier - 1, | ||||
|         conf.no_fp16, | ||||
|         globalConf.no_fp16, | ||||
|         Extract::getShader | ||||
|     ); | ||||
|     const int32_t ctx = lsfgCreateContext(-1, -1, {}, | ||||
|  |  | |||
|  | @ -209,17 +209,17 @@ void Utils::resetLimitN(const std::string& id) noexcept { | |||
| } | ||||
| 
 | ||||
| std::pair<std::string, std::string> Utils::getProcessName() { | ||||
|     // check override first
 | ||||
|     const char* process_name = std::getenv("LSFG_PROCESS"); | ||||
|     if (process_name && *process_name != '\0') | ||||
|         return { process_name, process_name }; | ||||
| 
 | ||||
|     // then check benchmark flag
 | ||||
|     // check benchmark flag
 | ||||
|     const char* benchmark_flag = std::getenv("LSFG_BENCHMARK"); | ||||
|     if (benchmark_flag) | ||||
|         return { "benchmark", "benchmark" }; | ||||
|     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
 | ||||
|     const ssize_t exe_len = readlink("/proc/self/exe", exe.data(), exe.size() - 1); | ||||
|     if (exe_len <= 0) | ||||
|  |  | |||
|  | @ -5,6 +5,10 @@ if(NOT LSFGVK_EXCESS_DEBUG) | |||
|     set(CMAKE_CXX_VISIBILITY_PRESET "hidden") | ||||
| endif() | ||||
| 
 | ||||
| if(LSFGVK_EXCESS_DEBUG) | ||||
|     add_compile_definitions(LSFGVK_EXCESS_DEBUG) | ||||
| endif() | ||||
| 
 | ||||
| project(lsfg-vk-test | ||||
|     DESCRIPTION "Test: lsfg-vk" | ||||
|     LANGUAGES CXX) | ||||
|  |  | |||
							
								
								
									
										1
									
								
								thirdparty/toml11
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								thirdparty/toml11
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +0,0 @@ | |||
| Subproject commit be08ba2be2a964edcdb3d3e3ea8d100abc26f286 | ||||
							
								
								
									
										1
									
								
								thirdparty/volk
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								thirdparty/volk
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +0,0 @@ | |||
| Subproject commit be3dbd49bf77052665e96b6c7484af855e7e5f67 | ||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Pancake
						Pancake