1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
import os
import zipfile
import shutil
import tempfile
from typing import Dict, Any
import decky
class InstallationService:
"""Service for handling lsfg-vk installation and uninstallation"""
def __init__(self):
self.user_home = os.path.expanduser("~")
self.local_lib_dir = os.path.join(self.user_home, ".local", "lib")
self.local_share_dir = os.path.join(self.user_home, ".local", "share", "vulkan", "implicit_layer.d")
self.lsfg_script_path = os.path.join(self.user_home, "lsfg")
# File paths
self.lib_file = os.path.join(self.local_lib_dir, "liblsfg-vk.so")
self.json_file = os.path.join(self.local_share_dir, "VkLayer_LS_frame_generation.json")
async def install(self) -> Dict[str, Any]:
"""Install lsfg-vk by extracting the zip file to ~/.local"""
try:
# Get the path to the lsfg-vk_archlinux.zip file in the bin directory
plugin_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
zip_path = os.path.join(plugin_dir, "bin", "lsfg-vk_archlinux.zip")
# Check if the zip file exists
if not os.path.exists(zip_path):
decky.logger.error(f"lsfg-vk_archlinux.zip not found at {zip_path}")
return {"success": False, "error": "lsfg-vk_archlinux.zip file not found"}
# Create directories if they don't exist
os.makedirs(self.local_lib_dir, exist_ok=True)
os.makedirs(self.local_share_dir, exist_ok=True)
# Extract the zip file
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
# Use /tmp for temporary extraction since we may not have write permissions in plugin dir
with tempfile.TemporaryDirectory() as temp_dir:
zip_ref.extractall(temp_dir)
# Look for the extracted files and copy them to the correct locations
for root, dirs, files in os.walk(temp_dir):
for file in files:
src_file = os.path.join(root, file)
if file.endswith('.so'):
# Copy library files to ~/.local/lib
dst_file = os.path.join(self.local_lib_dir, file)
shutil.copy2(src_file, dst_file)
decky.logger.info(f"Copied {file} to {dst_file}")
elif file.endswith('.json'):
# Copy JSON files to ~/.local/share/vulkan/implicit_layer.d
dst_file = os.path.join(self.local_share_dir, file)
shutil.copy2(src_file, dst_file)
decky.logger.info(f"Copied {file} to {dst_file}")
# Create the lsfg script
self._create_lsfg_script()
decky.logger.info("lsfg-vk installed successfully")
return {"success": True, "message": "lsfg-vk installed successfully"}
except Exception as e:
decky.logger.error(f"Error installing lsfg-vk: {str(e)}")
return {"success": False, "error": str(e)}
def _create_lsfg_script(self):
"""Create the lsfg script in home directory"""
script_content = """#!/bin/bash
export ENABLE_LSFG=1
export LSFG_MULTIPLIER=2
export LSFG_FLOW_SCALE=1.0
# export LSFG_HDR=1
# export LSFG_PERF_MODE=1
# export MESA_VK_WSI_PRESENT_MODE=immediate # - disable vsync
# Execute the passed command with the environment variables set
exec "$@"
"""
with open(self.lsfg_script_path, 'w') as script_file:
script_file.write(script_content)
# Make the script executable
os.chmod(self.lsfg_script_path, 0o755)
decky.logger.info(f"Created executable lsfg script at {self.lsfg_script_path}")
async def check_installation(self) -> Dict[str, Any]:
"""Check if lsfg-vk is already installed"""
try:
lib_exists = os.path.exists(self.lib_file)
json_exists = os.path.exists(self.json_file)
script_exists = os.path.exists(self.lsfg_script_path)
decky.logger.info(f"Installation check: lib={lib_exists}, json={json_exists}, script={script_exists}")
return {
"installed": lib_exists and json_exists,
"lib_exists": lib_exists,
"json_exists": json_exists,
"script_exists": script_exists,
"lib_path": self.lib_file,
"json_path": self.json_file,
"script_path": self.lsfg_script_path
}
except Exception as e:
decky.logger.error(f"Error checking lsfg-vk installation: {str(e)}")
return {"installed": False, "error": str(e)}
async def uninstall(self) -> Dict[str, Any]:
"""Uninstall lsfg-vk by removing the installed files"""
try:
removed_files = []
# Remove library file if it exists
if os.path.exists(self.lib_file):
os.remove(self.lib_file)
removed_files.append(self.lib_file)
decky.logger.info(f"Removed {self.lib_file}")
# Remove JSON file if it exists
if os.path.exists(self.json_file):
os.remove(self.json_file)
removed_files.append(self.json_file)
decky.logger.info(f"Removed {self.json_file}")
# Remove lsfg script if it exists
if os.path.exists(self.lsfg_script_path):
os.remove(self.lsfg_script_path)
removed_files.append(self.lsfg_script_path)
decky.logger.info(f"Removed {self.lsfg_script_path}")
if not removed_files:
return {"success": True, "message": "No lsfg-vk files found to remove"}
decky.logger.info("lsfg-vk uninstalled successfully")
return {
"success": True,
"message": f"lsfg-vk uninstalled successfully. Removed {len(removed_files)} files.",
"removed_files": removed_files
}
except Exception as e:
decky.logger.error(f"Error uninstalling lsfg-vk: {str(e)}")
return {"success": False, "error": str(e)}
def cleanup_on_uninstall(self) -> None:
"""Clean up lsfg-vk files when the plugin is uninstalled"""
try:
decky.logger.info(f"Checking for lsfg-vk files to clean up:")
decky.logger.info(f" Library file: {self.lib_file}")
decky.logger.info(f" JSON file: {self.json_file}")
decky.logger.info(f" lsfg script: {self.lsfg_script_path}")
removed_files = []
# Remove library file if it exists
if os.path.exists(self.lib_file):
decky.logger.info(f"Found library file, attempting to remove: {self.lib_file}")
try:
os.remove(self.lib_file)
removed_files.append(self.lib_file)
decky.logger.info(f"Successfully removed {self.lib_file}")
except Exception as e:
decky.logger.error(f"Failed to remove {self.lib_file}: {str(e)}")
else:
decky.logger.info(f"Library file not found: {self.lib_file}")
# Remove JSON file if it exists
if os.path.exists(self.json_file):
decky.logger.info(f"Found JSON file, attempting to remove: {self.json_file}")
try:
os.remove(self.json_file)
removed_files.append(self.json_file)
decky.logger.info(f"Successfully removed {self.json_file}")
except Exception as e:
decky.logger.error(f"Failed to remove {self.json_file}: {str(e)}")
else:
decky.logger.info(f"JSON file not found: {self.json_file}")
# Remove lsfg script if it exists
if os.path.exists(self.lsfg_script_path):
decky.logger.info(f"Found lsfg script, attempting to remove: {self.lsfg_script_path}")
try:
os.remove(self.lsfg_script_path)
removed_files.append(self.lsfg_script_path)
decky.logger.info(f"Successfully removed {self.lsfg_script_path}")
except Exception as e:
decky.logger.error(f"Failed to remove {self.lsfg_script_path}: {str(e)}")
else:
decky.logger.info(f"lsfg script not found: {self.lsfg_script_path}")
if removed_files:
decky.logger.info(f"Cleaned up {len(removed_files)} lsfg-vk files during plugin uninstall: {removed_files}")
else:
decky.logger.info("No lsfg-vk files found to clean up during plugin uninstall")
except Exception as e:
decky.logger.error(f"Error cleaning up lsfg-vk files during uninstall: {str(e)}")
import traceback
decky.logger.error(f"Traceback: {traceback.format_exc()}")
|