Compare commits

...

11 commits

Author SHA1 Message Date
Matt W. S.
0a6455a381
docs: update the readme page
Co-authored-by: strokesws <strokesws@gmail.com>
Co-authored-by: PancakeTAS <pancake@mgnet.work>
2025-08-13 23:01:50 +02:00
PancakeTAS
60baec1e26 feat(exe): fixing processes with space in their name 2025-08-13 20:49:42 +02:00
PancakeTAS
e09d590f2d feat(exe): present exe files in ui 2025-08-13 20:49:42 +02:00
PancakeTAS
7ddf1bdbde feat(exe): update c++ implementation to get exe 2025-08-13 20:49:42 +02:00
PancakeTAS
f5b55c7f83 feat(exe): remove pointless last file 2025-08-13 20:49:42 +02:00
PancakeTAS
938fe930b0 feat(exe): print process name rather than command name 2025-08-13 20:49:42 +02:00
PancakeTAS
62ce71e4d4 feat(exe): update default configuration 2025-08-13 20:49:42 +02:00
Rerence1016
26e4dc5827 feat(exe): fix comments, remove regex dependency 2025-08-13 20:49:42 +02:00
Rerence1016
ec59c072b5 feat(exe): use /proc/self/maps to get exe for ui and core lsfg-vk 2025-08-13 20:49:42 +02:00
Rerence1016
b899324b8c feat(exe): allow specifying games by their exe file 2025-08-13 20:49:42 +02:00
Rerence1016
bee751e16b feat(exe): add regex, find and use exe name for proton/wine processes in ui 2025-08-13 20:49:42 +02:00
7 changed files with 96 additions and 40 deletions

View file

@ -1,23 +1,46 @@
# lsfg-vk
Lossless Scaling is a Windows-exclusive app with the goal of bringing frame generation (among other features) to every single game or app.
lsfg-vk brings this frame generation to Linux users by acting as a Vulkan layer inbetween your game and your graphics card.
Lossless Scaling is a Windows-exclusive app bringing frame generation (among other features) to every single game or app.
## Installation
**lsfg-vk** brings this frame generation to Linux users by acting as a Vulkan layer inbetween your game and your graphics card.
lsfg-vk has been prebuilt to run on a variety of Linux distributions:
- Click [here](https://github.com/PancakeTAS/lsfg-vk/releases) to download lsfg-vk for your distribution
- Follow [this guide](https://github.com/PancakeTAS/lsfg-vk/wiki/Installation-Guide) if you need any more help.
## Getting Started
Once installed, open up the lsfg-vk Configuration Window from your application menu or by typing `lsfg-vk-ui` into the console.
For comprehensive instructions on setting up, configuring, and using **lsfg-vk**, please refer to the [Wiki](https://github.com/PancakeTAS/lsfg-vk/wiki).
Please see the [Wiki](https://github.com/PancakeTAS/lsfg-vk/wiki) for more information and join the [Discord](https://discord.gg/losslessscaling) for help (needs Steam verification).
### Installation
**lsfg-vk** is available as pre-built packages for various Linux distributions.
1. Visit the [Releases page](https://github.com/PancakeTAS/lsfg-vk/releases) to download the package for your Linux distribution.
2. Follow the step-by-step instructions in the [Installation Guide](https://github.com/PancakeTAS/lsfg-vk/wiki/Installation-Guide) for your specific distro.
### Configuration and Usage
After installation, you can open the graphical configuration editor **lsfg-vk-ui** from your application menu or by typing `lsfg-vk-ui` in your console.
* For detailed instructions on setting up your preferences, visit the [Configuring lsfg-vk](https://github.com/PancakeTAS/lsfg-vk/wiki/Configuring-lsfg%E2%80%90vk) page.
* Learn how to use **lsfg-vk**'s integrated benchmark on the [Using lsfg-vk's integrated benchmark](https://github.com/PancakeTAS/lsfg-vk/wiki/Using-lsfg%E2%80%90vk's-integrated-benchmark) page.
## Building from Source
If you prefer to build **lsfg-vk** yourself for development, debugging, or to use the latest and greatest features, a detailed build guide is available in the [Build Guide](https://github.com/PancakeTAS/lsfg-vk/wiki/Building-from-source) page.
## Support and Troubleshooting
If you encounter any issues or need assistance, please consult the following resources:
* **Quirks:** Before reporting any issues refer to the [Quirks](https://github.com/PancakeTAS/lsfg-vk/wiki/Quirks) page.
* **How to Ask for Help:** When creating a report, refer to the [How to ask for help](https://github.com/PancakeTAS/lsfg-vk/wiki/How-to-ask-for-help) page.
* **Discord:** Join the [Lossless Scaling Discord server](https://discord.gg/losslessscaling) for help (Steam verification required).
## Credits
Most of the project has still only been written by me, PancakeTAS, but I couldn't have done it without the help of these people:
- [0xNULLderef](https://github.com/0xNULLderef): Teaching me how to reverse engineer software.
- [Caliel666](https://github.com/Caliel666): Writing the initial draft of the user interface.
- [Samueru-sama](https://github.com/Samueru-sama): Helping with various things XDG as well as app images and testing.
- Other contributors: Thank you for your contribution!
* **0xNULLderef:** Teaching me how to reverse engineer software.
* **Caliel666:** Writing the initial draft of the user interface.
* **Samueru-sama:** Helping with various things XDG as well as app images and testing.
* Other contributors: Thank you for your contributions!
I'd also like to thank every single person sponsoring this project. Thanks to you I'll be able to invest more time into this and hopefully bring some cool new features to everyone.

View file

@ -32,7 +32,7 @@ multiplier = 4
performance_mode = false
[[game]] # override Genshin Impact
exe = "Genshin"
exe = "GenshinImpact.exe"
multiplier = 3
)";

View file

@ -51,7 +51,7 @@ LsContext::LsContext(const Hooks::DeviceInfo& info, VkSwapchainKHR swapchain,
LSFG_3_1::finalize();
// print config
std::cerr << "lsfg-vk: Reloaded configuration for " << name.second << ":\n";
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';

View file

@ -3,10 +3,7 @@
#include "utils/benchmark.hpp"
#include "utils/utils.hpp"
#include <unistd.h>
#include <exception>
#include <fstream>
#include <stdexcept>
#include <iostream>
#include <cstdint>
@ -34,7 +31,7 @@ namespace {
try {
Config::activeConf = Config::getConfig(name);
} catch (const std::exception& e) {
std::cerr << "lsfg-vk: The configuration for " << name.second << " is invalid, IGNORING:\n";
std::cerr << "lsfg-vk: The configuration for " << name.first << " is invalid, IGNORING:\n";
std::cerr << e.what() << '\n';
return; // default configuration will unload
}
@ -45,7 +42,7 @@ namespace {
return; // default configuration will unload
// print config
std::cerr << "lsfg-vk: Loaded configuration for " << name.second << ":\n";
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';
@ -57,22 +54,6 @@ namespace {
// remove mesa var in favor of config
unsetenv("MESA_VK_WSI_PRESENT_MODE"); // NOLINT
// write latest file
try {
std::ofstream latest("/tmp/lsfg-vk_last", std::ios::trunc);
if (!latest.is_open())
throw std::runtime_error("Failed to open /tmp/lsfg-vk_last for writing");
latest << "exe: " << name.first << '\n';
latest << "comm: " << name.second << '\n';
latest << "pid: " << getpid() << '\n';
if (!latest.good())
throw std::runtime_error("Failed to write to /tmp/lsfg-vk_last");
} catch (const std::exception& e) {
std::cerr << "lsfg-vk: An error occurred while trying to write the latest file, exiting:\n";
std::cerr << "- " << e.what() << '\n';
exit(EXIT_FAILURE);
}
// load shaders
try {
Extract::extractShaders();

View file

@ -209,20 +209,25 @@ 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
const char* benchmark_flag = std::getenv("LSFG_BENCHMARK");
if (benchmark_flag)
return { "benchmark", "benchmark" };
std::array<char, 4096> exe{};
// find executed binary
const ssize_t exe_len = readlink("/proc/self/exe", exe.data(), exe.size() - 1);
if (exe_len <= 0)
return { "Unknown Process", "unknown" };
exe.at(static_cast<size_t>(exe_len)) = '\0';
std::string exe_str(exe.data());
// find command name as well
std::ifstream comm_file("/proc/self/comm");
if (!comm_file.is_open())
return { std::string(exe.data()), "unknown" };
@ -233,7 +238,37 @@ std::pair<std::string, std::string> Utils::getProcessName() {
if (comm_str.back() == '\n')
comm_str.pop_back();
return{ std::string(exe.data()), comm_str };
// replace binary with exe for wine apps
if (exe_str.find("wine") != std::string::npos
|| exe_str.find("proton") != std::string::npos) {
std::ifstream proc_maps("/proc/self/maps");
if (!proc_maps.is_open())
return{ exe_str, comm_str };
std::string line;
while (std::getline(proc_maps, line)) {
if (!line.ends_with(".exe"))
continue;
size_t pos = line.find_first_of('/');
if (pos == std::string::npos) {
pos = line.find_last_of(' ');
if (pos == std::string::npos)
continue;
pos += 1; // skip space
}
const std::string exe_name = line.substr(pos);
if (exe_name.empty())
continue;
exe_str = exe_name;
break;
}
}
return{ exe_str, comm_str };
}
std::string Utils::getConfigFile() {

View file

@ -50,7 +50,7 @@ pub fn default_config() -> TomlConfig {
experimental_present_mode: PresentMode::Vsync,
},
TomlGame {
exe: String::from("Genshin"),
exe: String::from("GenshinImpact.exe"),
multiplier: Multiplier::from(3),
flow_scale: FlowScale::from(1.0),
performance_mode: false,

View file

@ -18,11 +18,28 @@ pub fn find_vulkan_processes() -> ProcResult<Vec<(String, String)>> {
continue;
}
// find executed binary
let mut exe = prc.exe()?.to_string_lossy().to_string();
// replace binary with exe for wine apps
if exe.contains("wine") || exe.contains("proton") {
let result = maps.iter()
.filter_map(|map| map.filename())
.map(|filename| filename.to_string_lossy().to_string())
.find(|filename| filename.ends_with(".exe"));
if let Some(exe_name) = result {
exe = exe_name;
}
}
// split off last part of the path
exe = exe.split('/').last().unwrap_or(&exe).to_string();
// format process information
let pid = prc.pid();
let name = prc.stat()?.comm;
let process_info = format!("PID {}: {}", pid, name);
processes.push((process_info, name));
let process_info = format!("PID {}: {}", pid, exe);
processes.push((process_info, exe));
}
Ok(processes)