diff --git a/Cargo.lock b/Cargo.lock index 97d1de4..6145da6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,9 +41,9 @@ dependencies = [ [[package]] name = "amdgpu-sysfs" -version = "0.12.8" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "165e7e777966011248a311f2c2e96ec1242935da4b829ac2c9a615ae936c0640" +checksum = "b3a224a37eff351e9942de53949ad8822b0ef0e628a3fb41d3b78fd06f39ecfc" dependencies = [ "enum_dispatch", "serde", @@ -1270,7 +1270,7 @@ dependencies = [ [[package]] name = "lact" -version = "0.5.1" +version = "0.5.2" dependencies = [ "anyhow", "lact-cli", @@ -1281,7 +1281,7 @@ dependencies = [ [[package]] name = "lact-cli" -version = "0.5.1" +version = "0.5.2" dependencies = [ "anyhow", "lact-client", @@ -1290,7 +1290,7 @@ dependencies = [ [[package]] name = "lact-client" -version = "0.5.1" +version = "0.5.2" dependencies = [ "anyhow", "lact-schema", @@ -1302,7 +1302,7 @@ dependencies = [ [[package]] name = "lact-daemon" -version = "0.5.1" +version = "0.5.2" dependencies = [ "anyhow", "bincode", @@ -1327,7 +1327,7 @@ dependencies = [ [[package]] name = "lact-gui" -version = "0.5.1" +version = "0.5.2" dependencies = [ "anyhow", "gtk4", @@ -1341,13 +1341,14 @@ dependencies = [ [[package]] name = "lact-schema" -version = "0.5.1" +version = "0.5.2" dependencies = [ "amdgpu-sysfs", "clap", "indexmap", "serde", "serde_json", + "serde_with", ] [[package]] diff --git a/lact-cli/Cargo.toml b/lact-cli/Cargo.toml index de51d19..962b40c 100644 --- a/lact-cli/Cargo.toml +++ b/lact-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lact-cli" -version = "0.5.1" +version = "0.5.2" edition = "2021" [dependencies] diff --git a/lact-client/Cargo.toml b/lact-client/Cargo.toml index 250b61c..5cc7f50 100644 --- a/lact-client/Cargo.toml +++ b/lact-client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lact-client" -version = "0.5.1" +version = "0.5.2" edition = "2021" [dependencies] diff --git a/lact-client/src/lib.rs b/lact-client/src/lib.rs index 6a8c61a..5e2105a 100644 --- a/lact-client/src/lib.rs +++ b/lact-client/src/lib.rs @@ -10,8 +10,8 @@ use schema::{ power_profile_mode::PowerProfileModesTable, PerformanceLevel, PowerLevelKind, }, request::{ConfirmCommand, SetClocksCommand}, - ClocksInfo, DeviceInfo, DeviceListEntry, DeviceStats, FanControlMode, FanCurveMap, PowerStates, - Request, Response, SystemInfo, + ClocksInfo, DeviceInfo, DeviceListEntry, DeviceStats, FanControlMode, FanCurveMap, PmfwOptions, + PowerStates, Request, Response, SystemInfo, }; use serde::Deserialize; use std::{ @@ -111,6 +111,7 @@ impl DaemonClient { mode: Option, static_speed: Option, curve: Option, + pmfw: PmfwOptions, ) -> anyhow::Result { self.make_request(Request::SetFanControl { id, @@ -118,6 +119,7 @@ impl DaemonClient { mode, static_speed, curve, + pmfw, })? .inner() } @@ -138,6 +140,7 @@ impl DaemonClient { PowerProfileModesTable ); request_with_id!(get_power_states, GetPowerStates, PowerStates); + request_with_id!(reset_pmfw, ResetPmfw, u64); pub fn set_performance_level( &self, diff --git a/lact-daemon/Cargo.toml b/lact-daemon/Cargo.toml index 74f8a39..b1b762a 100644 --- a/lact-daemon/Cargo.toml +++ b/lact-daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lact-daemon" -version = "0.5.1" +version = "0.5.2" edition = "2021" [features] diff --git a/lact-daemon/src/config.rs b/lact-daemon/src/config.rs index 649a0f0..bfe694b 100644 --- a/lact-daemon/src/config.rs +++ b/lact-daemon/src/config.rs @@ -4,7 +4,7 @@ use lact_schema::{ amdgpu_sysfs::gpu_handle::{PerformanceLevel, PowerLevelKind}, default_fan_curve, request::SetClocksCommand, - FanControlMode, + FanControlMode, PmfwOptions, }; use nix::unistd::getuid; use serde::{Deserialize, Serialize}; @@ -56,6 +56,8 @@ impl Default for Daemon { pub struct Gpu { pub fan_control_enabled: bool, pub fan_control_settings: Option, + #[serde(default)] + pub pmfw_options: PmfwOptions, pub power_cap: Option, pub performance_level: Option, #[serde(default, flatten)] @@ -179,10 +181,9 @@ fn default_apply_settings_timer() -> u64 { #[cfg(test)] mod tests { + use lact_schema::{FanControlMode, PmfwOptions}; use std::collections::HashMap; - use lact_schema::FanControlMode; - use super::{ClocksConfiguration, Config, Daemon, FanControlSettings, Gpu}; use crate::server::gpu_controller::fan_control::FanCurve; @@ -217,6 +218,7 @@ mod tests { let mut gpu = Gpu { fan_control_enabled: false, fan_control_settings: None, + pmfw_options: PmfwOptions::default(), power_cap: None, performance_level: None, clocks_configuration: ClocksConfiguration::default(), diff --git a/lact-daemon/src/server/gpu_controller/mod.rs b/lact-daemon/src/server/gpu_controller/mod.rs index 3dbec4e..41b18b2 100644 --- a/lact-daemon/src/server/gpu_controller/mod.rs +++ b/lact-daemon/src/server/gpu_controller/mod.rs @@ -18,7 +18,7 @@ use lact_schema::{ sysfs::SysFS, }, ClocksInfo, ClockspeedStats, DeviceInfo, DeviceStats, DrmInfo, FanStats, GpuPciInfo, LinkInfo, - PciInfo, PowerState, PowerStates, PowerStats, VoltageStats, VramStats, + PciInfo, PmfwInfo, PowerState, PowerStates, PowerStats, VoltageStats, VramStats, }; use pciid_parser::Database; use std::{ @@ -262,6 +262,12 @@ impl GpuController { speed_current: self.hw_mon_and_then(HwMon::get_fan_current), speed_max: self.hw_mon_and_then(HwMon::get_fan_max), speed_min: self.hw_mon_and_then(HwMon::get_fan_min), + pmfw_info: PmfwInfo { + acoustic_limit: self.handle.get_fan_acoustic_limit().ok(), + acoustic_target: self.handle.get_fan_acoustic_target().ok(), + target_temp: self.handle.get_fan_target_temperature().ok(), + minimum_pwm: self.handle.get_fan_minimum_pwm().ok(), + }, }, clockspeed: ClockspeedStats { gpu_clockspeed: self.hw_mon_and_then(HwMon::get_gpu_clockspeed), @@ -468,6 +474,30 @@ impl GpuController { .collect() } + pub fn reset_pmfw_settings(&self) { + let handle = &self.handle; + if self.handle.get_fan_target_temperature().is_ok() { + if let Err(err) = handle.reset_fan_target_temperature() { + warn!("Could not reset target temperature: {err:#}"); + } + } + if self.handle.get_fan_acoustic_target().is_ok() { + if let Err(err) = handle.reset_fan_acoustic_target() { + warn!("Could not reset acoustic target: {err:#}"); + } + } + if self.handle.get_fan_acoustic_limit().is_ok() { + if let Err(err) = handle.reset_fan_acoustic_limit() { + warn!("Could not reset acoustic limit: {err:#}"); + } + } + if self.handle.get_fan_minimum_pwm().is_ok() { + if let Err(err) = handle.reset_fan_minimum_pwm() { + warn!("Could not reset minimum pwm: {err:#}"); + } + } + } + pub async fn apply_config(&self, config: &config::Gpu) -> anyhow::Result<()> { if config.fan_control_enabled { if let Some(ref settings) = config.fan_control_settings { @@ -598,6 +628,30 @@ impl GpuController { .with_context(|| format!("Could not set {kind:?} power states"))?; } + if !config.fan_control_enabled { + let pmfw = &config.pmfw_options; + if let Some(acoustic_limit) = pmfw.acoustic_limit { + self.handle + .set_fan_acoustic_limit(acoustic_limit) + .context("Could not set acoustic limit")?; + } + if let Some(acoustic_target) = pmfw.acoustic_target { + self.handle + .set_fan_acoustic_target(acoustic_target) + .context("Could not set acoustic target")?; + } + if let Some(target_temperature) = pmfw.target_temperature { + self.handle + .set_fan_target_temperature(target_temperature) + .context("Could not set target temperature")?; + } + if let Some(minimum_pwm) = pmfw.minimum_pwm { + self.handle + .set_fan_minimum_pwm(minimum_pwm) + .context("Could not set minimum pwm")?; + } + } + Ok(()) } } diff --git a/lact-daemon/src/server/handler.rs b/lact-daemon/src/server/handler.rs index a40dcec..2d25b22 100644 --- a/lact-daemon/src/server/handler.rs +++ b/lact-daemon/src/server/handler.rs @@ -13,7 +13,8 @@ use lact_schema::{ }, default_fan_curve, request::{ConfirmCommand, SetClocksCommand}, - ClocksInfo, DeviceInfo, DeviceListEntry, DeviceStats, FanControlMode, FanCurveMap, PowerStates, + ClocksInfo, DeviceInfo, DeviceListEntry, DeviceStats, FanControlMode, FanCurveMap, PmfwOptions, + PowerStates, }; use std::{ cell::RefCell, @@ -263,6 +264,7 @@ impl<'a> Handler { mode: Option, static_speed: Option, curve: Option, + pmfw: PmfwOptions, ) -> anyhow::Result { let settings = { let mut config_guard = self @@ -323,6 +325,17 @@ impl<'a> Handler { if let Some(settings) = settings { config.fan_control_settings = Some(settings); } + config.pmfw_options = pmfw; + }) + .await + } + + pub async fn reset_pmfw(&self, id: &str) -> anyhow::Result { + info!("Resetting PMFW settings"); + self.controller_by_id(id)?.reset_pmfw_settings(); + + self.edit_gpu_config(id.to_owned(), |config| { + config.pmfw_options = PmfwOptions::default(); }) .await } @@ -510,6 +523,8 @@ impl<'a> Handler { } } + controller.reset_pmfw_settings(); + if let Err(err) = controller.apply_config(&config::Gpu::default()).await { error!("Could not reset settings for controller {id}: {err:#}"); } diff --git a/lact-daemon/src/server/mod.rs b/lact-daemon/src/server/mod.rs index 42ea0da..3b6bbad 100644 --- a/lact-daemon/src/server/mod.rs +++ b/lact-daemon/src/server/mod.rs @@ -92,11 +92,13 @@ async fn handle_request<'a>(request: Request<'a>, handler: &'a Handler) -> anyho mode, static_speed, curve, + pmfw, } => ok_response( handler - .set_fan_control(id, enabled, mode, static_speed, curve) + .set_fan_control(id, enabled, mode, static_speed, curve, pmfw) .await?, ), + Request::ResetPmfw { id } => ok_response(handler.reset_pmfw(id).await?), Request::SetPowerCap { id, cap } => ok_response(handler.set_power_cap(id, cap).await?), Request::SetPerformanceLevel { id, diff --git a/lact-gui/Cargo.toml b/lact-gui/Cargo.toml index c6bf51c..9d18101 100644 --- a/lact-gui/Cargo.toml +++ b/lact-gui/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lact-gui" -version = "0.5.1" +version = "0.5.2" authors = ["Ilya Zlobintsev "] edition = "2021" diff --git a/lact-gui/src/app/mod.rs b/lact-gui/src/app/mod.rs index 11820df..e66adff 100644 --- a/lact-gui/src/app/mod.rs +++ b/lact-gui/src/app/mod.rs @@ -125,6 +125,23 @@ impl App { } })); + app.root_stack.thermals_page.connect_reset_pmfw(clone!(@strong app, @strong current_gpu_id => move || { + debug!("Resetting PMFW settings"); + let gpu_id = current_gpu_id.borrow().clone(); + + match app.daemon_client.reset_pmfw(&gpu_id) + .and_then(|buffer| buffer.inner()) + .and_then(|_| app.daemon_client.confirm_pending_config(ConfirmCommand::Confirm)) + { + Ok(()) => { + app.set_initial(&gpu_id); + } + Err(err) => { + show_error(&app.window, err); + } + } + })); + app.apply_revealer.connect_apply_button_clicked( clone!(@strong app, @strong current_gpu_id => move || { glib::idle_add_local_once(clone!(@strong app, @strong current_gpu_id => move || { @@ -389,6 +406,7 @@ impl App { thermals_settings.mode, thermals_settings.static_speed, thermals_settings.curve, + thermals_settings.pmfw, ) .context("Could not set fan control")?; self.daemon_client diff --git a/lact-gui/src/app/root_stack/mod.rs b/lact-gui/src/app/root_stack/mod.rs index 68f3e73..9a7e63a 100644 --- a/lact-gui/src/app/root_stack/mod.rs +++ b/lact-gui/src/app/root_stack/mod.rs @@ -1,4 +1,5 @@ mod info_page; +mod oc_adjustment; mod oc_page; mod software_page; mod thermals_page; diff --git a/lact-gui/src/app/root_stack/oc_page/oc_adjustment/imp.rs b/lact-gui/src/app/root_stack/oc_adjustment/imp.rs similarity index 100% rename from lact-gui/src/app/root_stack/oc_page/oc_adjustment/imp.rs rename to lact-gui/src/app/root_stack/oc_adjustment/imp.rs diff --git a/lact-gui/src/app/root_stack/oc_page/oc_adjustment/mod.rs b/lact-gui/src/app/root_stack/oc_adjustment/mod.rs similarity index 85% rename from lact-gui/src/app/root_stack/oc_page/oc_adjustment/mod.rs rename to lact-gui/src/app/root_stack/oc_adjustment/mod.rs index e64c05b..2fe63fd 100644 --- a/lact-gui/src/app/root_stack/oc_page/oc_adjustment/mod.rs +++ b/lact-gui/src/app/root_stack/oc_adjustment/mod.rs @@ -2,7 +2,7 @@ mod imp; use glib::Object; use gtk::{ - glib::{self}, + glib::{self, ObjectExt}, subclass::prelude::*, traits::AdjustmentExt, }; @@ -57,9 +57,19 @@ impl OcAdjustment { } } + pub fn get_nonzero_value(&self) -> Option { + let value = self.value(); + if value == 0.0 { + None + } else { + Some(value) + } + } + pub fn set_initial_value(&self, value: f64) { let inner = self.imp(); inner.obj().set_value(value); + inner.obj().emit_by_name::<()>("value_changed", &[]); inner.changed.store(false, Ordering::SeqCst); } } diff --git a/lact-gui/src/app/root_stack/oc_page/mod.rs b/lact-gui/src/app/root_stack/oc_page/mod.rs index a5bca9d..b4f88f0 100644 --- a/lact-gui/src/app/root_stack/oc_page/mod.rs +++ b/lact-gui/src/app/root_stack/oc_page/mod.rs @@ -1,6 +1,5 @@ mod clocks_frame; mod gpu_stats_section; -mod oc_adjustment; mod performance_frame; mod power_cap_section; // mod power_cap_frame; diff --git a/lact-gui/src/app/root_stack/oc_page/power_cap_section.rs b/lact-gui/src/app/root_stack/oc_page/power_cap_section.rs index 1ad30a4..43e2de2 100644 --- a/lact-gui/src/app/root_stack/oc_page/power_cap_section.rs +++ b/lact-gui/src/app/root_stack/oc_page/power_cap_section.rs @@ -29,7 +29,7 @@ impl Default for PowerCapSection { } mod imp { - use crate::app::{page_section::PageSection, root_stack::oc_page::oc_adjustment::OcAdjustment}; + use crate::app::{page_section::PageSection, root_stack::oc_adjustment::OcAdjustment}; use gtk::{ glib::{self, clone, subclass::InitializingObject, Properties, StaticTypeExt}, prelude::{ButtonExt, ObjectExt}, diff --git a/lact-gui/src/app/root_stack/thermals_page/mod.rs b/lact-gui/src/app/root_stack/thermals_page/mod.rs index 24ba097..3af0e45 100644 --- a/lact-gui/src/app/root_stack/thermals_page/mod.rs +++ b/lact-gui/src/app/root_stack/thermals_page/mod.rs @@ -1,15 +1,16 @@ mod fan_curve_frame; +mod pmfw_frame; use glib::clone; use gtk::prelude::*; use gtk::*; -use lact_client::schema::{default_fan_curve, DeviceStats, FanControlMode, FanCurveMap}; - -use crate::app::page_section::PageSection; - -use self::fan_curve_frame::FanCurveFrame; +use lact_client::schema::{ + default_fan_curve, DeviceStats, FanControlMode, FanCurveMap, PmfwOptions, +}; +use self::{fan_curve_frame::FanCurveFrame, pmfw_frame::PmfwFrame}; use super::{label_row, values_grid}; +use crate::app::page_section::PageSection; #[derive(Debug)] pub struct ThermalsSettings { @@ -17,6 +18,7 @@ pub struct ThermalsSettings { pub mode: Option, pub static_speed: Option, pub curve: Option, + pub pmfw: PmfwOptions, } #[derive(Clone)] @@ -24,6 +26,7 @@ pub struct ThermalsPage { pub container: Box, temperatures_label: Label, fan_speed_label: Label, + pmfw_frame: PmfwFrame, fan_static_speed_adjustment: Adjustment, fan_curve_frame: FanCurveFrame, fan_control_mode_stack: Stack, @@ -58,6 +61,8 @@ impl ThermalsPage { .build(); let fan_static_speed_adjustment = static_speed_adj(&fan_static_speed_frame); + let pmfw_frame = PmfwFrame::new(); + let fan_control_section = PageSection::new("Fan control"); let fan_control_mode_stack = Stack::builder().build(); @@ -67,14 +72,8 @@ impl ThermalsPage { .sensitive(false) .build(); - fan_control_mode_stack.add_titled( - &Box::new(Orientation::Vertical, 15), - Some("automatic"), - "Automatic", - ); - + fan_control_mode_stack.add_titled(&pmfw_frame.container, Some("automatic"), "Automatic"); fan_control_mode_stack.add_titled(&fan_curve_frame.container, Some("curve"), "Curve"); - fan_control_mode_stack.add_titled(&fan_static_speed_frame, Some("static"), "Static"); fan_control_section.append(&fan_control_mode_stack_switcher); @@ -96,6 +95,7 @@ impl ThermalsPage { fan_curve_frame, fan_control_mode_stack, fan_control_mode_stack_switcher, + pmfw_frame, } } @@ -155,6 +155,8 @@ impl ThermalsPage { if !stats.fan.control_enabled && self.fan_curve_frame.get_curve().is_empty() { self.fan_curve_frame.set_curve(&default_fan_curve()); } + + self.pmfw_frame.set_info(&stats.fan.pmfw_info); } } @@ -169,6 +171,8 @@ impl ThermalsPage { f(); })); + self.pmfw_frame.connect_settings_changed(f.clone()); + self.fan_curve_frame.connect_adjusted(move || { f(); }); @@ -191,16 +195,23 @@ impl ThermalsPage { let curve = self.fan_curve_frame.get_curve(); let curve = if curve.is_empty() { None } else { Some(curve) }; + let pmfw = self.pmfw_frame.get_pmfw_options(); + Some(ThermalsSettings { manual_fan_control, mode, static_speed, curve, + pmfw, }) } else { None } } + + pub fn connect_reset_pmfw(&self, f: F) { + self.pmfw_frame.connect_reset(f); + } } fn static_speed_adj(parent_box: &Box) -> Adjustment { diff --git a/lact-gui/src/app/root_stack/thermals_page/pmfw_frame.rs b/lact-gui/src/app/root_stack/thermals_page/pmfw_frame.rs new file mode 100644 index 0000000..87c2377 --- /dev/null +++ b/lact-gui/src/app/root_stack/thermals_page/pmfw_frame.rs @@ -0,0 +1,179 @@ +use crate::app::root_stack::oc_adjustment::OcAdjustment; +use gtk::{ + glib::clone, + prelude::{AdjustmentExt, ButtonExt, GridExt, WidgetExt}, + Align, Button, Grid, Label, MenuButton, Orientation, Popover, Scale, SpinButton, +}; +use lact_client::schema::{amdgpu_sysfs::gpu_handle::fan_control::FanInfo, PmfwInfo, PmfwOptions}; + +#[derive(Clone)] +pub struct PmfwFrame { + pub container: Grid, + target_temperature: OcAdjustment, + acoustic_limit: OcAdjustment, + acoustic_target: OcAdjustment, + minimum_pwm: OcAdjustment, + reset_button: Button, +} + +impl PmfwFrame { + pub fn new() -> Self { + let grid = Grid::builder() + .orientation(Orientation::Vertical) + .row_spacing(5) + .margin_top(10) + .margin_bottom(10) + .margin_start(10) + .margin_end(10) + .build(); + + let target_temperature = adjustment(&grid, "Target temperature (°C)", 0); + let acoustic_limit = adjustment(&grid, "Acoustic limit (RPM)", 1); + let acoustic_target = adjustment(&grid, "Acoustic target (RPM)", 2); + let minimum_pwm = adjustment(&grid, "Minimum fan speed (%)", 3); + + let reset_button = Button::builder() + .label("Reset") + .halign(Align::Fill) + .margin_top(5) + .margin_bottom(5) + .tooltip_text("Warning: this resets the fan firmware settings!") + .css_classes(["destructive-action"]) + .visible(false) + .build(); + grid.attach(&reset_button, 5, 4, 1, 1); + + Self { + container: grid, + target_temperature, + acoustic_limit, + acoustic_target, + minimum_pwm, + reset_button, + } + } + + pub fn set_info(&self, info: &PmfwInfo) { + set_fan_info(&self.acoustic_limit, info.acoustic_limit); + set_fan_info(&self.acoustic_target, info.acoustic_target); + set_fan_info(&self.minimum_pwm, info.minimum_pwm); + set_fan_info(&self.target_temperature, info.target_temp); + + let settings_available = *info != PmfwInfo::default(); + self.reset_button.set_visible(settings_available); + } + + pub fn connect_settings_changed(&self, f: F) { + self.acoustic_limit + .connect_value_changed(clone!(@strong f => move |_| { + f(); + })); + self.acoustic_target + .connect_value_changed(clone!(@strong f => move |_| { + f(); + })); + self.minimum_pwm + .connect_value_changed(clone!(@strong f => move |_| { + f(); + })); + self.target_temperature + .connect_value_changed(clone!(@strong f => move |_| { + f(); + })); + } + + pub fn connect_reset(&self, f: F) { + self.reset_button.connect_clicked(move |_| { + f(); + }); + } + + pub fn get_pmfw_options(&self) -> PmfwOptions { + PmfwOptions { + acoustic_limit: self + .acoustic_limit + .get_nonzero_value() + .map(|value| value as u32), + acoustic_target: self + .acoustic_target + .get_nonzero_value() + .map(|value| value as u32), + minimum_pwm: self + .minimum_pwm + .get_nonzero_value() + .map(|value| value as u32), + target_temperature: self + .target_temperature + .get_nonzero_value() + .map(|value| value as u32), + } + } +} + +fn set_fan_info(adjustment: &OcAdjustment, info: Option) { + match info { + Some(info) => { + if let Some((min, max)) = info.allowed_range { + adjustment.set_lower(min as f64); + adjustment.set_upper(max as f64); + } else { + adjustment.set_lower(0.0); + adjustment.set_upper(info.current as f64); + } + + adjustment.set_initial_value(info.current as f64); + } + None => { + adjustment.set_upper(0.0); + adjustment.set_initial_value(0.0); + } + } +} + +fn adjustment(parent_grid: &Grid, label: &str, row: i32) -> OcAdjustment { + let label = Label::builder().label(label).halign(Align::Start).build(); + + let adjustment = OcAdjustment::new(0.0, 0.0, 100.0, 1.0, 1.0, 0.0); + + let scale = Scale::builder() + .orientation(Orientation::Horizontal) + .adjustment(&adjustment) + .hexpand(true) + .margin_start(5) + .margin_end(5) + .build(); + + let value_selector = SpinButton::new(Some(&adjustment), 1.0, 0); + let value_label = Label::new(None); + + let popover = Popover::builder().child(&value_selector).build(); + let value_button = MenuButton::builder() + .popover(&popover) + .child(&value_label) + .build(); + + adjustment.connect_value_changed( + clone!(@strong value_label, @strong label, @strong scale, @strong value_button => move |adjustment| { + let value = adjustment.value(); + value_label.set_text(&format!("{}", value as u32)); + + if adjustment.upper() == 0.0 { + label.hide(); + value_label.hide(); + scale.hide(); + value_button.hide(); + } else { + label.show(); + value_label.show(); + scale.show(); + value_button.show(); + } + }), + ); + + parent_grid.attach(&label, 0, row, 1, 1); + parent_grid.attach(&scale, 1, row, 4, 1); + parent_grid.attach(&value_button, 5, row, 1, 1); + + adjustment +} diff --git a/lact-schema/Cargo.toml b/lact-schema/Cargo.toml index 68f8305..75fa58f 100644 --- a/lact-schema/Cargo.toml +++ b/lact-schema/Cargo.toml @@ -1,16 +1,19 @@ [package] name = "lact-schema" -version = "0.5.1" +version = "0.5.2" edition = "2021" [features] args = ["clap"] [dependencies] -amdgpu-sysfs = { version = "0.12.7", features = ["serde"] } +amdgpu-sysfs = { version = "0.12.9", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } indexmap = { version = "*", features = ["serde"] } clap = { version = "4.4.11", features = ["derive"], optional = true } +serde_with = { version = "3.4.0", default-features = false, features = [ + "macros", +] } [dev-dependencies] serde_json = "1.0" diff --git a/lact-schema/src/lib.rs b/lact-schema/src/lib.rs index 52ae6b1..3fe0500 100644 --- a/lact-schema/src/lib.rs +++ b/lact-schema/src/lib.rs @@ -12,6 +12,7 @@ pub use response::Response; use amdgpu_sysfs::{ gpu_handle::{ + fan_control::FanInfo, overdrive::{ClocksTable, ClocksTableGen}, PerformanceLevel, }, @@ -19,6 +20,7 @@ use amdgpu_sysfs::{ }; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; +use serde_with::skip_serializing_none; use std::{ borrow::Cow, collections::{BTreeMap, HashMap}, @@ -195,6 +197,18 @@ pub struct FanStats { pub speed_current: Option, pub speed_max: Option, pub speed_min: Option, + // RDNA3+ params + #[serde(default)] + pub pmfw_info: PmfwInfo, +} + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq)] +pub struct PmfwInfo { + pub acoustic_limit: Option, + pub acoustic_target: Option, + pub target_temp: Option, + pub minimum_pwm: Option, } #[derive(Serialize, Deserialize, Debug, Clone, Copy)] @@ -248,3 +262,12 @@ pub enum InitramfsType { Debian, Mkinitcpio, } + +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct PmfwOptions { + pub acoustic_limit: Option, + pub acoustic_target: Option, + pub minimum_pwm: Option, + pub target_temperature: Option, +} diff --git a/lact-schema/src/request.rs b/lact-schema/src/request.rs index d744b02..2c3caf7 100644 --- a/lact-schema/src/request.rs +++ b/lact-schema/src/request.rs @@ -1,4 +1,4 @@ -use crate::{FanControlMode, FanCurveMap}; +use crate::{FanControlMode, FanCurveMap, PmfwOptions}; use amdgpu_sysfs::gpu_handle::{PerformanceLevel, PowerLevelKind}; use serde::{Deserialize, Serialize}; @@ -26,6 +26,11 @@ pub enum Request<'a> { mode: Option, static_speed: Option, curve: Option, + #[serde(default)] + pmfw: PmfwOptions, + }, + ResetPmfw { + id: &'a str, }, SetPowerCap { id: &'a str, diff --git a/lact/Cargo.toml b/lact/Cargo.toml index d5be169..9117ac4 100644 --- a/lact/Cargo.toml +++ b/lact/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lact" -version = "0.5.1" +version = "0.5.2" edition = "2021" [features] diff --git a/pkg/recipes/lact-headless/recipe.yml b/pkg/recipes/lact-headless/recipe.yml index 7d12aef..4f30280 100644 --- a/pkg/recipes/lact-headless/recipe.yml +++ b/pkg/recipes/lact-headless/recipe.yml @@ -3,7 +3,7 @@ metadata: description: AMDGPU control utility arch: x86_64 license: MIT - version: 0.5.1 + version: 0.5.2 maintainer: ilya-zlobintsev url: https://github.com/ilya-zlobintsev/lact source: diff --git a/pkg/recipes/lact-libadwaita/recipe.yml b/pkg/recipes/lact-libadwaita/recipe.yml index 1f8413f..3b5f696 100644 --- a/pkg/recipes/lact-libadwaita/recipe.yml +++ b/pkg/recipes/lact-libadwaita/recipe.yml @@ -3,7 +3,7 @@ metadata: description: AMDGPU control utility arch: x86_64 license: MIT - version: 0.5.1 + version: 0.5.2 maintainer: ilya-zlobintsev url: https://github.com/ilya-zlobintsev/lact source: diff --git a/pkg/recipes/lact/recipe.yml b/pkg/recipes/lact/recipe.yml index a8170f0..2ccb0bd 100644 --- a/pkg/recipes/lact/recipe.yml +++ b/pkg/recipes/lact/recipe.yml @@ -3,7 +3,7 @@ metadata: description: AMDGPU control utility arch: x86_64 license: MIT - version: 0.5.1 + version: 0.5.2 maintainer: ilya-zlobintsev url: https://github.com/ilya-zlobintsev/lact source: