mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
Merge branch 'master' into feature/intel
This commit is contained in:
commit
0f42435a0a
49
API.md
49
API.md
@ -1,49 +0,0 @@
|
||||
# Description
|
||||
|
||||
The LACT Daemon exposes a JSON API over a unix socket or TCP, available on `/var/run/lactd.sock` or an arbitrary TCP port. You can configure who has access to the unix socket in `/etc/lact/config.yaml` in the `daemon.admin_groups` field. The TCP listener is disabled by default for security reasons, see [this README section](./README.md#remote-management) for how to enable it.
|
||||
|
||||
The API expects newline-separated JSON objects, and returns a JSON object for every request.
|
||||
|
||||
The general format of requests looks like:
|
||||
```
|
||||
{"command": "command_name", "args": {}}
|
||||
```
|
||||
Note that the type of `args` depends on the specific request, and may be ommited in some cases.
|
||||
|
||||
The response looks like this:
|
||||
```
|
||||
{"status": "ok|error", "data": {}}
|
||||
```
|
||||
Same as `args` in requests, `data` can be of a different type and may not be present depending on the specific request.
|
||||
|
||||
You can try sending commands to socket interactively with `ncat`:
|
||||
```
|
||||
echo '{"command": "list_devices"}' | ncat -U /run/lactd.sock
|
||||
```
|
||||
Example response:
|
||||
```
|
||||
{"status":"ok","data":[{"id":"1002:687F-1043:0555-0000:0b:00.0","name":"Vega 10 XL/XT [Radeon RX Vega 56/64]"}]}
|
||||
```
|
||||
|
||||
Here's an example of calling the API with arguments to change a profile:
|
||||
```
|
||||
echo '{"command": "set_profile", "args": {"name":"name-of-the-profile"}}' | ncat -U /run/lactd.sock
|
||||
```
|
||||
In this code, `name-of-the-profile` should be replaced with the name of a profile that you've already created in LACT.
|
||||
|
||||
|
||||
# Commands
|
||||
|
||||
For the full list of available commands and responses, you can look at the source code of the schema: [requests](lact-schema/src/request.rs), [the basic response structure](lact-schema/src/response.rs) and [all possible types](lact-schema/src/lib.rs).
|
||||
|
||||
It should also be fairly easy to figure out the API by trial and error, as the error message are quite verbose:
|
||||
|
||||
```
|
||||
echo '{"command": "test"}' | ncat -U /run/lactd.sock
|
||||
|
||||
{"status":"error","data":"Failed to deserialize request: unknown variant `test`, expected one of `ping`, `list_devices`, `system_info`, `device_info`, `device_stats`, `device_clocks_info`, `set_fan_control`, `set_power_cap`, `set_performance_level`, `set_clocks_value` at line 1 column 18"}
|
||||
```
|
||||
|
||||
# Rust
|
||||
|
||||
If you want to connect to the socket from a Rust program, you can simply import either the `lact-client` or `lact-schema` (if you want to write a custom client) crates from this repository.
|
@ -15,7 +15,7 @@ Current features:
|
||||
- Viewing information about the GPU
|
||||
- Power and thermals monitoring, power limit configuration
|
||||
- Fan curve control
|
||||
- Overclocking (GPU/VRAM clockspeed and voltage, currently AMD only)
|
||||
- Overclocking (GPU/VRAM clockspeed and voltage)
|
||||
- Power states configuration (AMD only)
|
||||
|
||||
Both AMD and Nvidia functionality works on X11, Wayland or even headless sessions.
|
||||
@ -75,7 +75,7 @@ However the following table shows what functionality can be expected for a given
|
||||
| Vega | Supported | Supported | Supported | Supported | |
|
||||
| RDNA1 (RX 5000) | Supported | Supported | Supported | Supported | |
|
||||
| RDNA2 (RX 6000) | Supported | Supported | Supported | Supported | |
|
||||
| RDNA3 (RX 7000) | Supported | Limited | Supported | Limited | Fan zero RPM mode is enabled by default even with a custom fan curve, and requires kernel 6.13 (`linux-next` when writing this) to be disabled. The power cap is sometimes reported lower than it should be. See [#255](https://github.com/ilya-zlobintsev/LACT/issues/255) for more info. |
|
||||
| RDNA3 (RX 7000) | Supported | Limited | Supported | Limited | Fan zero RPM mode is enabled by default even with a custom fan curve, and requires kernel 6.13 to be disabled. The power cap is sometimes reported lower than it should be. See [#255](https://github.com/ilya-zlobintsev/LACT/issues/255) for more info. |
|
||||
|
||||
GPUs not listed here will still work, but might not have full functionality available.
|
||||
Monitoring/system info will be available everywhere. Integrated GPUs might also only have basic configuration available.
|
||||
@ -88,6 +88,8 @@ Anything Maxwell or newer should work, but generation support has not yet been t
|
||||
|
||||
There is a configuration file available in `/etc/lact/config.yaml`. Most of the settings are accessible through the GUI, but some of them may be useful to be edited manually (like `admin_groups` to specify who has access to the daemon)
|
||||
|
||||
See [CONFIG.md](./docs/CONFIG.md) for more information.
|
||||
|
||||
**Socket permissions setup:**
|
||||
|
||||
By default, LACT uses either ether the `wheel` or `sudo` group (whichever is available) for the ownership of the unix socket that the GUI needs to connect to.
|
||||
|
49
docs/API.md
Normal file
49
docs/API.md
Normal file
@ -0,0 +1,49 @@
|
||||
# Description
|
||||
|
||||
The LACT Daemon exposes a JSON API over a unix socket or TCP, available on `/var/run/lactd.sock` or an arbitrary TCP port. You can configure who has access to the unix socket in `/etc/lact/config.yaml` in the `daemon.admin_groups` field. The TCP listener is disabled by default for security reasons, see [this README section](./README.md#remote-management) for how to enable it.
|
||||
|
||||
The API expects newline-separated JSON objects, and returns a JSON object for every request.
|
||||
|
||||
The general format of requests looks like:
|
||||
```
|
||||
{"command": "command_name", "args": {}}
|
||||
```
|
||||
Note that the type of `args` depends on the specific request, and may be ommited in some cases.
|
||||
|
||||
The response looks like this:
|
||||
```
|
||||
{"status": "ok|error", "data": {}}
|
||||
```
|
||||
Same as `args` in requests, `data` can be of a different type and may not be present depending on the specific request.
|
||||
|
||||
You can try sending commands to socket interactively with `ncat`:
|
||||
```
|
||||
echo '{"command": "list_devices"}' | ncat -U /run/lactd.sock
|
||||
```
|
||||
Example response:
|
||||
```
|
||||
{"status":"ok","data":[{"id":"1002:687F-1043:0555-0000:0b:00.0","name":"Vega 10 XL/XT [Radeon RX Vega 56/64]"}]}
|
||||
```
|
||||
|
||||
Here's an example of calling the API with arguments to change a profile:
|
||||
```
|
||||
echo '{"command": "set_profile", "args": {"name":"name-of-the-profile"}}' | ncat -U /run/lactd.sock
|
||||
```
|
||||
In this code, `name-of-the-profile` should be replaced with the name of a profile that you've already created in LACT.
|
||||
|
||||
|
||||
# Commands
|
||||
|
||||
For the full list of available commands and responses, you can look at the source code of the schema: [requests](lact-schema/src/request.rs), [the basic response structure](lact-schema/src/response.rs) and [all possible types](lact-schema/src/lib.rs).
|
||||
|
||||
It should also be fairly easy to figure out the API by trial and error, as the error message are quite verbose:
|
||||
|
||||
```
|
||||
echo '{"command": "test"}' | ncat -U /run/lactd.sock
|
||||
|
||||
{"status":"error","data":"Failed to deserialize request: unknown variant `test`, expected one of `ping`, `list_devices`, `system_info`, `device_info`, `device_stats`, `device_clocks_info`, `set_fan_control`, `set_power_cap`, `set_performance_level`, `set_clocks_value` at line 1 column 18"}
|
||||
```
|
||||
|
||||
# Rust
|
||||
|
||||
If you want to connect to the socket from a Rust program, you can simply import either the `lact-client` or `lact-schema` (if you want to write a custom client) crates from this repository.
|
192
docs/CONFIG.md
Normal file
192
docs/CONFIG.md
Normal file
@ -0,0 +1,192 @@
|
||||
# Configuration
|
||||
|
||||
The LACT config file is located in `/etc/lact/config.yaml`, and contains all of the GPU settings that are typically edited in the GUI, as well as a few settings specifying the behaviour of the daemon.
|
||||
LACT listens for config file changes and reloads all GPU settings automatically, but daemon-related settings such as the logging level or permissions require a service restart (`systemctl restart lactd`).
|
||||
|
||||
Full config file with all possible options:
|
||||
```yaml
|
||||
# WARNING: this is only an example of each possible setting. DO NOT COPY THIS CONFIG AS IS.
|
||||
# Many options don't make sense to be used together, and depend on your hardware.
|
||||
daemon:
|
||||
# The logging level of the daemon.
|
||||
# Possible values: `error`, `warn`, `info` (default), `debug`, `trace`
|
||||
log_level: info
|
||||
# User groups who should have access to the daemon.
|
||||
# WARNING: only the first group from this list that is found on the system is used!
|
||||
# This is made a list and not a single value to allow this config to work across
|
||||
# different distros, which might have different groups for an "admin" user.
|
||||
admin_groups:
|
||||
- wheel
|
||||
- sudo
|
||||
# If set to `true`, this setting makes the LACT daemon not reset
|
||||
# GPU clocks when changing other settings or when turning off the daemon.
|
||||
# Can be used to work around a few very specific issues with
|
||||
# some settings not applying on AMD GPUs.
|
||||
disable_clocks_cleanup: false
|
||||
# Daemon's TCP listening address. Not specified by default.
|
||||
# By default TCP access is disabled, and only a unix socket is present.
|
||||
# Specifying this option enables the TCP listener.
|
||||
tcp_listen_address: 127.0.0.1:12853
|
||||
|
||||
# Period in seconds for how long settings should wait to be confirmed.
|
||||
# Most GPU setting change commands require a confirmation command to be used
|
||||
# in order to save these settings to the config.
|
||||
# If a confirm command is not issued within the configured period (default: 5 seconds)
|
||||
# the setting will be reverted.
|
||||
apply_settings_timer: 5
|
||||
|
||||
# The main GPU configuration map, containing the list of GPUs and their settings.
|
||||
gpus:
|
||||
# A GPU config entry. This is the ID of the GPU.
|
||||
# The ID is formed with a combination of a PCI device id,
|
||||
# PCI subsystem id and PCI slot name to uniquely identify
|
||||
# each GPU in the system, even if there are multiple of the same model.
|
||||
|
||||
# You can discover the id of your GPU by either:
|
||||
# - Changing a setting in the UI, so it's written to the config
|
||||
# - Using `lact cli list-gpus`
|
||||
1002:687F-1043:0555-0000:0b:00.0:
|
||||
# Whether the daemon should touch fan control settings at all.
|
||||
# Setting this to `true` requires the `fan_control_settings` field to be present as well.
|
||||
fan_control_enabled: true
|
||||
fan_control_settings:
|
||||
# Fan control mode. Can be either `curve` or `static`
|
||||
mode: curve
|
||||
# Static fan speed from 0 to 1. Used when `mode` is `static`
|
||||
static_speed: 1.0
|
||||
# The temperature sensor name to be used with a custom fan curve.
|
||||
# This can be used to base the fan curve off the`junction` (hotspot)
|
||||
# temperature instead of the default overall ("edge") tempreature.
|
||||
# Applicable on most Vega and newer AMD GPUs.
|
||||
temperature_key: edge
|
||||
# Interval in milliseconds for how often the GPU temperature should be checked
|
||||
# when adjusting the fan curve.
|
||||
interval_ms: 500
|
||||
# Custom fan curve used with `mode` set to `curve`.
|
||||
# The format of the map is temperature to fan speed from 0 to 1.
|
||||
# Note: on RDNA3+ AMD GPUs this must have 5 entries.
|
||||
curve:
|
||||
40: 0.2
|
||||
50: 0.35
|
||||
60: 0.5
|
||||
70: 0.75
|
||||
80: 1.0
|
||||
# Hysteresis setting: when spinning down fans after a temperature drop,
|
||||
# the target speed needs to be lower for at least this many milliseconds
|
||||
# for the fan to actually slow down.
|
||||
# This lets you avoid fan speed jumping around during short drops of load
|
||||
# (e.g. loading screen in a game).
|
||||
spindown_delay_ms: 0
|
||||
# Hysteresis setting: the minimum temperature change in degrees
|
||||
# to affect the fan speed. Also used to avoid rapid fan speed changes
|
||||
# when the temperature only changes e.g. 1 degree.
|
||||
change_threshold: 0
|
||||
# Power management firmware options. Specific to RDNA3+ AMD GPUs.
|
||||
# Most of these settings are only applied when not using a custom fan curve.
|
||||
pmfw_options:
|
||||
# This setting adjusts the PMFW’s behavior about the maximum speed in RPM the fan can spin.
|
||||
acoustic_limit: 3200
|
||||
# This setting adjusts the PMFW’s behavior about the maximum speed in RPM the fan can spin
|
||||
# when the temperature is not greater than target temperature.
|
||||
acoustic_target: 1450
|
||||
# The minimum speed in RPM that the fan can spin at.
|
||||
minimum_pwm: 15
|
||||
# Target temperature for the GPU in degrees.
|
||||
# Paring with the acoustic_target setting, they define the maximum speed in RPM
|
||||
# the fan can spin when the temperature is not greater than target temperature.
|
||||
target_temperature: 83
|
||||
# When set to `true`, allows the fan to be turned turned off when below the
|
||||
# `zero_rpm_threshold` temperature value.
|
||||
zero_rpm: true
|
||||
# Temperature in degrees below which the fan should be turned off when `zero_rpm` is set to true.
|
||||
zero_rpm_threshold: 50
|
||||
# Power limit in watts.
|
||||
power_cap: 320.0
|
||||
# Performance level option for AMD GPUs.
|
||||
# Can be `auto`, `low`, `high` or `manual`.
|
||||
performance_level: auto
|
||||
# Index of an AMD power profile mode.
|
||||
# Setting this requires `performance_level` to be set to `manual`.
|
||||
power_profile_mode_index: 0
|
||||
# Custom heuristic values when using the custom AMD power profile mode.
|
||||
# The meaning of these values, their format and count depend on the specific GPU model.
|
||||
# Check the names of these values in the UI.
|
||||
custom_power_profile_mode_hueristics:
|
||||
- - 0
|
||||
- 5
|
||||
- 1
|
||||
- 0
|
||||
- 4
|
||||
- 800
|
||||
- 4587520
|
||||
- -65536
|
||||
- 0
|
||||
- - 0
|
||||
- 5
|
||||
- 1
|
||||
- 0
|
||||
- 1
|
||||
- 0
|
||||
- 3276800
|
||||
- -65536
|
||||
- -6553
|
||||
- - 0
|
||||
- 5
|
||||
- 1
|
||||
- 0
|
||||
- 4
|
||||
- 800
|
||||
- 327680
|
||||
- -65536
|
||||
- 0
|
||||
# List of AMD power states which should be enabled
|
||||
power_states:
|
||||
# GPU power states
|
||||
core_clock:
|
||||
- 0
|
||||
- 2
|
||||
- 3
|
||||
# VRAM power states
|
||||
memory_clock:
|
||||
- 0
|
||||
- 1
|
||||
# Minimum GPU clockspeed in MHz.
|
||||
min_core_clock: 300
|
||||
# Minimum VRAM clockspeed in MHz.
|
||||
min_memory_clock: 500
|
||||
# Minimum GPU voltage in mV.
|
||||
min_voltage: 900
|
||||
# Maximum GPU clockspeed in MHz.
|
||||
max_core_clock: 1630
|
||||
# Maximum VRAM clockspeed in MHz.
|
||||
max_memory_clock: 800
|
||||
# Maximum GPU voltage in mV.
|
||||
max_voltage: 1200
|
||||
# Voltage offset value in mV for RDNA and newer AMD GPUs.
|
||||
voltage_offset: 0
|
||||
|
||||
# Settings profiles
|
||||
profiles:
|
||||
# Name of the profile
|
||||
vkcube:
|
||||
# GPU settings in this profile.
|
||||
# It is the same config format that is used for the top-level `gpus` option.
|
||||
gpus: {}
|
||||
# Profile activation rule for when this profile shoule be activated
|
||||
# when using automatic profile switching.
|
||||
rule:
|
||||
# Type of the rule. Can be either `process or `gamemode`.
|
||||
type: process
|
||||
# Process filter. This is not required when using the gamemode rule type.
|
||||
filter:
|
||||
# Name of the process.
|
||||
name: vkcube
|
||||
# Process arguments. Not required.
|
||||
args: --my-arg
|
||||
|
||||
# Current profile to be used. Does not have effect when `auto_switch_profiles` is used.
|
||||
# Omit this option or set to `null` to use the default profile (settings in the top-level `gpus` entry).
|
||||
current_profile: vkcube
|
||||
# If profiles should be switched between automatically based on their configured rules.
|
||||
auto_switch_profiles: true
|
||||
```
|
@ -51,7 +51,7 @@ copes = { git = "https://gitlab.com/corectrl/copes" }
|
||||
divan = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
lact-daemon = { path = ".", features = ["bench"] }
|
||||
insta = { version = "1.41.1", features = ["json"] }
|
||||
insta = { version = "1.41.1", features = ["json", "yaml"] }
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = "0.68"
|
||||
|
@ -364,6 +364,7 @@ fn default_apply_settings_timer() -> u64 {
|
||||
mod tests {
|
||||
use super::{ClocksConfiguration, Config, Daemon, FanControlSettings, Gpu};
|
||||
use crate::server::gpu_controller::fan_control::FanCurve;
|
||||
use insta::assert_yaml_snapshot;
|
||||
use lact_schema::{FanControlMode, PmfwOptions};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -395,6 +396,23 @@ mod tests {
|
||||
assert_eq!(config, deserialized_config);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_doc() {
|
||||
let doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../docs/CONFIG.md"));
|
||||
let example_config_start = doc
|
||||
.find("```yaml")
|
||||
.expect("Could not find example config start")
|
||||
+ 7;
|
||||
let example_config_end = doc[example_config_start..]
|
||||
.find("```")
|
||||
.expect("Could not find example config end")
|
||||
+ example_config_start;
|
||||
let example_config = &doc[example_config_start..example_config_end];
|
||||
|
||||
let deserialized_config: Config = serde_yaml::from_str(example_config).unwrap();
|
||||
assert_yaml_snapshot!(deserialized_config);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clocks_configuration_applied() {
|
||||
let mut gpu = Gpu {
|
||||
|
@ -879,18 +879,6 @@ impl GpuController for AmdGpuController {
|
||||
}
|
||||
}
|
||||
|
||||
for (kind, states) in &config.power_states {
|
||||
if config.performance_level != Some(PerformanceLevel::Manual) {
|
||||
return Err(anyhow!(
|
||||
"Performance level has to be set to `manual` to configure power states"
|
||||
));
|
||||
}
|
||||
|
||||
self.handle
|
||||
.set_enabled_power_levels(*kind, states)
|
||||
.with_context(|| format!("Could not set {kind:?} power states"))?;
|
||||
}
|
||||
|
||||
if config.fan_control_enabled {
|
||||
if let Some(ref settings) = config.fan_control_settings {
|
||||
match settings.mode {
|
||||
@ -1023,6 +1011,18 @@ impl GpuController for AmdGpuController {
|
||||
handle.commit()?;
|
||||
}
|
||||
|
||||
for (kind, states) in &config.power_states {
|
||||
if config.performance_level != Some(PerformanceLevel::Manual) {
|
||||
return Err(anyhow!(
|
||||
"Performance level has to be set to `manual` to configure power states"
|
||||
));
|
||||
}
|
||||
|
||||
self.handle
|
||||
.set_enabled_power_levels(*kind, states)
|
||||
.with_context(|| format!("Could not set {kind:?} power states"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
@ -0,0 +1,91 @@
|
||||
---
|
||||
source: lact-daemon/src/config.rs
|
||||
expression: deserialized_config
|
||||
snapshot_kind: text
|
||||
---
|
||||
daemon:
|
||||
log_level: info
|
||||
admin_groups:
|
||||
- wheel
|
||||
- sudo
|
||||
disable_clocks_cleanup: false
|
||||
tcp_listen_address: "127.0.0.1:12853"
|
||||
apply_settings_timer: 5
|
||||
gpus:
|
||||
"1002:687F-1043:0555-0000:0b:00.0":
|
||||
fan_control_enabled: true
|
||||
fan_control_settings:
|
||||
mode: curve
|
||||
static_speed: 1
|
||||
temperature_key: edge
|
||||
interval_ms: 500
|
||||
curve:
|
||||
40: 0.2
|
||||
50: 0.35
|
||||
60: 0.5
|
||||
70: 0.75
|
||||
80: 1
|
||||
spindown_delay_ms: 0
|
||||
change_threshold: 0
|
||||
pmfw_options:
|
||||
acoustic_limit: 3200
|
||||
acoustic_target: 1450
|
||||
minimum_pwm: 15
|
||||
target_temperature: 83
|
||||
zero_rpm: true
|
||||
zero_rpm_threshold: 50
|
||||
power_cap: 320
|
||||
performance_level: auto
|
||||
min_core_clock: 300
|
||||
min_memory_clock: 500
|
||||
min_voltage: 900
|
||||
max_core_clock: 1630
|
||||
max_memory_clock: 800
|
||||
max_voltage: 1200
|
||||
voltage_offset: 0
|
||||
power_profile_mode_index: 0
|
||||
custom_power_profile_mode_hueristics:
|
||||
- - 0
|
||||
- 5
|
||||
- 1
|
||||
- 0
|
||||
- 4
|
||||
- 800
|
||||
- 4587520
|
||||
- -65536
|
||||
- 0
|
||||
- - 0
|
||||
- 5
|
||||
- 1
|
||||
- 0
|
||||
- 1
|
||||
- 0
|
||||
- 3276800
|
||||
- -65536
|
||||
- -6553
|
||||
- - 0
|
||||
- 5
|
||||
- 1
|
||||
- 0
|
||||
- 4
|
||||
- 800
|
||||
- 327680
|
||||
- -65536
|
||||
- 0
|
||||
power_states:
|
||||
memory_clock:
|
||||
- 0
|
||||
- 1
|
||||
core_clock:
|
||||
- 0
|
||||
- 2
|
||||
- 3
|
||||
profiles:
|
||||
vkcube:
|
||||
rule:
|
||||
type: process
|
||||
filter:
|
||||
name: vkcube
|
||||
args: "--my-arg"
|
||||
current_profile: vkcube
|
||||
auto_switch_profiles: true
|
@ -121,6 +121,8 @@ impl OcPage {
|
||||
.map(|info| info.vram_clock_ratio)
|
||||
.unwrap_or(1.0);
|
||||
|
||||
self.power_states_frame
|
||||
.set_vram_clock_ratio(vram_clock_ratio);
|
||||
self.stats_section.set_vram_clock_ratio(vram_clock_ratio);
|
||||
self.clocks_frame.set_vram_clock_ratio(vram_clock_ratio);
|
||||
}
|
||||
|
@ -26,8 +26,10 @@ impl PowerStatesFrame {
|
||||
imp.expander.set_expanded(false);
|
||||
}
|
||||
|
||||
imp.core_states_list.set_power_states(states.core, "MHz");
|
||||
imp.vram_states_list.set_power_states(states.vram, "MHz");
|
||||
imp.core_states_list
|
||||
.set_power_states(states.core, "MHz", 1.0);
|
||||
imp.vram_states_list
|
||||
.set_power_states(states.vram, "MHz", self.vram_clock_ratio());
|
||||
}
|
||||
|
||||
pub fn connect_values_changed<F: Fn() + 'static + Clone>(&self, f: F) {
|
||||
@ -76,7 +78,7 @@ mod imp {
|
||||
},
|
||||
CompositeTemplate, Expander,
|
||||
};
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::{cell::Cell, sync::atomic::AtomicBool};
|
||||
|
||||
#[derive(CompositeTemplate, Default, Properties)]
|
||||
#[properties(wrapper_type = super::PowerStatesFrame)]
|
||||
@ -91,6 +93,8 @@ mod imp {
|
||||
|
||||
#[property(get, set)]
|
||||
configurable: AtomicBool,
|
||||
#[property(get, set)]
|
||||
vram_clock_ratio: Cell<f64>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
|
@ -31,9 +31,15 @@ impl PowerStatesList {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn set_power_states(&self, power_states: Vec<PowerState>, value_suffix: &str) {
|
||||
pub fn set_power_states(
|
||||
&self,
|
||||
power_states: Vec<PowerState>,
|
||||
value_suffix: &str,
|
||||
value_ratio: f64,
|
||||
) {
|
||||
let store = gio::ListStore::new::<PowerStateRow>();
|
||||
for (i, state) in power_states.into_iter().enumerate() {
|
||||
for (i, mut state) in power_states.into_iter().enumerate() {
|
||||
state.value = (state.value as f64 * value_ratio) as u64;
|
||||
let index = u8::try_from(i).expect("Power state index doesn't fit in u8?");
|
||||
let row = PowerStateRow::new(state, index, value_suffix);
|
||||
store.append(&row);
|
||||
|
@ -8,7 +8,7 @@ default = ["lact-gui"]
|
||||
adw = ["lact-gui/adw"]
|
||||
|
||||
[dependencies]
|
||||
lact-daemon = { path = "../lact-daemon", default-features = false }
|
||||
lact-daemon = { path = "../lact-daemon" }
|
||||
lact-schema = { path = "../lact-schema", features = ["args"] }
|
||||
lact-cli = { path = "../lact-cli" }
|
||||
lact-gui = { path = "../lact-gui", optional = true }
|
||||
|
Loading…
Reference in New Issue
Block a user