From 9dbce2a812c2e67a4866e2b4600c3c7ee37854ed Mon Sep 17 00:00:00 2001 From: Ilya Zlobintsev Date: Sat, 7 Sep 2024 15:01:51 +0300 Subject: [PATCH] feat: show effective VRAM clockspeed in the GUI on GDDR6 (#368) * feat: refactor clocks frame adjustments into a separate widget * feat: show effective VRAM clockspeed in the GUI on GDDR6 --- lact-daemon/src/server/gpu_controller/mod.rs | 6 + lact-gui/src/app/graphs_window/mod.rs | 14 +- lact-gui/src/app/mod.rs | 8 + .../app/root_stack/oc_page/clocks_frame.rs | 302 +++++++----------- .../oc_page/clocks_frame/adjustment_row.rs | 151 +++++++++ .../root_stack/oc_page/gpu_stats_section.rs | 20 +- lact-gui/src/app/root_stack/oc_page/mod.rs | 13 +- .../oc_page/clocks_frame/adjustment_row.blp | 37 +++ lact-schema/src/lib.rs | 1 + 9 files changed, 361 insertions(+), 191 deletions(-) create mode 100644 lact-gui/src/app/root_stack/oc_page/clocks_frame/adjustment_row.rs create mode 100644 lact-gui/ui/oc_page/clocks_frame/adjustment_row.blp diff --git a/lact-daemon/src/server/gpu_controller/mod.rs b/lact-daemon/src/server/gpu_controller/mod.rs index fa2b3e3..7ad3491 100644 --- a/lact-daemon/src/server/gpu_controller/mod.rs +++ b/lact-daemon/src/server/gpu_controller/mod.rs @@ -189,6 +189,8 @@ impl GpuController { #[cfg(feature = "libdrm_amdgpu_sys")] fn get_drm_info(&self) -> Option { + use libdrm_amdgpu_sys::AMDGPU::VRAM_TYPE; + trace!("Reading DRM info"); let drm_handle = self.drm_handle.as_ref(); @@ -211,6 +213,10 @@ impl GpuController { chip_class: drm_info.get_chip_class().to_string(), compute_units: drm_info.cu_active_number, vram_type: drm_info.get_vram_type().to_string(), + vram_clock_ratio: match drm_info.get_vram_type() { + VRAM_TYPE::GDDR6 => 2.0, + _ => 1.0, + }, vram_bit_width: drm_info.vram_bit_width, vram_max_bw: drm_info.peak_memory_bw_gb().to_string(), l1_cache_per_cu: drm_info.get_l1_cache_size(), diff --git a/lact-gui/src/app/graphs_window/mod.rs b/lact-gui/src/app/graphs_window/mod.rs index f7550db..871583e 100644 --- a/lact-gui/src/app/graphs_window/mod.rs +++ b/lact-gui/src/app/graphs_window/mod.rs @@ -18,7 +18,7 @@ glib::wrapper! { impl GraphsWindow { pub fn new() -> Self { - Object::builder().build() + Object::builder().property("vram_clock_ratio", 1.0).build() } pub fn set_stats(&self, stats: &DeviceStats) { @@ -79,7 +79,7 @@ impl GraphsWindow { clockspeed_plot.push_line_series("GPU (Trgt)", point as f64); } if let Some(point) = stats.clockspeed.vram_clockspeed { - clockspeed_plot.push_line_series("VRAM", point as f64); + clockspeed_plot.push_line_series("VRAM", point as f64 * self.vram_clock_ratio()); } if let Some(max_speed) = stats.fan.speed_max { @@ -132,7 +132,7 @@ impl Default for GraphsWindow { mod imp { use super::plot::Plot; use gtk::{ - glib::{self, subclass::InitializingObject}, + glib::{self, subclass::InitializingObject, Properties}, prelude::*, subclass::{ prelude::*, @@ -140,8 +140,10 @@ mod imp { }, CompositeTemplate, }; + use std::cell::Cell; - #[derive(CompositeTemplate, Default)] + #[derive(CompositeTemplate, Default, Properties)] + #[properties(wrapper_type = super::GraphsWindow)] #[template(file = "ui/graphs_window.blp")] pub struct GraphsWindow { #[template_child] @@ -152,6 +154,9 @@ mod imp { pub(super) power_plot: TemplateChild, #[template_child] pub(super) fan_plot: TemplateChild, + + #[property(get, set)] + pub vram_clock_ratio: Cell, } #[glib::object_subclass] @@ -171,6 +176,7 @@ mod imp { } } + #[glib::derived_properties] impl ObjectImpl for GraphsWindow {} impl WidgetImpl for GraphsWindow {} diff --git a/lact-gui/src/app/mod.rs b/lact-gui/src/app/mod.rs index 60bdf28..aa442e4 100644 --- a/lact-gui/src/app/mod.rs +++ b/lact-gui/src/app/mod.rs @@ -361,6 +361,14 @@ impl App { trace!("setting info {info:?}"); self.root_stack.info_page.set_info(&info); + self.root_stack.oc_page.set_info(&info); + + let vram_clock_ratio = info + .drm_info + .as_ref() + .map(|info| info.vram_clock_ratio) + .unwrap_or(1.0); + self.graphs_window.set_vram_clock_ratio(vram_clock_ratio); self.set_initial(gpu_id); self.root_stack.thermals_page.set_info(&info); diff --git a/lact-gui/src/app/root_stack/oc_page/clocks_frame.rs b/lact-gui/src/app/root_stack/oc_page/clocks_frame.rs index badc6f7..bce64ca 100644 --- a/lact-gui/src/app/root_stack/oc_page/clocks_frame.rs +++ b/lact-gui/src/app/root_stack/oc_page/clocks_frame.rs @@ -1,10 +1,13 @@ +mod adjustment_row; + use crate::app::page_section::PageSection; +use crate::app::root_stack::oc_adjustment::OcAdjustment; +use adjustment_row::AdjustmentRow; use amdgpu_sysfs::gpu_handle::overdrive::{ClocksTable, ClocksTableGen}; use glib::clone; use gtk::prelude::*; use gtk::*; -use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; +use subclass::prelude::ObjectSubclassIsExt; use tracing::debug; const DEFAULT_VOLTAGE_OFFSET_RANGE: i32 = 250; @@ -19,13 +22,13 @@ pub struct ClocksFrame { basic_togglebutton: ToggleButton, advanced_togglebutton: ToggleButton, min_values_grid: Grid, - min_sclk_adjustment: (Adjustment, Scale, Rc), - min_mclk_adjustment: (Adjustment, Scale, Rc), - min_voltage_adjustment: (Adjustment, Scale, Rc), - max_sclk_adjustment: (Adjustment, Scale, Rc), - max_mclk_adjustment: (Adjustment, Scale, Rc), - max_voltage_adjustment: (Adjustment, Scale, Rc), - voltage_offset_adjustment: (Adjustment, Scale, Rc), + min_sclk_adjustment: AdjustmentRow, + min_mclk_adjustment: AdjustmentRow, + min_voltage_adjustment: AdjustmentRow, + max_sclk_adjustment: AdjustmentRow, + max_mclk_adjustment: AdjustmentRow, + max_voltage_adjustment: AdjustmentRow, + voltage_offset_adjustment: AdjustmentRow, reset_button: Button, warning_label: Label, clocks_data_unavailable_label: Label, @@ -62,18 +65,25 @@ impl ClocksFrame { let min_values_grid = Grid::builder().row_spacing(5).build(); - let min_sclk_adjustment = oc_adjustment("Minimum GPU Clock (MHz)", &min_values_grid, 0); - let min_mclk_adjustment = oc_adjustment("Minimum VRAM Clock (MHz)", &min_values_grid, 1); - let min_voltage_adjustment = oc_adjustment("Minimum GPU voltage (mV)", &min_values_grid, 2); + let min_sclk_adjustment = + AdjustmentRow::new_and_attach("Minimum GPU Clock (MHz)", &min_values_grid, 0); + let min_mclk_adjustment = + AdjustmentRow::new_and_attach("Minimum VRAM Clock (MHz)", &min_values_grid, 1); + let min_voltage_adjustment = + AdjustmentRow::new_and_attach("Minimum GPU voltage (mV)", &min_values_grid, 2); container.append(&min_values_grid); let tweaking_grid = Grid::builder().row_spacing(5).build(); - let max_sclk_adjustment = oc_adjustment("Maximum GPU Clock (MHz)", &tweaking_grid, 1); - let max_voltage_adjustment = oc_adjustment("Maximum GPU voltage (mV)", &tweaking_grid, 2); - let max_mclk_adjustment = oc_adjustment("Maximum VRAM Clock (MHz)", &tweaking_grid, 3); - let voltage_offset_adjustment = oc_adjustment("GPU voltage offset (mV)", &tweaking_grid, 4); + let max_sclk_adjustment = + AdjustmentRow::new_and_attach("Maximum GPU Clock (MHz)", &tweaking_grid, 1); + let max_voltage_adjustment = + AdjustmentRow::new_and_attach("Maximum GPU voltage (mV)", &tweaking_grid, 2); + let max_mclk_adjustment = + AdjustmentRow::new_and_attach("Maximum VRAM Clock (MHz)", &tweaking_grid, 3); + let voltage_offset_adjustment = + AdjustmentRow::new_and_attach("GPU voltage offset (mV)", &tweaking_grid, 4); let reset_button = Button::builder() .label("Reset") @@ -145,15 +155,14 @@ impl ClocksFrame { ) }) { - self.min_sclk_adjustment.0.set_lower(sclk_min.into()); - self.min_sclk_adjustment.0.set_upper(sclk_max.into()); - self.min_sclk_adjustment - .0 - .set_value(current_sclk_min.into()); + let min_sclk_adjustment = &self.min_sclk_adjustment.imp().adjustment; + min_sclk_adjustment.set_lower(sclk_min.into()); + min_sclk_adjustment.set_upper(sclk_max.into()); + min_sclk_adjustment.set_initial_value(current_sclk_min.into()); - self.min_sclk_adjustment.1.set_visible(true); + self.min_sclk_adjustment.set_visible(true); } else { - self.min_sclk_adjustment.1.set_visible(false); + self.min_sclk_adjustment.set_visible(false); } if let Some((current_mclk_min, mclk_min, mclk_max)) = @@ -164,14 +173,14 @@ impl ClocksFrame { ) }) { - self.min_mclk_adjustment.0.set_lower(mclk_min.into()); - self.min_mclk_adjustment.0.set_upper(mclk_max.into()); - self.min_mclk_adjustment - .0 - .set_value(current_mclk_min.into()); - self.min_mclk_adjustment.1.set_visible(true); + let min_mclk_adjustment = &self.min_mclk_adjustment.imp().adjustment; + min_mclk_adjustment.set_lower(mclk_min.into()); + min_mclk_adjustment.set_upper(mclk_max.into()); + min_mclk_adjustment.set_initial_value(current_mclk_min.into()); + + self.min_mclk_adjustment.set_visible(true); } else { - self.min_mclk_adjustment.1.set_visible(false); + self.min_mclk_adjustment.set_visible(false); } if let Some((current_min_voltage, voltage_min, voltage_max)) = @@ -184,14 +193,15 @@ impl ClocksFrame { ) }) { - self.min_voltage_adjustment.0.set_lower(voltage_min.into()); - self.min_voltage_adjustment.0.set_upper(voltage_max.into()); - self.min_voltage_adjustment - .0 - .set_value(current_min_voltage.into()); - self.min_voltage_adjustment.1.set_visible(true); + let min_voltage_adjustment = &self.min_voltage_adjustment.imp().adjustment; + + min_voltage_adjustment.set_lower(voltage_min.into()); + min_voltage_adjustment.set_upper(voltage_max.into()); + min_voltage_adjustment.set_value(current_min_voltage.into()); + + self.min_voltage_adjustment.set_visible(true); } else { - self.min_voltage_adjustment.1.set_visible(false); + self.min_voltage_adjustment.set_visible(false); } if let Some((current_sclk_max, sclk_min, sclk_max)) = @@ -199,14 +209,15 @@ impl ClocksFrame { (table.get_max_sclk(), table.get_max_sclk_range()) }) { - self.max_sclk_adjustment.0.set_lower(sclk_min.into()); - self.max_sclk_adjustment.0.set_upper(sclk_max.into()); - self.max_sclk_adjustment - .0 - .set_value(current_sclk_max.into()); - self.max_sclk_adjustment.1.set_visible(true); + let max_sclk_adjustment = &self.max_sclk_adjustment.imp().adjustment; + + max_sclk_adjustment.set_lower(sclk_min.into()); + max_sclk_adjustment.set_upper(sclk_max.into()); + max_sclk_adjustment.set_value(current_sclk_max.into()); + + self.max_sclk_adjustment.set_visible(true); } else { - self.max_sclk_adjustment.1.set_visible(false); + self.max_sclk_adjustment.set_visible(false); } if let Some((current_mclk_max, mclk_min, mclk_max)) = @@ -214,14 +225,14 @@ impl ClocksFrame { (table.get_max_mclk(), table.get_max_mclk_range()) }) { - self.max_mclk_adjustment.0.set_lower(mclk_min.into()); - self.max_mclk_adjustment.0.set_upper(mclk_max.into()); - self.max_mclk_adjustment - .0 - .set_value(current_mclk_max.into()); - self.max_mclk_adjustment.1.set_visible(true); + let max_mclk_adjustment = &self.max_mclk_adjustment.imp().adjustment; + max_mclk_adjustment.set_lower(mclk_min.into()); + max_mclk_adjustment.set_upper(mclk_max.into()); + max_mclk_adjustment.set_value(current_mclk_max.into()); + + self.max_mclk_adjustment.set_visible(true); } else { - self.max_mclk_adjustment.1.set_visible(false); + self.max_mclk_adjustment.set_visible(false); } if let Some((current_voltage_max, voltage_min, voltage_max)) = @@ -229,14 +240,14 @@ impl ClocksFrame { (table.get_max_sclk_voltage(), table.get_max_voltage_range()) }) { - self.max_voltage_adjustment.0.set_lower(voltage_min.into()); - self.max_voltage_adjustment.0.set_upper(voltage_max.into()); - self.max_voltage_adjustment - .0 - .set_value(current_voltage_max.into()); - self.max_voltage_adjustment.1.set_visible(true); + let max_voltage_adjustment = &self.max_voltage_adjustment.imp().adjustment; + max_voltage_adjustment.set_lower(voltage_min.into()); + max_voltage_adjustment.set_upper(voltage_max.into()); + max_voltage_adjustment.set_value(current_voltage_max.into()); + + self.max_voltage_adjustment.set_visible(true); } else { - self.max_voltage_adjustment.1.set_visible(false); + self.max_voltage_adjustment.set_visible(false); } if let ClocksTableGen::Vega20(table) = table { @@ -247,28 +258,26 @@ impl ClocksFrame { .and_then(|range| range.into_full()) .unwrap_or((-DEFAULT_VOLTAGE_OFFSET_RANGE, DEFAULT_VOLTAGE_OFFSET_RANGE)); - self.voltage_offset_adjustment - .0 - .set_lower(min_offset as f64); - self.voltage_offset_adjustment - .0 - .set_upper(max_offset as f64); - self.voltage_offset_adjustment.0.set_value(offset.into()); - self.voltage_offset_adjustment.1.set_visible(true); + let voltage_offset_adjustment = &self.voltage_offset_adjustment.imp().adjustment; + voltage_offset_adjustment.set_lower(min_offset as f64); + voltage_offset_adjustment.set_upper(max_offset as f64); + voltage_offset_adjustment.set_value(offset.into()); + + self.voltage_offset_adjustment.set_visible(true); } else { - self.voltage_offset_adjustment.1.set_visible(false); + self.voltage_offset_adjustment.set_visible(false); } } else { - self.voltage_offset_adjustment.1.set_visible(false); + self.voltage_offset_adjustment.set_visible(false); } - emit_changed(&self.min_sclk_adjustment); - emit_changed(&self.min_mclk_adjustment); - emit_changed(&self.min_voltage_adjustment); - emit_changed(&self.max_sclk_adjustment); - emit_changed(&self.max_mclk_adjustment); - emit_changed(&self.max_voltage_adjustment); - emit_changed(&self.voltage_offset_adjustment); + self.min_sclk_adjustment.refresh(); + self.min_mclk_adjustment.refresh(); + self.min_voltage_adjustment.refresh(); + self.max_sclk_adjustment.refresh(); + self.max_mclk_adjustment.refresh(); + self.max_voltage_adjustment.refresh(); + self.voltage_offset_adjustment.refresh(); Ok(()) } @@ -287,23 +296,46 @@ impl ClocksFrame { self.clocks_data_unavailable_label.show(); } + pub fn set_vram_clock_ratio(&self, ratio: f64) { + self.min_mclk_adjustment.set_value_ratio(ratio); + self.max_mclk_adjustment.set_value_ratio(ratio); + } + pub fn connect_clocks_changed(&self, f: F) { let f = clone!( #[strong] f, - move |_: &Adjustment| f() + move |_: &OcAdjustment| f() ); - self.min_sclk_adjustment.0.connect_value_changed(f.clone()); - self.min_mclk_adjustment.0.connect_value_changed(f.clone()); + + self.min_sclk_adjustment + .imp() + .adjustment + .connect_value_changed(f.clone()); + self.min_mclk_adjustment + .imp() + .adjustment + .connect_value_changed(f.clone()); self.min_voltage_adjustment - .0 + .imp() + .adjustment + .connect_value_changed(f.clone()); + self.max_sclk_adjustment + .imp() + .adjustment + .connect_value_changed(f.clone()); + self.max_mclk_adjustment + .imp() + .adjustment .connect_value_changed(f.clone()); - self.max_sclk_adjustment.0.connect_value_changed(f.clone()); - self.max_mclk_adjustment.0.connect_value_changed(f.clone()); self.max_voltage_adjustment - .0 + .imp() + .adjustment .connect_value_changed(f.clone()); - self.voltage_offset_adjustment.0.connect_value_changed(f); + self.voltage_offset_adjustment + .imp() + .adjustment + .connect_value_changed(f); } pub fn connect_clocks_reset(&self, f: F) { @@ -312,15 +344,15 @@ impl ClocksFrame { pub fn get_settings(&self) -> ClocksSettings { if self.tweaking_grid.get_visible() { - let min_core_clock = get_adjustment_value(&self.min_sclk_adjustment); - let min_memory_clock = get_adjustment_value(&self.min_mclk_adjustment); - let min_voltage = get_adjustment_value(&self.min_voltage_adjustment); - let max_core_clock = get_adjustment_value(&self.max_sclk_adjustment); - let max_memory_clock = get_adjustment_value(&self.max_mclk_adjustment); - let max_voltage = get_adjustment_value(&self.max_voltage_adjustment); + let min_core_clock = self.min_sclk_adjustment.get_value(); + let min_memory_clock = self.min_mclk_adjustment.get_value(); + let min_voltage = self.min_voltage_adjustment.get_value(); + let max_core_clock = self.max_sclk_adjustment.get_value(); + let max_memory_clock = self.max_mclk_adjustment.get_value(); + let max_voltage = self.max_voltage_adjustment.get_value(); - let voltage_offset = if self.voltage_offset_adjustment.1.get_visible() { - Some(self.voltage_offset_adjustment.0.value() as i32) + let voltage_offset = if self.voltage_offset_adjustment.get_visible() { + self.voltage_offset_adjustment.get_value() } else { None }; @@ -362,71 +394,6 @@ fn extract_value_and_range( Some((value, min, max)) } -fn oc_adjustment( - title: &'static str, - grid: &Grid, - row: i32, -) -> (Adjustment, Scale, Rc) { - let label = Label::builder().label(title).halign(Align::Start).build(); - - let adjustment = Adjustment::new(0.0, 0.0, 0.0, 1.0, 10.0, 0.0); - - let scale = Scale::builder() - .orientation(Orientation::Horizontal) - .adjustment(&adjustment) - .hexpand(true) - .round_digits(0) - .digits(0) - .value_pos(PositionType::Right) - .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(); - - let changed = Rc::new(AtomicBool::new(false)); - - adjustment.connect_value_changed(clone!( - #[strong] - value_label, - #[strong] - changed, - move |adjustment| { - changed.store(true, Ordering::SeqCst); - - let value = adjustment.value(); - value_label.set_text(&value.to_string()); - } - )); - - scale.connect_visible_notify(clone!( - #[strong] - label, - #[strong] - value_label, - #[strong] - value_button, - move |scale| { - label.set_visible(scale.get_visible()); - value_button.set_visible(scale.get_visible()); - value_label.set_visible(scale.get_visible()); - } - )); - - grid.attach(&label, 0, row, 1, 1); - grid.attach(&scale, 1, row, 4, 1); - grid.attach(&value_button, 6, row, 4, 1); - - (adjustment, scale, changed) -} - #[derive(Debug, Default)] pub struct ClocksSettings { pub min_core_clock: Option, @@ -437,26 +404,3 @@ pub struct ClocksSettings { pub max_voltage: Option, pub voltage_offset: Option, } - -fn get_adjustment_value( - (adjustment, scale, changed): &(Adjustment, Scale, Rc), -) -> Option { - let changed = changed.load(Ordering::SeqCst); - - if changed { - let value = adjustment.value(); - if scale.get_visible() { - Some(value as i32) - } else { - None - } - } else { - None - } -} - -fn emit_changed(adjustment: &(Adjustment, Scale, Rc)) { - adjustment.0.emit_by_name::<()>("value-changed", &[]); - adjustment.1.notify("visible"); - adjustment.2.store(false, Ordering::SeqCst); -} diff --git a/lact-gui/src/app/root_stack/oc_page/clocks_frame/adjustment_row.rs b/lact-gui/src/app/root_stack/oc_page/clocks_frame/adjustment_row.rs new file mode 100644 index 0000000..8d7bdc2 --- /dev/null +++ b/lact-gui/src/app/root_stack/oc_page/clocks_frame/adjustment_row.rs @@ -0,0 +1,151 @@ +use gtk::{ + glib::{self, Object}, + prelude::WidgetExt, + prelude::{GridExt, ObjectExt}, + subclass::prelude::ObjectSubclassIsExt, + Grid, +}; +use std::sync::atomic::Ordering; + +glib::wrapper! { + pub struct AdjustmentRow(ObjectSubclass) + @extends gtk::Widget, + @implements gtk::Orientable, gtk::Accessible, gtk::Buildable; +} + +impl AdjustmentRow { + pub fn new(title: &str) -> Self { + Object::builder() + .property("title", title) + .property("visible", true) + .property("value_ratio", 1.0) + .build() + } + + pub fn new_and_attach(title: &str, grid: &Grid, row: i32) -> Self { + let adj_row = Self::new(title); + adj_row.attach_to_grid(grid, row); + adj_row + } + + pub fn get_value(&self) -> Option { + self.imp() + .adjustment + .get_changed_value(false) + .map(|value| value as i32) + } + + pub fn attach_to_grid(&self, grid: &Grid, row: i32) { + let obj = self.imp(); + + obj.label.unparent(); + obj.scale.unparent(); + obj.value_button.unparent(); + + grid.attach(&obj.label.get(), 0, row, 1, 1); + grid.attach(&obj.scale.get(), 1, row, 4, 1); + grid.attach(&obj.value_button.get(), 6, row, 4, 1); + } + + pub fn refresh(&self) { + let obj = self.imp(); + obj.adjustment.emit_by_name::<()>("value-changed", &[]); + self.notify("visible"); + obj.adjustment.imp().changed.store(false, Ordering::SeqCst); + } +} + +mod imp { + use crate::app::root_stack::oc_adjustment::OcAdjustment; + use glib::{clone, subclass::InitializingObject}; + use gtk::{ + glib::{self, Properties}, + prelude::*, + subclass::{ + prelude::*, + widget::{CompositeTemplateClass, WidgetImpl}, + }, + CompositeTemplate, Label, MenuButton, Scale, SpinButton, TemplateChild, + }; + use std::{cell::RefCell, rc::Rc}; + + #[derive(CompositeTemplate, Default, Properties)] + #[properties(wrapper_type = super::AdjustmentRow)] + #[template(file = "ui/oc_page/clocks_frame/adjustment_row.blp")] + pub struct AdjustmentRow { + #[property(get, set)] + pub visible: Rc>, + #[property(get, set)] + pub value_ratio: Rc>, + #[property(get, set)] + pub title: Rc>, + + #[template_child] + pub label: TemplateChild