diff --git a/core/global/launch_manager.gd b/core/global/launch_manager.gd index ee7775c3e..820c0576c 100644 --- a/core/global/launch_manager.gd +++ b/core/global/launch_manager.gd @@ -64,6 +64,7 @@ var _persist_path: String = "/".join([_data_dir, "launcher.json"]) var _persist_data: Dictionary = {"version": 1} var _ogui_window_id := 0 var should_manage_overlay := true +var steam_input_enabled := false var logger := Log.get_logger("LaunchManager", Log.LEVEL.INFO) var _focused_app_id := 0 var _input_manager: InputManager @@ -476,6 +477,13 @@ func set_app_gamepad_profile(app: RunningApp) -> void: var section := ".".join(["game", app.launch_item.name.to_lower()]) var profile_path := settings_manager.get_value(section, "gamepad_profile", "") as String var profile_gamepad := settings_manager.get_value(section, "gamepad_profile_target", "") as String + if steam_input_enabled and not (profile_path.is_empty() and profile_gamepad.is_empty()): + # Steam Input handles per-game controller configuration itself while Steam + # is running, so there's no value in us applying our own on top of it. + # Defer to Steam and keep the session-wide profile and target. + logger.debug("Ignoring per-game gamepad profile. Steam Input is in use") + profile_path = "" + profile_gamepad = "" if profile_path.is_empty(): logger.debug("Using global gamepad profile") else: @@ -485,11 +493,21 @@ func set_app_gamepad_profile(app: RunningApp) -> void: ## Sets the gamepad profile for the running app with the given profile func set_gamepad_profile(profile_path: String, target_gamepad: String = "") -> void: + if target_gamepad.is_empty(): + # If overridden by settings, use that, so the user's selection survives + # a restart. + #TODO: This is a global setting, refactor settings to permit individual gamepads to have different targets + target_gamepad = settings_manager.get_value("input", "gamepad_profile_target", "") as String + if target_gamepad.is_empty() and is_instance_valid(_input_manager): + # Otherwise use the default for the current mode. Overlay mode emulates a + # Steam Deck controller when Steam Input is in use. + target_gamepad = _input_manager.get_default_target_gamepad() + # Discover the currently set target for each gamepad to properly add additional # capabilities based on that target for device: CompositeDevice in input_plumber.get_composite_devices(): + # Fall back to the gamepad currently set on this composite device if target_gamepad.is_empty(): - # First, find the currently set gamepad on the composite device var targets = device.get_target_devices() for target in targets: var target_dbus_path: String = target.get("dbus_path") @@ -497,11 +515,6 @@ func set_gamepad_profile(profile_path: String, target_gamepad: String = "") -> v continue target_gamepad = target.get("device_type") break - if not target_gamepad.is_empty(): - break - # Then, if overriden by settings, use that instead - #TODO: This is a global setting, refactor settings to permit individual gamepads to have different targets - target_gamepad = settings_manager.get_value("input", "gamepad_profile_target", target_gamepad) as String # If no profile was specified, unset the gamepad profiles if profile_path == "": diff --git a/core/main.gd b/core/main.gd index 5afd83997..915662f5b 100644 --- a/core/main.gd +++ b/core/main.gd @@ -44,9 +44,11 @@ func _show_help() -> void: print(" help Display this help message") print("") print("Flags:") - print(" --vapor-ui Load Vapor UI") - print(" --only-qam Launch in overlay mode (Deprecated)") - print(" --overlay-mode Launch in overlay mode") + print(" --vapor-ui Load Vapor UI") + print(" --only-qam Launch in overlay mode (Deprecated)") + print(" --overlay-mode Launch in overlay mode") + print(" --steamos-manager Defer conflicting features to SteamOS Manager") + print(" --steam-input Defer controller configuration to Steam Input") print("") print("Environment Variables:") print(" LOG_LEVEL Set the global log level (debug,info,warn,error)") diff --git a/core/platform/handheld/gpd/gpd_gen3.tres b/core/platform/handheld/gpd/gpd_gen3.tres index 56b68fee8..88dc602e0 100644 --- a/core/platform/handheld/gpd/gpd_gen3.tres +++ b/core/platform/handheld/gpd/gpd_gen3.tres @@ -10,3 +10,4 @@ icon_mappings = Array[ExtResource("1_cxaik")]([]) name = "" startup_actions = Array[ExtResource("3_woapc")]([]) shutdown_actions = Array[ExtResource("3_woapc")]([]) +target_gamepad_override = "xbox-elite" diff --git a/core/platform/platform_provider.gd b/core/platform/platform_provider.gd index 86a8f7a19..48732c048 100644 --- a/core/platform/platform_provider.gd +++ b/core/platform/platform_provider.gd @@ -11,6 +11,12 @@ class_name PlatformProvider @export var name: String ## Name of the platform @export var startup_actions: Array[PlatformAction] ## Actions to take upon startup @export var shutdown_actions: Array[PlatformAction] ## Actions to take upon shutdown +## InputPlumber target device to emulate instead of the default one chosen for +## the current session. Leave empty to use the default. Set this for devices +## where the default target is a bad fit, such as handhelds without a dedicated +## Quick Access Menu button, where Steam ignores the guide+south chord on +## Steam Deck and Horipad targets and leaves the user no way to open the QAM. +@export var target_gamepad_override: String var logger := Log.get_logger("PlatformProvider", Log.LEVEL.INFO) diff --git a/core/systems/input/input_manager.gd b/core/systems/input/input_manager.gd index 305290f63..40498e4a0 100644 --- a/core/systems/input/input_manager.gd +++ b/core/systems/input/input_manager.gd @@ -82,6 +82,14 @@ func get_default_global_profile_path() -> String: return "user://data/gamepad/profiles/global_default.json" +## Returns the InputPlumber target device to emulate when the user has not +## configured one. Stubbed out here because the full session never overrides the +## user's controller; it exists so callers can invoke it on any InputManager +## without crashing. Overridden by OverlayModeInputManager. +func get_default_target_gamepad() -> String: + return "" + + ## Returns true if the given event is an InputPlumber event static func is_inputplumber_event(event: InputEvent) -> bool: return event.has_meta("dbus_path") diff --git a/core/systems/input/input_manager_test.gd b/core/systems/input/input_manager_test.gd new file mode 100644 index 000000000..0e4582fc3 --- /dev/null +++ b/core/systems/input/input_manager_test.gd @@ -0,0 +1,56 @@ +extends GutTest + + +# Test that the default input manager makes no assumptions about the target +# gamepad, leaving whatever target InputPlumber already configured in place. +func test_get_default_target_gamepad() -> void: + var input_manager := InputManager.new() + assert_eq(input_manager.get_default_target_gamepad(), "", "should not default to any target gamepad") + input_manager.free() + + +# Test that overlay mode only assumes a target gamepad when Steam Input is in +# use, so games running under Steam see the same controller they would on a +# Deck while other sessions keep whatever is already configured. +func test_get_default_target_gamepad_overlay_mode() -> void: + var launch_manager := load("res://core/global/launch_manager.tres") as LaunchManager + var platform := load("res://core/global/platform.tres") as Platform + var was_steam_input := launch_manager.steam_input_enabled + var was_platform := platform.platform + var input_manager := OverlayInputManager.new() + platform.platform = null + + launch_manager.steam_input_enabled = false + assert_eq(input_manager.get_default_target_gamepad(), "", "should not default to any target gamepad without Steam Input") + + launch_manager.steam_input_enabled = true + assert_eq(input_manager.get_default_target_gamepad(), "deck-uhid", "should default to the Steam Deck target gamepad under Steam Input") + + platform.platform = was_platform + launch_manager.steam_input_enabled = was_steam_input + input_manager.free() + + +# Test that a platform can override the default target gamepad. Devices without +# a dedicated Quick Access Menu button need this, as Steam ignores the guide +# button chords on the Steam Deck target and leaves no way to open the QAM. +func test_get_default_target_gamepad_platform_override() -> void: + var launch_manager := load("res://core/global/launch_manager.tres") as LaunchManager + var platform := load("res://core/global/platform.tres") as Platform + var was_steam_input := launch_manager.steam_input_enabled + var was_platform := platform.platform + var input_manager := OverlayInputManager.new() + + var provider := PlatformProvider.new() + provider.target_gamepad_override = "xbox-elite" + platform.platform = provider + + launch_manager.steam_input_enabled = true + assert_eq(input_manager.get_default_target_gamepad(), "xbox-elite", "should use the target gamepad the platform asked for") + + launch_manager.steam_input_enabled = false + assert_eq(input_manager.get_default_target_gamepad(), "", "should not default to any target gamepad without Steam Input") + + platform.platform = was_platform + launch_manager.steam_input_enabled = was_steam_input + input_manager.free() diff --git a/core/systems/input/overlay_mode_input_manager.gd b/core/systems/input/overlay_mode_input_manager.gd index 360a621ad..5d002d1af 100644 --- a/core/systems/input/overlay_mode_input_manager.gd +++ b/core/systems/input/overlay_mode_input_manager.gd @@ -13,6 +13,7 @@ class_name OverlayInputManager var menu_state_machine := preload("res://assets/state/state_machines/menu_state_machine.tres") as StateMachine var base_state = preload("res://assets/state/states/in_game.tres") as State +var platform := load("res://core/global/platform.tres") as Platform # Called when the node enters the scene tree for the first time. func _ready() -> void: @@ -30,6 +31,19 @@ func _get_default_profile_path() -> String: return "res://assets/gamepad/profiles/default_overlay.json" +## In overlay mode we run alongside an underlay like Steam. Emulate a Steam Deck +## controller by default so Steam recognizes the guide button chords, unless the +## detected platform asks for a different target. +func get_default_target_gamepad() -> String: + if not launch_manager.steam_input_enabled: + return "" + if platform.platform and not platform.platform.target_gamepad_override.is_empty(): + var override := platform.platform.target_gamepad_override + logger.debug("Platform overrides the default target gamepad with " + override) + return override + return "deck-uhid" + + func get_default_global_profile_path() -> String: return "user://data/gamepad/profiles/global_default_overlay.json" diff --git a/core/systems/performance/performance_manager.gd b/core/systems/performance/performance_manager.gd index 590e4af72..4ae3aa4d8 100644 --- a/core/systems/performance/performance_manager.gd +++ b/core/systems/performance/performance_manager.gd @@ -27,6 +27,13 @@ var _settings_manager := load("res://core/global/settings_manager.tres") as Sett var _power_station := load("res://core/systems/performance/power_station.tres") as PowerStationInstance var _launch_manager := load("res://core/global/launch_manager.tres") as LaunchManager +## Whether the GPU settings, the performance level, and the clock +## frequency, are managed by the session OpenGamepadUI is running on top of. +## Static so it can be set before this resource is ever loaded -- _init() applies +## the saved profile as soon as performance_manager.tres is first loaded, so an +## instance variable would be set too late to stop that first TDP write. +static var session_manages_gpu_power := false + var display_device := _power_manager.get_display_device() var current_profile: PerformanceProfile var current_profile_state: PROFILE_STATE # docked or undocked @@ -170,6 +177,23 @@ func apply_profile(profile: PerformanceProfile) -> void: logger.info("Applying performance profile: " + profile.name) + # Apply CPU settings from the given profile + if _power_station.cpu: + logger.debug("Applying CPU performance settings from profile") + if _power_station.cpu.boost_enabled != profile.cpu_boost_enabled: + _power_station.cpu.boost_enabled = profile.cpu_boost_enabled + if _power_station.cpu.smt_enabled != profile.cpu_smt_enabled: + _power_station.cpu.smt_enabled = profile.cpu_smt_enabled + if profile.cpu_core_count_current > 0 and _power_station.cpu.cores_enabled != profile.cpu_core_count_current: + _power_station.cpu.cores_enabled = profile.cpu_core_count_current + + # The power profile, clock frequency, thermal limit, and TDP are all owned by + # the session we are running on top of when it manages GPU power. + if session_manages_gpu_power: + logger.info("Applied Performance Profile: " + profile.name + ". GPU settings are managed by the session") + profile_applied.emit(profile) + return + # Detect all GPU cards var cards: Array[GpuCard] = [] if _power_station.gpu: @@ -206,16 +230,6 @@ func apply_profile(profile: PerformanceProfile) -> void: logger.debug("Applying TDP Boost: " + str(profile.tdp_boost_current)) card.boost = profile.tdp_boost_current - # Apply CPU settings from the given profile - if _power_station.cpu: - logger.debug("Applying CPU performance settings from profile") - if _power_station.cpu.boost_enabled != profile.cpu_boost_enabled: - _power_station.cpu.boost_enabled = profile.cpu_boost_enabled - if _power_station.cpu.smt_enabled != profile.cpu_smt_enabled: - _power_station.cpu.smt_enabled = profile.cpu_smt_enabled - if profile.cpu_core_count_current > 0 and _power_station.cpu.cores_enabled != profile.cpu_core_count_current: - _power_station.cpu.cores_enabled = profile.cpu_core_count_current - logger.info("Applied Performance Profile: " + profile.name) profile_applied.emit(profile) diff --git a/core/ui/card_ui/gamepad/gamepad_settings.gd b/core/ui/card_ui/gamepad/gamepad_settings.gd index f86ef1297..3dfe3fc9a 100644 --- a/core/ui/card_ui/gamepad/gamepad_settings.gd +++ b/core/ui/card_ui/gamepad/gamepad_settings.gd @@ -73,6 +73,8 @@ func _ready() -> void: # Load the default profile for every attached gamepad var profile_path = settings_manager.get_value("input", "gamepad_profile", "") + var saved_gamepad := settings_manager.get_value("input", "gamepad_profile_target", "") as String + var default_gamepad := input_manager.get_default_target_gamepad() for composite_device in input_plumber.get_composite_devices(): # Set the current profile_gamepad type to the currently configured CompositeDevice target gamepad var targets = composite_device.get_target_devices() @@ -80,7 +82,12 @@ func _ready() -> void: var target_dbus_path: String = target.get("dbus_path") if not target_dbus_path.contains("target/gamepad"): continue - self.profile_gamepad = target.get("device_type") + if not saved_gamepad.is_empty(): + self.profile_gamepad = saved_gamepad + elif not default_gamepad.is_empty(): + self.profile_gamepad = default_gamepad + else: + self.profile_gamepad = target.get("device_type") _set_gamepad_profile(composite_device, profile_path) break @@ -153,6 +160,14 @@ func _on_state_entered(_from: State) -> void: if not self.library_item: self.library_item = launch_manager.get_current_app_library_item() + # Steam Input configures controllers per-game itself while Steam is running, + # so a per-game profile of ours would only ever be ignored. Edit the global + # profile instead; the user can still pick a target gamepad, it just applies + # to every game. + if self.library_item and launch_manager.steam_input_enabled: + logger.debug("Steam Input is in use. Editing the global gamepad profile") + self.library_item = null + # Set the current profile_gamepad type to the current CompositeDevice target gamepad var targets = self.gamepad.get_target_devices() for target in targets: @@ -624,6 +639,11 @@ func _set_gamepad_profile(device: CompositeDevice, profile_path: String = "") -> if not library_item: library_item = launch_manager.get_current_app_library_item() + # Per-game profiles are gated while Steam Input is in use, since + # Steam Input configures controllers per-game itself. + if launch_manager.steam_input_enabled: + library_item = null + # If no library item was set with the state, then use the default if not library_item: profile_path = input_manager.get_default_global_profile_path() @@ -631,6 +651,16 @@ func _set_gamepad_profile(device: CompositeDevice, profile_path: String = "") -> else: profile_path = settings_manager.get_library_value(library_item, "gamepad_profile", "") + if self.profile_gamepad.is_empty(): + if not library_item: + self.profile_gamepad = settings_manager.get_value("input", "gamepad_profile_target", "") as String + else: + self.profile_gamepad = settings_manager.get_library_value(library_item, "gamepad_profile_target", "") as String + if self.profile_gamepad.is_empty() and is_instance_valid(input_manager): + # Fall back to the default for the current mode, so devices added after + # startup get the same target gamepad as the ones present at startup. + self.profile_gamepad = input_manager.get_default_target_gamepad() + logger.debug("Setting " + device.name + " to profile: " + profile_path) InputPlumber.load_target_modified_profile(device, profile_path, self.profile_gamepad) diff --git a/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.gd b/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.gd index 816512126..2fa834547 100644 --- a/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.gd +++ b/core/ui/card_ui_overlay_mode/card_ui_overlay_mode.gd @@ -78,6 +78,26 @@ func _init(): # Ensure LaunchManager doesn't override our custom overlay management l launch_manager.should_manage_overlay = false + # Workaround old versions that don't pass launch args via update pack + # TODO: Parse the parent PID's CLI args and use those instead. + if "--skip-update-pack" in cmdargs and self.launch_args.size() == 0: + logger.warn("Launched via update pack without arguments! Falling back to default.") + self.launch_args = PackedStringArray(["steam", "-gamepadui", "-steamos3", "-steampal", "-steamdeck"]) + + # SteamOS Manager owns TDP and GPU clocks when it is in use. This has to stay + # in _init(), which runs before our children are instantiated -- moving it to + # _setup_overlay_mode() would run it from _ready(), after the quick bar has + # already loaded the performance manager and applied the saved profile's TDP. + if "--steamos-manager" in cmdargs: + logger.info("Launched with --steamos-manager. TDP and GPU clocks are managed by the session") + PerformanceManager.session_manages_gpu_power = true + + # Steam Input configures controllers itself when it is in use, so defer to + # it instead of applying our own configuration on top. + if "--steam-input" in cmdargs: + logger.info("Launched with --steam-input, deferring controller configuration to Steam Input.") + launch_manager.steam_input_enabled = true + # Set up plugin manager for quick-bar tags var plugin_loader := load("res://core/global/plugin_loader.tres") as PluginLoader var filters : Array[Callable] = [plugin_loader.filter_by_tag.bind("quick-bar")] @@ -86,12 +106,6 @@ func _init(): ## Starts the --overlay-mode session. func _ready() -> void: - # Workaround old versions that don't pass launch args via update pack - # TODO: Parse the parent PID's CLI args and use those instead. - if "--skip-update-pack" in cmdargs and launch_args.size() == 0: - logger.warn("Launched via update pack without arguments! Falling back to default.") - launch_args = PackedStringArray(["steam", "-gamepadui", "-steamos3", "-steampal", "-steamdeck"]) - # Configure the locale logger.debug("Setup Locale") var locale := settings_manager.get_value("general", "locale", "en_US") as String diff --git a/core/ui/common/quick_bar/performance_menu.gd b/core/ui/common/quick_bar/performance_menu.gd index 211b324ed..8f58bf663 100644 --- a/core/ui/common/quick_bar/performance_menu.gd +++ b/core/ui/common/quick_bar/performance_menu.gd @@ -19,7 +19,7 @@ var _profiles_available: PackedStringArray @onready var smt_button := $SMTButton as Toggle @onready var cpu_label := $CPUSectionLabel as Control @onready var gpu_label := $GPUSectionLabel as Control -@onready var wait_label := $WaitLabel as Control +@onready var wait_label := $WaitLabel as Label @onready var service_timer := $ServiceTimer as Timer @onready var apply_timer := $ApplyTimer as Timer @onready var mangoapp_slider := $%MangoAppSlider as ValueSlider @@ -34,33 +34,20 @@ var logger := Log.get_logger("Performance", Log.LEVEL.INFO) # Called when the node enters the scene tree for the first time. # Finds default values and current settings of the hardware. func _ready() -> void: - # Setup dropdowns - var i := 0 - _get_available_profiles() - power_profile_dropdown.clear() - for profile in _profiles_available: - power_profile_dropdown.add_item(profile, i) - i += 1 - - # Configure the interface - _on_profile_loaded(_performance_manager.current_profile) - - _performance_manager.profile_loaded.connect(_on_profile_loaded) - mangoapp_slider.value_changed.connect(_on_mangoapp_changed) - mode_toggle.toggled.connect(_on_mode_toggled) - - service_timer.timeout.connect(_on_service_timer_timeout) - apply_timer.timeout.connect(_on_apply_timer_timeout) + if PerformanceManager.session_manages_gpu_power: + wait_label.text = "TDP managed in Steam QAM" # Re-start the apply timer when changes happen var on_changed := func() -> void: if _profile_loading: return apply_timer.start() - cpu_boost_button.pressed.connect(on_changed) - smt_button.pressed.connect(on_changed) - gpu_freq_enable.pressed.connect(on_changed) - mode_toggle.pressed.connect(on_changed) + + # Restart the timer when any slider changes happen + var on_slider_changed := func(_value) -> void: + if _profile_loading: + return + apply_timer.start() # Set the total number of available cores if the SMT button is pressed var on_smt_pressed := func() -> void: @@ -74,32 +61,6 @@ func _ready() -> void: if cpu_cores_slider.value > cores: cpu_cores_slider.value = cores cpu_cores_slider.max_value = cores - smt_button.pressed.connect(on_smt_pressed) - - # Restart the timer when any slider changes happen - var on_slider_changed := func(_value) -> void: - if _profile_loading: - return - apply_timer.start() - cpu_cores_slider.value_changed.connect(on_slider_changed) - tdp_slider.value_changed.connect(on_slider_changed) - tdp_boost_slider.value_changed.connect(on_slider_changed) - gpu_freq_min_slider.value_changed.connect(on_slider_changed) - gpu_freq_max_slider.value_changed.connect(on_slider_changed) - gpu_temp_slider.value_changed.connect(on_slider_changed) - - # Configure GPU frequency timers so the minimum value can never go higher - # than the maximum value slider and the maximum value can never go lower - # than the minimum value slider. - var on_gpu_freq_changed := func(_value: float, kind: String) -> void: - if kind == "min" and gpu_freq_min_slider.value > gpu_freq_max_slider.value: - gpu_freq_max_slider.value = gpu_freq_min_slider.value - return - if kind == "max" and gpu_freq_max_slider.value < gpu_freq_min_slider.value: - gpu_freq_min_slider.value = gpu_freq_max_slider.value - return - gpu_freq_min_slider.value_changed.connect(on_gpu_freq_changed.bind("min")) - gpu_freq_max_slider.value_changed.connect(on_gpu_freq_changed.bind("max")) # Also restart the apply timer when dropdown changes happen var on_dropdown_changed := func(index) -> void: @@ -117,7 +78,17 @@ func _ready() -> void: _performance_manager.apply_and_save_profile(_current_profile) else: apply_timer.start() - power_profile_dropdown.item_selected.connect(on_dropdown_changed) + + # Configure GPU frequency sliders so the minimum value can never go higher + # than the maximum value slider and the maximum value can never go lower + # than the minimum value slider. + var on_gpu_freq_changed := func(_value: float, kind: String) -> void: + if kind == "min" and gpu_freq_min_slider.value > gpu_freq_max_slider.value: + gpu_freq_max_slider.value = gpu_freq_min_slider.value + return + if kind == "max" and gpu_freq_max_slider.value < gpu_freq_min_slider.value: + gpu_freq_min_slider.value = gpu_freq_max_slider.value + return # Toggle visibility when the GPU freq manual toggle is on var on_manual_freq := func() -> void: @@ -138,6 +109,48 @@ func _ready() -> void: gpu_freq_max_slider.min_value = round(card.clock_limit_mhz_min) gpu_freq_max_slider.max_value = round(card.clock_limit_mhz_max) gpu_freq_max_slider.value = round(card.clock_value_mhz_max) + + # Setup dropdowns + var i := 0 + _get_available_profiles() + power_profile_dropdown.clear() + for profile in _profiles_available: + power_profile_dropdown.add_item(profile, i) + i += 1 + + # Configure the interface + _on_profile_loaded(_performance_manager.current_profile) + + _performance_manager.profile_loaded.connect(_on_profile_loaded) + mangoapp_slider.value_changed.connect(_on_mangoapp_changed) + mode_toggle.toggled.connect(_on_mode_toggled) + mode_toggle.pressed.connect(on_changed) + + service_timer.timeout.connect(_on_service_timer_timeout) + apply_timer.timeout.connect(_on_apply_timer_timeout) + + # Configure the CPU controls. These stay available even when the session + # manages GPU power, since it has no equivalent of its own. + cpu_boost_button.pressed.connect(on_changed) + smt_button.pressed.connect(on_changed) + smt_button.pressed.connect(on_smt_pressed) + cpu_cores_slider.value_changed.connect(on_slider_changed) + + # The GPU settings are all owned by the session we are running on top of when + # it manages GPU power, so leave their controls disconnected. + if PerformanceManager.session_manages_gpu_power: + return + + # Configure the GPU controls + gpu_freq_enable.pressed.connect(on_changed) + tdp_slider.value_changed.connect(on_slider_changed) + tdp_boost_slider.value_changed.connect(on_slider_changed) + gpu_freq_min_slider.value_changed.connect(on_slider_changed) + gpu_freq_max_slider.value_changed.connect(on_slider_changed) + gpu_temp_slider.value_changed.connect(on_slider_changed) + gpu_freq_min_slider.value_changed.connect(on_gpu_freq_changed.bind("min")) + gpu_freq_max_slider.value_changed.connect(on_gpu_freq_changed.bind("max")) + power_profile_dropdown.item_selected.connect(on_dropdown_changed) gpu_freq_enable.pressed.connect(on_manual_freq) @@ -258,7 +271,6 @@ func _setup_interface() -> void: cpu_cores_slider.max_value = cpu.cores_count / 2 cpu_cores_slider.visible = is_advanced - # Configure GPU components if not _power_station.gpu: return var card := _get_integrated_card() @@ -269,22 +281,25 @@ func _setup_interface() -> void: gpu_label.visible = is_advanced - tdp_slider.visible = is_advanced + # Avoid setting TDP/Freq if managed by the underlying session + var gpu_power_manageable := not PerformanceManager.session_manages_gpu_power + + tdp_slider.visible = is_advanced and gpu_power_manageable tdp_slider.min_value = round(_hardware_manager.gpu.tdp_min) tdp_slider.max_value = round(_hardware_manager.gpu.tdp_max) - tdp_boost_slider.visible = is_advanced + tdp_boost_slider.visible = is_advanced and gpu_power_manageable tdp_boost_slider.max_value = round(_hardware_manager.gpu.max_boost) - gpu_freq_enable.visible = is_advanced + gpu_freq_enable.visible = is_advanced and gpu_power_manageable - power_profile_dropdown.visible = not is_advanced + power_profile_dropdown.visible = not is_advanced and gpu_power_manageable - gpu_freq_min_slider.visible = card.manual_clock and is_advanced + gpu_freq_min_slider.visible = card.manual_clock and is_advanced and gpu_power_manageable gpu_freq_min_slider.min_value = round(card.clock_limit_mhz_min) gpu_freq_min_slider.max_value = round(card.clock_limit_mhz_max) - gpu_freq_max_slider.visible = card.manual_clock and is_advanced + gpu_freq_max_slider.visible = card.manual_clock and is_advanced and gpu_power_manageable gpu_freq_max_slider.min_value = round(card.clock_limit_mhz_min) gpu_freq_max_slider.max_value = round(card.clock_limit_mhz_max)