diff options
| author | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2025-07-16 13:54:09 -0400 |
|---|---|---|
| committer | xXJSONDeruloXx <danielhimebauch@gmail.com> | 2025-07-16 13:54:09 -0400 |
| commit | 7868396718b13443209e7c5d83a2c96cd7eee31e (patch) | |
| tree | 96e8e172c4484caecca591174a3dea2e5d8da363 /py_modules/lsfg_vk/config_schema.py | |
| parent | 41bba67d24241dea18b056734b153270bb230ba1 (diff) | |
| download | decky-lsfg-vk-7868396718b13443209e7c5d83a2c96cd7eee31e.tar.gz decky-lsfg-vk-7868396718b13443209e7c5d83a2c96cd7eee31e.zip | |
centralized configuration system for lsfg-vk params
Diffstat (limited to 'py_modules/lsfg_vk/config_schema.py')
| -rw-r--r-- | py_modules/lsfg_vk/config_schema.py | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/py_modules/lsfg_vk/config_schema.py b/py_modules/lsfg_vk/config_schema.py new file mode 100644 index 0000000..0f1bdae --- /dev/null +++ b/py_modules/lsfg_vk/config_schema.py @@ -0,0 +1,228 @@ +""" +Centralized configuration schema for lsfg-vk. + +This module defines the complete configuration structure, including: +- Field definitions with types, defaults, and metadata +- Script generation logic +- Validation rules +- Type definitions +""" + +from typing import TypedDict, Dict, Any, Union, Callable, cast +from dataclasses import dataclass, field +from enum import Enum + + +class ConfigFieldType(Enum): + """Supported configuration field types""" + BOOLEAN = "boolean" + INTEGER = "integer" + FLOAT = "float" + + +@dataclass +class ConfigField: + """Configuration field definition""" + name: str + field_type: ConfigFieldType + default: Union[bool, int, float] + description: str + script_template: str # Template for script generation + script_comment: str = "" # Comment to add when disabled + + def get_script_line(self, value: Union[bool, int, float]) -> str: + """Generate script line for this field""" + if self.field_type == ConfigFieldType.BOOLEAN: + if value: + return self.script_template.format(value=1) + else: + return f"# {self.script_template.format(value=1)}" + else: + return self.script_template.format(value=value) + + +# Configuration schema definition +CONFIG_SCHEMA: Dict[str, ConfigField] = { + "enable_lsfg": ConfigField( + name="enable_lsfg", + field_type=ConfigFieldType.BOOLEAN, + default=True, + description="Enables the frame generation layer", + script_template="export ENABLE_LSFG={value}", + script_comment="# export ENABLE_LSFG=1" + ), + + "multiplier": ConfigField( + name="multiplier", + field_type=ConfigFieldType.INTEGER, + default=2, + description="Traditional FPS multiplier value", + script_template="export LSFG_MULTIPLIER={value}" + ), + + "flow_scale": ConfigField( + name="flow_scale", + field_type=ConfigFieldType.FLOAT, + default=0.8, + description="Lowers the internal motion estimation resolution", + script_template="export LSFG_FLOW_SCALE={value}" + ), + + "hdr": ConfigField( + name="hdr", + field_type=ConfigFieldType.BOOLEAN, + default=False, + description="Enable HDR mode (only if Game supports HDR)", + script_template="export LSFG_HDR={value}", + script_comment="# export LSFG_HDR=1" + ), + + "perf_mode": ConfigField( + name="perf_mode", + field_type=ConfigFieldType.BOOLEAN, + default=True, + description="Use lighter model for FG", + script_template="export LSFG_PERF_MODE={value}", + script_comment="# export LSFG_PERF_MODE=1" + ), + + "immediate_mode": ConfigField( + name="immediate_mode", + field_type=ConfigFieldType.BOOLEAN, + default=False, + description="Reduce input lag (Experimental, will cause issues in many games)", + script_template="export MESA_VK_WSI_PRESENT_MODE=immediate # - disable vsync", + script_comment="# export MESA_VK_WSI_PRESENT_MODE=immediate # - disable vsync" + ), + + "disable_vkbasalt": ConfigField( + name="disable_vkbasalt", + field_type=ConfigFieldType.BOOLEAN, + default=True, + description="Some plugins add vkbasalt layer, which can break lsfg. Toggling on fixes this", + script_template="export DISABLE_VKBASALT={value}", + script_comment="# export DISABLE_VKBASALT=1" + ), + + "frame_cap": ConfigField( + name="frame_cap", + field_type=ConfigFieldType.INTEGER, + default=0, + description="Limit base game FPS (0 = disabled)", + script_template="export DXVK_FRAME_RATE={value}", + script_comment="# export DXVK_FRAME_RATE=60" + ) +} + + +class ConfigurationData(TypedDict): + """Type-safe configuration data structure""" + enable_lsfg: bool + multiplier: int + flow_scale: float + hdr: bool + perf_mode: bool + immediate_mode: bool + disable_vkbasalt: bool + frame_cap: int + + +class ConfigurationManager: + """Centralized configuration management""" + + @staticmethod + def get_defaults() -> ConfigurationData: + """Get default configuration values""" + return cast(ConfigurationData, { + field.name: field.default + for field in CONFIG_SCHEMA.values() + }) + + @staticmethod + def get_field_names() -> list[str]: + """Get ordered list of configuration field names""" + return list(CONFIG_SCHEMA.keys()) + + @staticmethod + def get_field_types() -> Dict[str, ConfigFieldType]: + """Get field type mapping""" + return { + field.name: field.field_type + for field in CONFIG_SCHEMA.values() + } + + @staticmethod + def validate_config(config: Dict[str, Any]) -> ConfigurationData: + """Validate and convert configuration data""" + validated = {} + + for field_name, field_def in CONFIG_SCHEMA.items(): + value = config.get(field_name, field_def.default) + + # Type validation and conversion + if field_def.field_type == ConfigFieldType.BOOLEAN: + validated[field_name] = bool(value) + elif field_def.field_type == ConfigFieldType.INTEGER: + validated[field_name] = int(value) + elif field_def.field_type == ConfigFieldType.FLOAT: + validated[field_name] = float(value) + else: + validated[field_name] = value + + return cast(ConfigurationData, validated) + + @staticmethod + def generate_script_content(config: ConfigurationData) -> str: + """Generate lsfg script content from configuration""" + script_lines = ["#!/bin/bash", ""] + + # Generate script lines for each field + for field_name in CONFIG_SCHEMA.keys(): + field_def = CONFIG_SCHEMA[field_name] + value = config[field_name] + + if field_def.field_type == ConfigFieldType.BOOLEAN: + if value: + script_lines.append(field_def.script_template.format(value=1)) + else: + script_lines.append(field_def.script_comment) + else: + # For frame_cap, special handling for 0 value + if field_name == "frame_cap" and value == 0: + script_lines.append(field_def.script_comment) + else: + script_lines.append(field_def.script_template.format(value=value)) + + # Add script footer + script_lines.extend([ + "", + "# Execute the passed command with the environment variables set", + 'exec "$@"' + ]) + + return "\n".join(script_lines) + + @staticmethod + def get_update_signature() -> list[tuple[str, type]]: + """Get the function signature for update_config method""" + signature = [] + for field_name, field_def in CONFIG_SCHEMA.items(): + if field_def.field_type == ConfigFieldType.BOOLEAN: + signature.append((field_name, bool)) + elif field_def.field_type == ConfigFieldType.INTEGER: + signature.append((field_name, int)) + elif field_def.field_type == ConfigFieldType.FLOAT: + signature.append((field_name, float)) + return signature + + @staticmethod + def create_config_from_args(*args) -> ConfigurationData: + """Create configuration from ordered arguments""" + field_names = ConfigurationManager.get_field_names() + if len(args) != len(field_names): + raise ValueError(f"Expected {len(field_names)} arguments, got {len(args)}") + + return cast(ConfigurationData, { + field_name: args[i] + for i, field_name in enumerate(field_names) + }) |
