mirror of
				https://github.com/PancakeTAS/lsfg-vk.git
				synced 2025-10-30 07:01:10 +00:00 
			
		
		
		
	Compare commits
	
		
			6 commits
		
	
	
		
			0a6455a381
			...
			5e04b4f5f6
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
							 | 
						5e04b4f5f6 | ||
| 
							 | 
						82fb53f089 | ||
| 
							 | 
						77c9cc632d | ||
| 
							 | 
						daa1e410eb | ||
| 
							 | 
						f8526a1fe3 | ||
| 
							 | 
						bfebf9b27e | 
					 21 changed files with 24439 additions and 298 deletions
				
			
		
							
								
								
									
										9
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,9 +0,0 @@
 | 
			
		|||
[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
 | 
			
		||||
| 
						 | 
				
			
			@ -12,9 +12,6 @@ add_compile_options(-fPIC
 | 
			
		|||
    -Wno-deprecated-declarations
 | 
			
		||||
    -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 +38,13 @@ 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
 | 
			
		||||
    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();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								include/extract/dll.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								include/extract/dll.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace DLL {
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    /// Parse all resources from a DLL file.
 | 
			
		||||
    ///
 | 
			
		||||
    /// *Shouldn't* cause any segmentation faults.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param filename Path to the DLL file.
 | 
			
		||||
    /// @return A map of resource IDs to their binary data.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @throws std::runtime_error on various failure points.
 | 
			
		||||
    ///
 | 
			
		||||
    std::unordered_map<uint32_t, std::vector<uint8_t>> parse_dll(const std::string& filename);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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())
 | 
			
		||||
    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");
 | 
			
		||||
        if (!gameTable.contains("exe"))
 | 
			
		||||
            throw std::runtime_error("Game override missing 'exe' field");
 | 
			
		||||
            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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										203
									
								
								src/extract/dll.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								src/extract/dll.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,203 @@
 | 
			
		|||
#include "extract/dll.hpp"
 | 
			
		||||
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <span>
 | 
			
		||||
 | 
			
		||||
/// DOS file header
 | 
			
		||||
struct DOSHeader {
 | 
			
		||||
    uint16_t magic; // 0x5A4D
 | 
			
		||||
    std::array<uint16_t, 29> pad;
 | 
			
		||||
    int32_t pe_offset; // file offset
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// PE header
 | 
			
		||||
struct PEHeader {
 | 
			
		||||
    uint32_t signature; // "PE\0\0"
 | 
			
		||||
    std::array<uint16_t, 1> pad1;
 | 
			
		||||
    uint16_t sect_count;
 | 
			
		||||
    std::array<uint16_t, 6> pad2;
 | 
			
		||||
    uint16_t opt_hdr_size;
 | 
			
		||||
    std::array<uint16_t, 1> pad3;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// (partial!) PE optional header
 | 
			
		||||
struct PEOptionalHeader {
 | 
			
		||||
    uint16_t magic; // 0x20B
 | 
			
		||||
    std::array<uint16_t, 63> pad4;
 | 
			
		||||
    std::pair<uint32_t, uint32_t> resource_table; // file offset/size
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Section header
 | 
			
		||||
struct SectionHeader {
 | 
			
		||||
    std::array<uint16_t, 4> pad1;
 | 
			
		||||
    uint32_t vsize; // virtual
 | 
			
		||||
    uint32_t vaddress;
 | 
			
		||||
    uint32_t fsize; // raw
 | 
			
		||||
    uint32_t foffset;
 | 
			
		||||
    std::array<uint16_t, 8> pad2;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Resource directory
 | 
			
		||||
struct ResourceDirectory {
 | 
			
		||||
    std::array<uint16_t, 6> pad;
 | 
			
		||||
    uint16_t name_count;
 | 
			
		||||
    uint16_t id_count;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Resource directory entry
 | 
			
		||||
struct ResourceDirectoryEntry {
 | 
			
		||||
    uint32_t id;
 | 
			
		||||
    uint32_t offset; // high bit = directory
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Resource data entry
 | 
			
		||||
struct ResourceDataEntry {
 | 
			
		||||
    uint32_t offset;
 | 
			
		||||
    uint32_t size;
 | 
			
		||||
    std::array<uint32_t, 2> pad;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container"
 | 
			
		||||
namespace {
 | 
			
		||||
    /// Safely cast a vector to a pointer of type T
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    const T* safe_cast(const std::vector<uint8_t>& data, size_t offset) {
 | 
			
		||||
        const size_t end = offset + sizeof(T);
 | 
			
		||||
        if (end > data.size() || end < offset)
 | 
			
		||||
            throw std::runtime_error("Buffer overflow during safe cast");
 | 
			
		||||
        return reinterpret_cast<const T*>(&data.at(offset));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Safely cast a vector to a span of T
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    std::span<const T> span_cast(const std::vector<uint8_t>& data, size_t offset, size_t count) {
 | 
			
		||||
        const size_t end = offset + (count * sizeof(T));
 | 
			
		||||
        if (end > data.size() || end < offset)
 | 
			
		||||
            throw std::runtime_error("Buffer overflow during safe cast");
 | 
			
		||||
        return std::span<const T>(reinterpret_cast<const T*>(&data.at(offset)), count);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
 | 
			
		||||
std::unordered_map<uint32_t, std::vector<uint8_t>> DLL::parse_dll(const std::string& filename) {
 | 
			
		||||
    std::ifstream file(filename, std::ios::binary | std::ios::ate);
 | 
			
		||||
    if (!file.is_open())
 | 
			
		||||
        throw std::runtime_error("Failed to open Lossless.dll");
 | 
			
		||||
 | 
			
		||||
    const auto size = file.tellg();
 | 
			
		||||
    file.seekg(0, std::ios::beg);
 | 
			
		||||
 | 
			
		||||
    std::vector<uint8_t> data(static_cast<size_t>(size));
 | 
			
		||||
    if (!file.read(reinterpret_cast<char*>(data.data()), size))
 | 
			
		||||
        throw std::runtime_error("Failed to read Lossless.dll");
 | 
			
		||||
 | 
			
		||||
    // parse dos header
 | 
			
		||||
    size_t fileOffset = 0;
 | 
			
		||||
    const auto* dosHdr = safe_cast<const DOSHeader>(data, 0);
 | 
			
		||||
    if (dosHdr->magic != 0x5A4D)
 | 
			
		||||
        throw std::runtime_error("Invalid DOS header magic number");
 | 
			
		||||
 | 
			
		||||
    // parse pe header
 | 
			
		||||
    fileOffset += static_cast<size_t>(dosHdr->pe_offset);
 | 
			
		||||
    const auto* peHdr = safe_cast<const PEHeader>(data, fileOffset);
 | 
			
		||||
    if (peHdr->signature != 0x00004550)
 | 
			
		||||
        throw std::runtime_error("Invalid PE header signature");
 | 
			
		||||
 | 
			
		||||
    // parse optional pe header
 | 
			
		||||
    fileOffset += sizeof(PEHeader);
 | 
			
		||||
    const auto* peOptHdr = safe_cast<const PEOptionalHeader>(data, fileOffset);
 | 
			
		||||
    if (peOptHdr->magic != 0x20B)
 | 
			
		||||
        throw std::runtime_error("Unsupported PE format (not PE32+)");
 | 
			
		||||
    const auto& [rsrc_rva, rsrc_size] = peOptHdr->resource_table;
 | 
			
		||||
 | 
			
		||||
    // locate section containing resources
 | 
			
		||||
    std::optional<size_t> rsrc_offset;
 | 
			
		||||
    fileOffset += peHdr->opt_hdr_size;
 | 
			
		||||
    const auto sectHdrs = span_cast<const SectionHeader>(data, fileOffset, peHdr->sect_count);
 | 
			
		||||
    for (const auto& sectHdr : sectHdrs) {
 | 
			
		||||
        if (rsrc_rva < sectHdr.vaddress || rsrc_rva > (sectHdr.vaddress + sectHdr.vsize))
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        rsrc_offset.emplace((rsrc_rva - sectHdr.vaddress) + sectHdr.foffset);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    if (!rsrc_offset)
 | 
			
		||||
        throw std::runtime_error("Failed to locate resource section");
 | 
			
		||||
 | 
			
		||||
    // parse resource directory
 | 
			
		||||
    fileOffset = rsrc_offset.value();
 | 
			
		||||
    const auto* rsrcDir = safe_cast<const ResourceDirectory>(data, fileOffset);
 | 
			
		||||
    if (rsrcDir->id_count < 3)
 | 
			
		||||
        throw std::runtime_error("Incorrect resource directory");
 | 
			
		||||
 | 
			
		||||
    // find resource table with data type
 | 
			
		||||
    std::optional<size_t> rsrc_tbl_offset;
 | 
			
		||||
    fileOffset = rsrc_offset.value() + sizeof(ResourceDirectory);
 | 
			
		||||
    const auto rsrcDirEntries = span_cast<const ResourceDirectoryEntry>(
 | 
			
		||||
        data, fileOffset, rsrcDir->name_count + rsrcDir->id_count);
 | 
			
		||||
    for (const auto& rsrcDirEntry : rsrcDirEntries) {
 | 
			
		||||
        if (rsrcDirEntry.id != 10) // RT_RCDATA
 | 
			
		||||
            continue;
 | 
			
		||||
        if ((rsrcDirEntry.offset & 0x80000000) == 0)
 | 
			
		||||
            throw std::runtime_error("Expected resource directory, but found data entry");
 | 
			
		||||
 | 
			
		||||
        rsrc_tbl_offset.emplace(rsrcDirEntry.offset & 0x7FFFFFFF);
 | 
			
		||||
    }
 | 
			
		||||
    if (!rsrc_tbl_offset)
 | 
			
		||||
        throw std::runtime_error("Failed to locate RT_RCDATA directory");
 | 
			
		||||
 | 
			
		||||
    // parse data type resource directory
 | 
			
		||||
    fileOffset = rsrc_offset.value() + rsrc_tbl_offset.value();
 | 
			
		||||
    const auto* rsrcTbl = safe_cast<const ResourceDirectory>(data, fileOffset);
 | 
			
		||||
    if (rsrcTbl->id_count < 1)
 | 
			
		||||
        throw std::runtime_error("Incorrect RT_RCDATA directory");
 | 
			
		||||
 | 
			
		||||
    // collect all resources
 | 
			
		||||
    fileOffset += sizeof(ResourceDirectory);
 | 
			
		||||
    const auto rsrcTblEntries = span_cast<const ResourceDirectoryEntry>(
 | 
			
		||||
        data, fileOffset, rsrcTbl->name_count + rsrcTbl->id_count);
 | 
			
		||||
    std::unordered_map<uint32_t, std::vector<uint8_t>> resources;
 | 
			
		||||
    for (const auto& rsrcTblEntry : rsrcTblEntries) {
 | 
			
		||||
        if ((rsrcTblEntry.offset & 0x80000000) == 0)
 | 
			
		||||
            throw std::runtime_error("Expected resource directory, but found data entry");
 | 
			
		||||
 | 
			
		||||
        // skip over language directory
 | 
			
		||||
        fileOffset = rsrc_offset.value() + (rsrcTblEntry.offset & 0x7FFFFFFF);
 | 
			
		||||
        const auto* langDir = safe_cast<const ResourceDirectory>(data, fileOffset);
 | 
			
		||||
        if (langDir->id_count < 1)
 | 
			
		||||
            throw std::runtime_error("Incorrect language directory");
 | 
			
		||||
 | 
			
		||||
        fileOffset += sizeof(ResourceDirectory);
 | 
			
		||||
        const auto* langDirEntry = safe_cast<const ResourceDirectoryEntry>(data, fileOffset);
 | 
			
		||||
        if ((langDirEntry->offset & 0x80000000) != 0)
 | 
			
		||||
            throw std::runtime_error("Expected resource data entry, but found directory");
 | 
			
		||||
 | 
			
		||||
        // parse resource data entry
 | 
			
		||||
        fileOffset = rsrc_offset.value() + (langDirEntry->offset & 0x7FFFFFFF);
 | 
			
		||||
        const auto* entry = safe_cast<const ResourceDataEntry>(data, fileOffset);
 | 
			
		||||
        if (entry->offset < rsrc_rva || entry->offset > (rsrc_rva + rsrc_size))
 | 
			
		||||
            throw std::runtime_error("Resource data entry points outside resource section");
 | 
			
		||||
 | 
			
		||||
        // extract resource
 | 
			
		||||
        std::vector<uint8_t> resource(entry->size);
 | 
			
		||||
        fileOffset = (entry->offset - rsrc_rva) + rsrc_offset.value();
 | 
			
		||||
        if (fileOffset + entry->size > data.size())
 | 
			
		||||
            throw std::runtime_error("Resource data entry points outside file");
 | 
			
		||||
        std::copy_n(&data.at(fileOffset), entry->size, resource.data());
 | 
			
		||||
        resources.emplace(rsrcTblEntry.id, std::move(resource));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return resources;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,16 +1,14 @@
 | 
			
		|||
#include "extract/extract.hpp"
 | 
			
		||||
#include "config/config.hpp"
 | 
			
		||||
#include "extract/dll.hpp"
 | 
			
		||||
 | 
			
		||||
#include <pe-parse/parse.h>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -73,22 +71,11 @@ const std::unordered_map<std::string, uint32_t> nameIdxTable = {{
 | 
			
		|||
}};
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
    auto& pshaders() {
 | 
			
		||||
    auto& shaders() {
 | 
			
		||||
        static std::unordered_map<uint32_t, std::array<std::vector<uint8_t>, 2>> shaderData;
 | 
			
		||||
        return shaderData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int on_resource(void* ptr, const peparse::resource& res) {
 | 
			
		||||
        if (res.type != peparse::RT_RCDATA || res.buf == nullptr || res.buf->bufLen <= 0)
 | 
			
		||||
            return 0;
 | 
			
		||||
        std::vector<uint8_t> resource_data(res.buf->bufLen);
 | 
			
		||||
        std::copy_n(res.buf->buf, res.buf->bufLen, resource_data.data());
 | 
			
		||||
 | 
			
		||||
        auto* shaders = reinterpret_cast<std::unordered_map<uint32_t, std::vector<uint8_t>>*>(ptr);
 | 
			
		||||
        shaders->emplace(res.name, std::move(resource_data));
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const std::vector<std::filesystem::path> PATHS{{
 | 
			
		||||
        ".local/share/Steam/steamapps/common",
 | 
			
		||||
        ".steam/steam/steamapps/common",
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +86,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
 | 
			
		||||
| 
						 | 
				
			
			@ -121,44 +108,39 @@ namespace {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void Extract::extractShaders() {
 | 
			
		||||
    if (!pshaders().empty())
 | 
			
		||||
    if (!shaders().empty())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    std::unordered_map<uint32_t, std::vector<uint8_t>> shaders{};
 | 
			
		||||
 | 
			
		||||
    // parse the dll
 | 
			
		||||
    peparse::parsed_pe* dll = peparse::ParsePEFromFile(getDllPath().c_str());
 | 
			
		||||
    if (!dll)
 | 
			
		||||
        throw std::runtime_error("Unable to read Lossless.dll, is it installed?");
 | 
			
		||||
    peparse::IterRsrc(dll, on_resource, reinterpret_cast<void*>(&shaders));
 | 
			
		||||
    peparse::DestructParsedPE(dll);
 | 
			
		||||
    const auto resources = DLL::parse_dll(getDllPath());
 | 
			
		||||
    std::cerr << "lsfg-vk: Extracted " << resources.size() << " resources from dll.\n";
 | 
			
		||||
 | 
			
		||||
    // ensure all shaders are present
 | 
			
		||||
    for (const auto& [name, idx] : nameIdxTable) {
 | 
			
		||||
        auto fp16 = shaders.find(idx);
 | 
			
		||||
        if (fp16 == shaders.end())
 | 
			
		||||
        auto fp16 = resources.find(idx);
 | 
			
		||||
        if (fp16 == resources.end())
 | 
			
		||||
            throw std::runtime_error("Shader not found: " + name + " (FP16).\n- Is Lossless Scaling up to date?");
 | 
			
		||||
        auto fp32 = shaders.find(idx + FP);
 | 
			
		||||
        if (fp32 == shaders.end())
 | 
			
		||||
        auto fp32 = resources.find(idx + FP);
 | 
			
		||||
        if (fp32 == resources.end())
 | 
			
		||||
            throw std::runtime_error("Shader not found: " + name + " (FP32).\n- Is Lossless Scaling up to date?");
 | 
			
		||||
 | 
			
		||||
        pshaders().emplace(idx, std::array<std::vector<uint8_t>, 2>{
 | 
			
		||||
            std::move(fp32->second),
 | 
			
		||||
            std::move(fp16->second)
 | 
			
		||||
        shaders().emplace(idx, std::array<std::vector<uint8_t>, 2>{
 | 
			
		||||
            fp32->second,
 | 
			
		||||
            fp16->second
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<uint8_t> Extract::getShader(const std::string& name, bool fp16) {
 | 
			
		||||
    if (pshaders().empty())
 | 
			
		||||
    if (shaders().empty())
 | 
			
		||||
        throw std::runtime_error("Shaders are not loaded.");
 | 
			
		||||
 | 
			
		||||
    auto hit = nameIdxTable.find(name);
 | 
			
		||||
    if (hit == nameIdxTable.end())
 | 
			
		||||
        throw std::runtime_error("Shader hash not found: " + name);
 | 
			
		||||
 | 
			
		||||
    auto sit = pshaders().find(hit->second);
 | 
			
		||||
    if (sit == pshaders().end())
 | 
			
		||||
    auto sit = shaders().find(hit->second);
 | 
			
		||||
    if (sit == shaders().end())
 | 
			
		||||
        throw std::runtime_error("Shader not found: " + name);
 | 
			
		||||
    return fp16 ? sit->second.at(1) : sit->second.at(0);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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/pe-parse
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								thirdparty/pe-parse
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
Subproject commit 31ac5966503689d5693cd9fb520bd525a8710e17
 | 
			
		||||
							
								
								
									
										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