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
This commit is contained in:
Ilya Zlobintsev 2024-09-07 15:01:51 +03:00 committed by GitHub
parent 99f6e9ee35
commit 9dbce2a812
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 361 additions and 191 deletions

View File

@ -189,6 +189,8 @@ impl GpuController {
#[cfg(feature = "libdrm_amdgpu_sys")] #[cfg(feature = "libdrm_amdgpu_sys")]
fn get_drm_info(&self) -> Option<DrmInfo> { fn get_drm_info(&self) -> Option<DrmInfo> {
use libdrm_amdgpu_sys::AMDGPU::VRAM_TYPE;
trace!("Reading DRM info"); trace!("Reading DRM info");
let drm_handle = self.drm_handle.as_ref(); let drm_handle = self.drm_handle.as_ref();
@ -211,6 +213,10 @@ impl GpuController {
chip_class: drm_info.get_chip_class().to_string(), chip_class: drm_info.get_chip_class().to_string(),
compute_units: drm_info.cu_active_number, compute_units: drm_info.cu_active_number,
vram_type: drm_info.get_vram_type().to_string(), 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_bit_width: drm_info.vram_bit_width,
vram_max_bw: drm_info.peak_memory_bw_gb().to_string(), vram_max_bw: drm_info.peak_memory_bw_gb().to_string(),
l1_cache_per_cu: drm_info.get_l1_cache_size(), l1_cache_per_cu: drm_info.get_l1_cache_size(),

View File

@ -18,7 +18,7 @@ glib::wrapper! {
impl GraphsWindow { impl GraphsWindow {
pub fn new() -> Self { pub fn new() -> Self {
Object::builder().build() Object::builder().property("vram_clock_ratio", 1.0).build()
} }
pub fn set_stats(&self, stats: &DeviceStats) { pub fn set_stats(&self, stats: &DeviceStats) {
@ -79,7 +79,7 @@ impl GraphsWindow {
clockspeed_plot.push_line_series("GPU (Trgt)", point as f64); clockspeed_plot.push_line_series("GPU (Trgt)", point as f64);
} }
if let Some(point) = stats.clockspeed.vram_clockspeed { 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 { if let Some(max_speed) = stats.fan.speed_max {
@ -132,7 +132,7 @@ impl Default for GraphsWindow {
mod imp { mod imp {
use super::plot::Plot; use super::plot::Plot;
use gtk::{ use gtk::{
glib::{self, subclass::InitializingObject}, glib::{self, subclass::InitializingObject, Properties},
prelude::*, prelude::*,
subclass::{ subclass::{
prelude::*, prelude::*,
@ -140,8 +140,10 @@ mod imp {
}, },
CompositeTemplate, CompositeTemplate,
}; };
use std::cell::Cell;
#[derive(CompositeTemplate, Default)] #[derive(CompositeTemplate, Default, Properties)]
#[properties(wrapper_type = super::GraphsWindow)]
#[template(file = "ui/graphs_window.blp")] #[template(file = "ui/graphs_window.blp")]
pub struct GraphsWindow { pub struct GraphsWindow {
#[template_child] #[template_child]
@ -152,6 +154,9 @@ mod imp {
pub(super) power_plot: TemplateChild<Plot>, pub(super) power_plot: TemplateChild<Plot>,
#[template_child] #[template_child]
pub(super) fan_plot: TemplateChild<Plot>, pub(super) fan_plot: TemplateChild<Plot>,
#[property(get, set)]
pub vram_clock_ratio: Cell<f64>,
} }
#[glib::object_subclass] #[glib::object_subclass]
@ -171,6 +176,7 @@ mod imp {
} }
} }
#[glib::derived_properties]
impl ObjectImpl for GraphsWindow {} impl ObjectImpl for GraphsWindow {}
impl WidgetImpl for GraphsWindow {} impl WidgetImpl for GraphsWindow {}

View File

@ -361,6 +361,14 @@ impl App {
trace!("setting info {info:?}"); trace!("setting info {info:?}");
self.root_stack.info_page.set_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.set_initial(gpu_id);
self.root_stack.thermals_page.set_info(&info); self.root_stack.thermals_page.set_info(&info);

View File

@ -1,10 +1,13 @@
mod adjustment_row;
use crate::app::page_section::PageSection; 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 amdgpu_sysfs::gpu_handle::overdrive::{ClocksTable, ClocksTableGen};
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::*; use gtk::*;
use std::rc::Rc; use subclass::prelude::ObjectSubclassIsExt;
use std::sync::atomic::{AtomicBool, Ordering};
use tracing::debug; use tracing::debug;
const DEFAULT_VOLTAGE_OFFSET_RANGE: i32 = 250; const DEFAULT_VOLTAGE_OFFSET_RANGE: i32 = 250;
@ -19,13 +22,13 @@ pub struct ClocksFrame {
basic_togglebutton: ToggleButton, basic_togglebutton: ToggleButton,
advanced_togglebutton: ToggleButton, advanced_togglebutton: ToggleButton,
min_values_grid: Grid, min_values_grid: Grid,
min_sclk_adjustment: (Adjustment, Scale, Rc<AtomicBool>), min_sclk_adjustment: AdjustmentRow,
min_mclk_adjustment: (Adjustment, Scale, Rc<AtomicBool>), min_mclk_adjustment: AdjustmentRow,
min_voltage_adjustment: (Adjustment, Scale, Rc<AtomicBool>), min_voltage_adjustment: AdjustmentRow,
max_sclk_adjustment: (Adjustment, Scale, Rc<AtomicBool>), max_sclk_adjustment: AdjustmentRow,
max_mclk_adjustment: (Adjustment, Scale, Rc<AtomicBool>), max_mclk_adjustment: AdjustmentRow,
max_voltage_adjustment: (Adjustment, Scale, Rc<AtomicBool>), max_voltage_adjustment: AdjustmentRow,
voltage_offset_adjustment: (Adjustment, Scale, Rc<AtomicBool>), voltage_offset_adjustment: AdjustmentRow,
reset_button: Button, reset_button: Button,
warning_label: Label, warning_label: Label,
clocks_data_unavailable_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_values_grid = Grid::builder().row_spacing(5).build();
let min_sclk_adjustment = oc_adjustment("Minimum GPU Clock (MHz)", &min_values_grid, 0); let min_sclk_adjustment =
let min_mclk_adjustment = oc_adjustment("Minimum VRAM Clock (MHz)", &min_values_grid, 1); AdjustmentRow::new_and_attach("Minimum GPU Clock (MHz)", &min_values_grid, 0);
let min_voltage_adjustment = oc_adjustment("Minimum GPU voltage (mV)", &min_values_grid, 2); 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); container.append(&min_values_grid);
let tweaking_grid = Grid::builder().row_spacing(5).build(); let tweaking_grid = Grid::builder().row_spacing(5).build();
let max_sclk_adjustment = oc_adjustment("Maximum GPU Clock (MHz)", &tweaking_grid, 1); let max_sclk_adjustment =
let max_voltage_adjustment = oc_adjustment("Maximum GPU voltage (mV)", &tweaking_grid, 2); AdjustmentRow::new_and_attach("Maximum GPU Clock (MHz)", &tweaking_grid, 1);
let max_mclk_adjustment = oc_adjustment("Maximum VRAM Clock (MHz)", &tweaking_grid, 3); let max_voltage_adjustment =
let voltage_offset_adjustment = oc_adjustment("GPU voltage offset (mV)", &tweaking_grid, 4); 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() let reset_button = Button::builder()
.label("Reset") .label("Reset")
@ -145,15 +155,14 @@ impl ClocksFrame {
) )
}) })
{ {
self.min_sclk_adjustment.0.set_lower(sclk_min.into()); let min_sclk_adjustment = &self.min_sclk_adjustment.imp().adjustment;
self.min_sclk_adjustment.0.set_upper(sclk_max.into()); min_sclk_adjustment.set_lower(sclk_min.into());
self.min_sclk_adjustment min_sclk_adjustment.set_upper(sclk_max.into());
.0 min_sclk_adjustment.set_initial_value(current_sclk_min.into());
.set_value(current_sclk_min.into());
self.min_sclk_adjustment.1.set_visible(true); self.min_sclk_adjustment.set_visible(true);
} else { } 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)) = 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()); let min_mclk_adjustment = &self.min_mclk_adjustment.imp().adjustment;
self.min_mclk_adjustment.0.set_upper(mclk_max.into()); min_mclk_adjustment.set_lower(mclk_min.into());
self.min_mclk_adjustment min_mclk_adjustment.set_upper(mclk_max.into());
.0 min_mclk_adjustment.set_initial_value(current_mclk_min.into());
.set_value(current_mclk_min.into());
self.min_mclk_adjustment.1.set_visible(true); self.min_mclk_adjustment.set_visible(true);
} else { } 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)) = 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()); let min_voltage_adjustment = &self.min_voltage_adjustment.imp().adjustment;
self.min_voltage_adjustment.0.set_upper(voltage_max.into());
self.min_voltage_adjustment min_voltage_adjustment.set_lower(voltage_min.into());
.0 min_voltage_adjustment.set_upper(voltage_max.into());
.set_value(current_min_voltage.into()); min_voltage_adjustment.set_value(current_min_voltage.into());
self.min_voltage_adjustment.1.set_visible(true);
self.min_voltage_adjustment.set_visible(true);
} else { } 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)) = 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()) (table.get_max_sclk(), table.get_max_sclk_range())
}) })
{ {
self.max_sclk_adjustment.0.set_lower(sclk_min.into()); let max_sclk_adjustment = &self.max_sclk_adjustment.imp().adjustment;
self.max_sclk_adjustment.0.set_upper(sclk_max.into());
self.max_sclk_adjustment max_sclk_adjustment.set_lower(sclk_min.into());
.0 max_sclk_adjustment.set_upper(sclk_max.into());
.set_value(current_sclk_max.into()); max_sclk_adjustment.set_value(current_sclk_max.into());
self.max_sclk_adjustment.1.set_visible(true);
self.max_sclk_adjustment.set_visible(true);
} else { } 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)) = 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()) (table.get_max_mclk(), table.get_max_mclk_range())
}) })
{ {
self.max_mclk_adjustment.0.set_lower(mclk_min.into()); let max_mclk_adjustment = &self.max_mclk_adjustment.imp().adjustment;
self.max_mclk_adjustment.0.set_upper(mclk_max.into()); max_mclk_adjustment.set_lower(mclk_min.into());
self.max_mclk_adjustment max_mclk_adjustment.set_upper(mclk_max.into());
.0 max_mclk_adjustment.set_value(current_mclk_max.into());
.set_value(current_mclk_max.into());
self.max_mclk_adjustment.1.set_visible(true); self.max_mclk_adjustment.set_visible(true);
} else { } 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)) = 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()) (table.get_max_sclk_voltage(), table.get_max_voltage_range())
}) })
{ {
self.max_voltage_adjustment.0.set_lower(voltage_min.into()); let max_voltage_adjustment = &self.max_voltage_adjustment.imp().adjustment;
self.max_voltage_adjustment.0.set_upper(voltage_max.into()); max_voltage_adjustment.set_lower(voltage_min.into());
self.max_voltage_adjustment max_voltage_adjustment.set_upper(voltage_max.into());
.0 max_voltage_adjustment.set_value(current_voltage_max.into());
.set_value(current_voltage_max.into());
self.max_voltage_adjustment.1.set_visible(true); self.max_voltage_adjustment.set_visible(true);
} else { } else {
self.max_voltage_adjustment.1.set_visible(false); self.max_voltage_adjustment.set_visible(false);
} }
if let ClocksTableGen::Vega20(table) = table { if let ClocksTableGen::Vega20(table) = table {
@ -247,28 +258,26 @@ impl ClocksFrame {
.and_then(|range| range.into_full()) .and_then(|range| range.into_full())
.unwrap_or((-DEFAULT_VOLTAGE_OFFSET_RANGE, DEFAULT_VOLTAGE_OFFSET_RANGE)); .unwrap_or((-DEFAULT_VOLTAGE_OFFSET_RANGE, DEFAULT_VOLTAGE_OFFSET_RANGE));
self.voltage_offset_adjustment let voltage_offset_adjustment = &self.voltage_offset_adjustment.imp().adjustment;
.0 voltage_offset_adjustment.set_lower(min_offset as f64);
.set_lower(min_offset as f64); voltage_offset_adjustment.set_upper(max_offset as f64);
self.voltage_offset_adjustment voltage_offset_adjustment.set_value(offset.into());
.0
.set_upper(max_offset as f64); self.voltage_offset_adjustment.set_visible(true);
self.voltage_offset_adjustment.0.set_value(offset.into());
self.voltage_offset_adjustment.1.set_visible(true);
} else { } else {
self.voltage_offset_adjustment.1.set_visible(false); self.voltage_offset_adjustment.set_visible(false);
} }
} else { } else {
self.voltage_offset_adjustment.1.set_visible(false); self.voltage_offset_adjustment.set_visible(false);
} }
emit_changed(&self.min_sclk_adjustment); self.min_sclk_adjustment.refresh();
emit_changed(&self.min_mclk_adjustment); self.min_mclk_adjustment.refresh();
emit_changed(&self.min_voltage_adjustment); self.min_voltage_adjustment.refresh();
emit_changed(&self.max_sclk_adjustment); self.max_sclk_adjustment.refresh();
emit_changed(&self.max_mclk_adjustment); self.max_mclk_adjustment.refresh();
emit_changed(&self.max_voltage_adjustment); self.max_voltage_adjustment.refresh();
emit_changed(&self.voltage_offset_adjustment); self.voltage_offset_adjustment.refresh();
Ok(()) Ok(())
} }
@ -287,23 +296,46 @@ impl ClocksFrame {
self.clocks_data_unavailable_label.show(); 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<F: Fn() + 'static + Clone>(&self, f: F) { pub fn connect_clocks_changed<F: Fn() + 'static + Clone>(&self, f: F) {
let f = clone!( let f = clone!(
#[strong] #[strong]
f, 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 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()); .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 self.max_voltage_adjustment
.0 .imp()
.adjustment
.connect_value_changed(f.clone()); .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<F: Fn() + 'static + Clone>(&self, f: F) { pub fn connect_clocks_reset<F: Fn() + 'static + Clone>(&self, f: F) {
@ -312,15 +344,15 @@ impl ClocksFrame {
pub fn get_settings(&self) -> ClocksSettings { pub fn get_settings(&self) -> ClocksSettings {
if self.tweaking_grid.get_visible() { if self.tweaking_grid.get_visible() {
let min_core_clock = get_adjustment_value(&self.min_sclk_adjustment); let min_core_clock = self.min_sclk_adjustment.get_value();
let min_memory_clock = get_adjustment_value(&self.min_mclk_adjustment); let min_memory_clock = self.min_mclk_adjustment.get_value();
let min_voltage = get_adjustment_value(&self.min_voltage_adjustment); let min_voltage = self.min_voltage_adjustment.get_value();
let max_core_clock = get_adjustment_value(&self.max_sclk_adjustment); let max_core_clock = self.max_sclk_adjustment.get_value();
let max_memory_clock = get_adjustment_value(&self.max_mclk_adjustment); let max_memory_clock = self.max_mclk_adjustment.get_value();
let max_voltage = get_adjustment_value(&self.max_voltage_adjustment); let max_voltage = self.max_voltage_adjustment.get_value();
let voltage_offset = if self.voltage_offset_adjustment.1.get_visible() { let voltage_offset = if self.voltage_offset_adjustment.get_visible() {
Some(self.voltage_offset_adjustment.0.value() as i32) self.voltage_offset_adjustment.get_value()
} else { } else {
None None
}; };
@ -362,71 +394,6 @@ fn extract_value_and_range(
Some((value, min, max)) Some((value, min, max))
} }
fn oc_adjustment(
title: &'static str,
grid: &Grid,
row: i32,
) -> (Adjustment, Scale, Rc<AtomicBool>) {
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)] #[derive(Debug, Default)]
pub struct ClocksSettings { pub struct ClocksSettings {
pub min_core_clock: Option<i32>, pub min_core_clock: Option<i32>,
@ -437,26 +404,3 @@ pub struct ClocksSettings {
pub max_voltage: Option<i32>, pub max_voltage: Option<i32>,
pub voltage_offset: Option<i32>, pub voltage_offset: Option<i32>,
} }
fn get_adjustment_value(
(adjustment, scale, changed): &(Adjustment, Scale, Rc<AtomicBool>),
) -> Option<i32> {
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<AtomicBool>)) {
adjustment.0.emit_by_name::<()>("value-changed", &[]);
adjustment.1.notify("visible");
adjustment.2.store(false, Ordering::SeqCst);
}

View File

@ -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<imp::AdjustmentRow>)
@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<i32> {
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<RefCell<bool>>,
#[property(get, set)]
pub value_ratio: Rc<RefCell<f64>>,
#[property(get, set)]
pub title: Rc<RefCell<String>>,
#[template_child]
pub label: TemplateChild<Label>,
#[template_child]
pub scale: TemplateChild<Scale>,
#[template_child]
pub value_button: TemplateChild<MenuButton>,
#[template_child]
pub value_spinbutton: TemplateChild<SpinButton>,
#[template_child]
pub adjustment: TemplateChild<OcAdjustment>,
}
#[glib::object_subclass]
impl ObjectSubclass for AdjustmentRow {
const NAME: &'static str = "AdjustmentRow";
type Type = super::AdjustmentRow;
type ParentType = gtk::Widget;
fn class_init(class: &mut Self::Class) {
OcAdjustment::ensure_type();
class.bind_template();
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
#[glib::derived_properties]
impl ObjectImpl for AdjustmentRow {
fn constructed(&self) {
self.parent_constructed();
self.adjustment.connect_value_changed(clone!(
#[strong(rename_to = value_button)]
self.value_button,
#[strong(rename_to = value_ratio)]
self.value_ratio,
move |adj| {
let ratio = *value_ratio.borrow();
let text = (adj.value() * ratio).to_string();
value_button.set_label(&text);
}
));
self.value_spinbutton.connect_input(clone!(
#[strong(rename_to = value_ratio)]
self.value_ratio,
move |spin| {
let text = spin.text();
let value: f64 = text.parse().ok()?;
Some(Ok(value / *value_ratio.borrow()))
}
));
self.value_spinbutton.connect_output(clone!(
#[strong(rename_to = value_ratio)]
self.value_ratio,
move |spin| {
let display_value = spin.value() * *value_ratio.borrow();
spin.set_text(&display_value.to_string());
glib::Propagation::Stop
}
));
}
}
impl WidgetImpl for AdjustmentRow {}
}

View File

@ -10,7 +10,7 @@ glib::wrapper! {
impl GpuStatsSection { impl GpuStatsSection {
pub fn new() -> Self { pub fn new() -> Self {
Object::builder().build() Object::builder().property("vram_clock_ratio", 1.0).build()
} }
pub fn set_stats(&self, stats: &DeviceStats) { pub fn set_stats(&self, stats: &DeviceStats) {
@ -28,9 +28,12 @@ impl GpuStatsSection {
)); ));
let clockspeed = stats.clockspeed; let clockspeed = stats.clockspeed;
self.set_core_clock(format_clockspeed(clockspeed.gpu_clockspeed)); self.set_core_clock(format_clockspeed(clockspeed.gpu_clockspeed, 1.0));
self.set_current_core_clock(format_current_gfxclk(clockspeed.current_gfxclk)); self.set_current_core_clock(format_current_gfxclk(clockspeed.current_gfxclk));
self.set_vram_clock(format_clockspeed(clockspeed.vram_clockspeed)); self.set_vram_clock(format_clockspeed(
clockspeed.vram_clockspeed,
self.vram_clock_ratio(),
));
let voltage = format!("{:.3} V", stats.voltage.gpu.unwrap_or(0) as f64 / 1000f64); let voltage = format!("{:.3} V", stats.voltage.gpu.unwrap_or(0) as f64 / 1000f64);
self.set_voltage(voltage); self.set_voltage(voltage);
@ -99,7 +102,7 @@ mod imp {
}, },
CompositeTemplate, CompositeTemplate,
}; };
use std::cell::RefCell; use std::cell::{Cell, RefCell};
#[derive(CompositeTemplate, Default, Properties)] #[derive(CompositeTemplate, Default, Properties)]
#[properties(wrapper_type = super::GpuStatsSection)] #[properties(wrapper_type = super::GpuStatsSection)]
@ -125,6 +128,9 @@ mod imp {
vram_usage_text: RefCell<String>, vram_usage_text: RefCell<String>,
#[property(get, set)] #[property(get, set)]
throttling: RefCell<String>, throttling: RefCell<String>,
#[property(get, set)]
vram_clock_ratio: Cell<f64>,
} }
#[glib::object_subclass] #[glib::object_subclass]
@ -150,8 +156,8 @@ mod imp {
impl BoxImpl for GpuStatsSection {} impl BoxImpl for GpuStatsSection {}
} }
fn format_clockspeed(value: Option<u64>) -> String { fn format_clockspeed(value: Option<u64>, ratio: f64) -> String {
format!("{:.3} GHz", value.unwrap_or(0) as f64 / 1000.0) format!("{:.3} GHz", value.unwrap_or(0) as f64 / 1000.0 * ratio)
} }
fn format_current_gfxclk(value: Option<u16>) -> String { fn format_current_gfxclk(value: Option<u16>) -> String {
@ -161,7 +167,7 @@ fn format_current_gfxclk(value: Option<u16>) -> String {
if v == u16::MAX { if v == u16::MAX {
"N/A".to_string() "N/A".to_string()
} else { } else {
format_clockspeed(Some(v as u64)) format_clockspeed(Some(v as u64), 1.0)
} }
} else { } else {
"N/A".to_string() "N/A".to_string()

View File

@ -12,7 +12,7 @@ use clocks_frame::ClocksFrame;
use gpu_stats_section::GpuStatsSection; use gpu_stats_section::GpuStatsSection;
use gtk::*; use gtk::*;
use gtk::{glib::clone, prelude::*}; use gtk::{glib::clone, prelude::*};
use lact_client::schema::{DeviceStats, SystemInfo}; use lact_client::schema::{DeviceInfo, DeviceStats, SystemInfo};
use performance_frame::PerformanceFrame; use performance_frame::PerformanceFrame;
// use power_cap_frame::PowerCapFrame; // use power_cap_frame::PowerCapFrame;
use std::collections::HashMap; use std::collections::HashMap;
@ -113,6 +113,17 @@ impl OcPage {
} }
} }
pub fn set_info(&self, info: &DeviceInfo) {
let vram_clock_ratio = info
.drm_info
.as_ref()
.map(|info| info.vram_clock_ratio)
.unwrap_or(1.0);
self.stats_section.set_vram_clock_ratio(vram_clock_ratio);
self.clocks_frame.set_vram_clock_ratio(vram_clock_ratio);
}
pub fn set_clocks_table(&self, table: Option<ClocksTableGen>) { pub fn set_clocks_table(&self, table: Option<ClocksTableGen>) {
match table { match table {
Some(table) => match self.clocks_frame.set_table(table) { Some(table) => match self.clocks_frame.set_table(table) {

View File

@ -0,0 +1,37 @@
using Gtk 4.0;
template $AdjustmentRow: Widget {
Label label {
label: bind template.title;
visible: bind template.visible;
halign: start;
}
Scale scale {
adjustment: adjustment;
orientation: horizontal;
hexpand: true;
digits: 0;
round-digits: 0;
value-pos: right;
margin-start: 5;
margin-end: 5;
visible: bind template.visible;
}
MenuButton value_button {
popover: Popover {
child: SpinButton value_spinbutton {
adjustment: adjustment;
};
};
direction: none;
visible: bind template.visible;
}
}
$OcAdjustment adjustment {
step-increment: 1;
page-increment: 10;
}

View File

@ -100,6 +100,7 @@ pub struct DrmInfo {
pub chip_class: String, pub chip_class: String,
pub compute_units: u32, pub compute_units: u32,
pub vram_type: String, pub vram_type: String,
pub vram_clock_ratio: f64,
pub vram_bit_width: u32, pub vram_bit_width: u32,
pub vram_max_bw: String, pub vram_max_bw: String,
pub l1_cache_per_cu: u32, pub l1_cache_per_cu: u32,