mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
feat: initial power states gui
This commit is contained in:
@@ -8,8 +8,8 @@ use nix::unistd::getuid;
|
||||
use schema::{
|
||||
amdgpu_sysfs::gpu_handle::{power_profile_mode::PowerProfileModesTable, PerformanceLevel},
|
||||
request::{ConfirmCommand, SetClocksCommand},
|
||||
ClocksInfo, DeviceInfo, DeviceListEntry, DeviceStats, FanControlMode, FanCurveMap, Request,
|
||||
Response, SystemInfo,
|
||||
ClocksInfo, DeviceInfo, DeviceListEntry, DeviceStats, FanControlMode, FanCurveMap, PowerStates,
|
||||
Request, Response, SystemInfo,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
@@ -134,6 +134,7 @@ impl DaemonClient {
|
||||
DevicePowerProfileModes,
|
||||
PowerProfileModesTable
|
||||
);
|
||||
request_with_id!(get_power_states, GetPowerStates, PowerStates);
|
||||
|
||||
pub fn set_performance_level(
|
||||
&self,
|
||||
|
||||
@@ -66,6 +66,7 @@ pub struct Gpu {
|
||||
pub max_voltage: Option<i32>,
|
||||
pub voltage_offset: Option<i32>,
|
||||
pub power_profile_mode_index: Option<u16>,
|
||||
#[serde(default)]
|
||||
pub power_states: HashMap<PowerLevelKind, Vec<u8>>,
|
||||
}
|
||||
|
||||
|
||||
@@ -413,8 +413,8 @@ impl GpuController {
|
||||
|
||||
pub fn get_power_states(&self, gpu_config: Option<&config::Gpu>) -> PowerStates {
|
||||
let core = self.get_power_states_kind(gpu_config, PowerLevelKind::CoreClock);
|
||||
let memory = self.get_power_states_kind(gpu_config, PowerLevelKind::MemoryClock);
|
||||
PowerStates { core, memory }
|
||||
let vram = self.get_power_states_kind(gpu_config, PowerLevelKind::MemoryClock);
|
||||
PowerStates { core, vram }
|
||||
}
|
||||
|
||||
fn get_power_states_kind<T>(
|
||||
|
||||
@@ -256,6 +256,20 @@ impl App {
|
||||
.performance_frame
|
||||
.set_power_profile_modes(maybe_modes_table);
|
||||
|
||||
match self
|
||||
.daemon_client
|
||||
.get_power_states(gpu_id)
|
||||
.and_then(|states| states.inner())
|
||||
{
|
||||
Ok(power_states) => {
|
||||
self.root_stack
|
||||
.oc_page
|
||||
.power_states_frame
|
||||
.set_power_states(power_states);
|
||||
}
|
||||
Err(err) => warn!("could not get power states: {err:?}"),
|
||||
}
|
||||
|
||||
// Show apply button on setting changes
|
||||
// This is done here because new widgets may appear after applying settings (like fan curve points) which should be connected
|
||||
let show_revealer = clone!(@strong self.apply_revealer as apply_revealer => move || {
|
||||
@@ -424,9 +438,17 @@ impl App {
|
||||
.daemon_client
|
||||
.batch_set_clocks_value(&gpu_id, clocks_commands)
|
||||
.context("Could not commit clocks settins")?;
|
||||
|
||||
self.ask_confirmation(gpu_id.clone(), delay);
|
||||
}
|
||||
|
||||
let enabled_states = self
|
||||
.root_stack
|
||||
.oc_page
|
||||
.power_states_frame
|
||||
.get_enabled_power_states();
|
||||
println!("{:?}", enabled_states);
|
||||
|
||||
self.set_initial(&gpu_id);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -68,18 +68,6 @@ mod imp {
|
||||
}
|
||||
}
|
||||
|
||||
// impl Default for VulkanFeaturesWindow {
|
||||
// fn default() -> Self {
|
||||
// Self {
|
||||
// model: RefCell::new(gio::ListStore::new::<VulkanFeature>().into()),
|
||||
// features_factory: Default::default(),
|
||||
// filter_model: Default::default(),
|
||||
// search_filter: Default::default(),
|
||||
// search_entry: Default::default(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for VulkanFeaturesWindow {
|
||||
fn constructed(&self) {
|
||||
|
||||
@@ -3,11 +3,13 @@ mod gpu_stats_section;
|
||||
mod oc_adjustment;
|
||||
mod performance_frame;
|
||||
mod power_cap_frame;
|
||||
mod power_states;
|
||||
|
||||
use self::power_states::power_states_frame::PowerStatesFrame;
|
||||
use clocks_frame::ClocksFrame;
|
||||
use gpu_stats_section::GpuStatsSection;
|
||||
use gtk::prelude::*;
|
||||
use gtk::*;
|
||||
use gtk::{glib::clone, prelude::*};
|
||||
use lact_client::schema::{
|
||||
amdgpu_sysfs::gpu_handle::{overdrive::ClocksTableGen, PerformanceLevel},
|
||||
DeviceStats, SystemInfo,
|
||||
@@ -25,6 +27,7 @@ pub struct OcPage {
|
||||
stats_section: GpuStatsSection,
|
||||
pub performance_frame: PerformanceFrame,
|
||||
power_cap_frame: PowerCapFrame,
|
||||
pub power_states_frame: PowerStatesFrame,
|
||||
pub clocks_frame: ClocksFrame,
|
||||
pub enable_overclocking_button: Option<Button>,
|
||||
}
|
||||
@@ -54,9 +57,18 @@ impl OcPage {
|
||||
let power_cap_frame = PowerCapFrame::new();
|
||||
let performance_level_frame = PerformanceFrame::new();
|
||||
let clocks_frame = ClocksFrame::new();
|
||||
let power_states_frame = PowerStatesFrame::new();
|
||||
|
||||
performance_level_frame.connect_settings_changed(
|
||||
clone!(@strong performance_level_frame, @strong power_states_frame => move || {
|
||||
let level = performance_level_frame.get_selected_performance_level();
|
||||
power_states_frame.set_sensitive(level == PerformanceLevel::Manual);
|
||||
}),
|
||||
);
|
||||
|
||||
vbox.append(&power_cap_frame.container);
|
||||
vbox.append(&performance_level_frame.container);
|
||||
vbox.append(&power_states_frame);
|
||||
vbox.append(&clocks_frame.container);
|
||||
|
||||
container.set_child(Some(&vbox));
|
||||
@@ -68,6 +80,7 @@ impl OcPage {
|
||||
clocks_frame,
|
||||
power_cap_frame,
|
||||
enable_overclocking_button,
|
||||
power_states_frame,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +116,8 @@ impl OcPage {
|
||||
pub fn connect_settings_changed<F: Fn() + 'static + Clone>(&self, f: F) {
|
||||
self.performance_frame.connect_settings_changed(f.clone());
|
||||
self.power_cap_frame.connect_cap_changed(f.clone());
|
||||
self.clocks_frame.connect_clocks_changed(f);
|
||||
self.clocks_frame.connect_clocks_changed(f.clone());
|
||||
self.power_states_frame.connect_values_changed(f);
|
||||
}
|
||||
|
||||
pub fn set_performance_level(&self, profile: Option<PerformanceLevel>) {
|
||||
|
||||
3
lact-gui/src/app/root_stack/oc_page/power_states/mod.rs
Normal file
3
lact-gui/src/app/root_stack/oc_page/power_states/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
mod power_state_row;
|
||||
pub mod power_states_frame;
|
||||
mod power_states_list;
|
||||
@@ -0,0 +1,69 @@
|
||||
use gtk::glib::{self, Object};
|
||||
use lact_client::schema::PowerState;
|
||||
use std::fmt::Display;
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct PowerStateRow(ObjectSubclass<imp::PowerStateRow>)
|
||||
@extends gtk::Widget,
|
||||
@implements gtk::Accessible, gtk::Buildable;
|
||||
}
|
||||
|
||||
impl PowerStateRow {
|
||||
pub fn new<T: Display>(power_state: PowerState<T>, index: usize, value_suffix: &str) -> Self {
|
||||
let title = format!("{}: {} {}", index, power_state.value, value_suffix);
|
||||
Object::builder()
|
||||
.property("enabled", power_state.enabled)
|
||||
.property("title", title)
|
||||
.property("index", index as u64)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
mod imp {
|
||||
use gtk::{
|
||||
glib::{self, subclass::InitializingObject, Properties},
|
||||
prelude::ObjectExt,
|
||||
subclass::{
|
||||
prelude::*,
|
||||
widget::{CompositeTemplateClass, WidgetImpl},
|
||||
},
|
||||
CompositeTemplate,
|
||||
};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::atomic::{AtomicBool, AtomicU64},
|
||||
};
|
||||
|
||||
#[derive(CompositeTemplate, Default, Properties)]
|
||||
#[properties(wrapper_type = super::PowerStateRow)]
|
||||
#[template(file = "ui/oc_page/power_state_row.blp")]
|
||||
pub struct PowerStateRow {
|
||||
#[property(get, set)]
|
||||
title: RefCell<String>,
|
||||
#[property(get, set)]
|
||||
enabled: AtomicBool,
|
||||
#[property(get, set)]
|
||||
index: AtomicU64,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for PowerStateRow {
|
||||
const NAME: &'static str = "PowerStateRow";
|
||||
type Type = super::PowerStateRow;
|
||||
type ParentType = gtk::Box;
|
||||
|
||||
fn class_init(class: &mut Self::Class) {
|
||||
class.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for PowerStateRow {}
|
||||
|
||||
impl WidgetImpl for PowerStateRow {}
|
||||
impl BoxImpl for PowerStateRow {}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use gtk::glib::{self, subclass::types::ObjectSubclassIsExt, Object};
|
||||
use lact_client::schema::{amdgpu_sysfs::gpu_handle::PowerLevelKind, PowerStates};
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct PowerStatesFrame(ObjectSubclass<imp::PowerStatesFrame>)
|
||||
@extends gtk::Widget,
|
||||
@implements gtk::Accessible, gtk::Buildable;
|
||||
}
|
||||
|
||||
impl PowerStatesFrame {
|
||||
pub fn new() -> Self {
|
||||
Object::builder().build()
|
||||
}
|
||||
|
||||
pub fn set_power_states(&self, states: PowerStates) {
|
||||
let imp = self.imp();
|
||||
imp.core_states_list.set_power_states(states.core, "MHz");
|
||||
imp.vram_states_list.set_power_states(states.vram, "MHz");
|
||||
}
|
||||
|
||||
pub fn connect_values_changed<F: Fn() + 'static + Clone>(&self, f: F) {
|
||||
let imp = self.imp();
|
||||
imp.core_states_list.connect_values_changed(f.clone());
|
||||
imp.vram_states_list.connect_values_changed(f);
|
||||
}
|
||||
|
||||
pub fn get_enabled_power_states(&self) -> HashMap<PowerLevelKind, Vec<usize>> {
|
||||
let imp = self.imp();
|
||||
let core_states = imp.core_states_list.get_enabled_power_states();
|
||||
let vram_states = imp.vram_states_list.get_enabled_power_states();
|
||||
|
||||
[
|
||||
(PowerLevelKind::CoreClock, core_states),
|
||||
(PowerLevelKind::MemoryClock, vram_states),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PowerStatesFrame {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
mod imp {
|
||||
use crate::app::root_stack::oc_page::power_states::power_states_list::PowerStatesList;
|
||||
use gtk::{
|
||||
glib::{self, subclass::InitializingObject, StaticTypeExt},
|
||||
subclass::{
|
||||
prelude::*,
|
||||
widget::{CompositeTemplateClass, WidgetImpl},
|
||||
},
|
||||
CompositeTemplate,
|
||||
};
|
||||
|
||||
#[derive(CompositeTemplate, Default)]
|
||||
#[template(file = "ui/oc_page/power_states_frame.blp")]
|
||||
pub struct PowerStatesFrame {
|
||||
#[template_child]
|
||||
pub core_states_list: TemplateChild<PowerStatesList>,
|
||||
#[template_child]
|
||||
pub vram_states_list: TemplateChild<PowerStatesList>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for PowerStatesFrame {
|
||||
const NAME: &'static str = "PowerStatesFrame";
|
||||
type Type = super::PowerStatesFrame;
|
||||
type ParentType = gtk::Box;
|
||||
|
||||
fn class_init(class: &mut Self::Class) {
|
||||
PowerStatesList::ensure_type();
|
||||
class.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
// #[glib::derived_properties]
|
||||
impl ObjectImpl for PowerStatesFrame {}
|
||||
|
||||
impl WidgetImpl for PowerStatesFrame {}
|
||||
impl BoxImpl for PowerStatesFrame {}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
use crate::app::root_stack::oc_page::power_states::power_state_row::PowerStateRow;
|
||||
use gtk::{
|
||||
gio,
|
||||
glib::{self, clone, subclass::types::ObjectSubclassIsExt, Cast, Object},
|
||||
prelude::{ListBoxRowExt, WidgetExt},
|
||||
ListBoxRow, Widget,
|
||||
};
|
||||
use lact_client::schema::PowerState;
|
||||
use std::fmt::Display;
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct PowerStatesList(ObjectSubclass<imp::PowerStatesList>)
|
||||
@extends gtk::Widget,
|
||||
@implements gtk::Accessible, gtk::Buildable;
|
||||
}
|
||||
|
||||
impl PowerStatesList {
|
||||
pub fn new(title: &str) -> Self {
|
||||
Object::builder().property("title", title).build()
|
||||
}
|
||||
|
||||
pub fn get_enabled_power_states(&self) -> Vec<usize> {
|
||||
self.rows()
|
||||
.iter()
|
||||
.filter(|row| row.enabled())
|
||||
.map(|row| row.index() as usize)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn set_power_states<T: Display>(
|
||||
&self,
|
||||
power_states: Vec<PowerState<T>>,
|
||||
value_suffix: &str,
|
||||
) {
|
||||
let store = gio::ListStore::new::<PowerStateRow>();
|
||||
for (i, state) in power_states.into_iter().enumerate() {
|
||||
let row = PowerStateRow::new(state, i, value_suffix);
|
||||
store.append(&row);
|
||||
}
|
||||
|
||||
self.imp().states_listbox.bind_model(Some(&store), |obj| {
|
||||
obj.clone().downcast::<Widget>().unwrap()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn connect_values_changed<F: Fn() + 'static + Clone>(&self, f: F) {
|
||||
for row in self.rows() {
|
||||
row.connect_enabled_notify(clone!(@strong f => move |_| f()));
|
||||
}
|
||||
}
|
||||
|
||||
fn rows(&self) -> Vec<PowerStateRow> {
|
||||
let children = self.imp().states_listbox.observe_children();
|
||||
children
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(|object| {
|
||||
let item = object.downcast::<ListBoxRow>().unwrap();
|
||||
let child = item.child()?;
|
||||
let row = child
|
||||
.downcast::<PowerStateRow>()
|
||||
.expect("ListBoxRow child must be a PowerStateRow");
|
||||
Some(row)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
mod imp {
|
||||
use gtk::{
|
||||
glib::{self, subclass::InitializingObject, Properties},
|
||||
prelude::ObjectExt,
|
||||
subclass::{
|
||||
prelude::*,
|
||||
widget::{CompositeTemplateClass, WidgetImpl},
|
||||
},
|
||||
CompositeTemplate, ListBox,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[derive(CompositeTemplate, Default, Properties)]
|
||||
#[properties(wrapper_type = super::PowerStatesList)]
|
||||
#[template(file = "ui/oc_page/power_states_list.blp")]
|
||||
pub struct PowerStatesList {
|
||||
#[property(get, set)]
|
||||
title: RefCell<String>,
|
||||
|
||||
#[template_child]
|
||||
pub states_listbox: TemplateChild<ListBox>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for PowerStatesList {
|
||||
const NAME: &'static str = "PowerStatesList";
|
||||
type Type = super::PowerStatesList;
|
||||
type ParentType = gtk::Frame;
|
||||
|
||||
fn class_init(class: &mut Self::Class) {
|
||||
class.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for PowerStatesList {}
|
||||
|
||||
impl WidgetImpl for PowerStatesList {}
|
||||
impl FrameImpl for PowerStatesList {}
|
||||
}
|
||||
12
lact-gui/ui/oc_page/power_state_row.blp
Normal file
12
lact-gui/ui/oc_page/power_state_row.blp
Normal file
@@ -0,0 +1,12 @@
|
||||
using Gtk 4.0;
|
||||
|
||||
template $PowerStateRow: Box {
|
||||
orientation: horizontal;
|
||||
spacing: 5;
|
||||
|
||||
CheckButton {
|
||||
active: bind template.enabled bidirectional;
|
||||
label: bind template.title;
|
||||
hexpand: true;
|
||||
}
|
||||
}
|
||||
24
lact-gui/ui/oc_page/power_states_frame.blp
Normal file
24
lact-gui/ui/oc_page/power_states_frame.blp
Normal file
@@ -0,0 +1,24 @@
|
||||
using Gtk 4.0;
|
||||
|
||||
template $PowerStatesFrame: Box {
|
||||
Expander {
|
||||
label: "Power states";
|
||||
|
||||
Box {
|
||||
margin-start: 10;
|
||||
margin-end: 10;
|
||||
margin-top: 10;
|
||||
margin-bottom: 10;
|
||||
spacing: 10;
|
||||
orientation: horizontal;
|
||||
|
||||
$PowerStatesList core_states_list {
|
||||
title: "GPU power states";
|
||||
}
|
||||
|
||||
$PowerStatesList vram_states_list {
|
||||
title: "VRAM power states";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
lact-gui/ui/oc_page/power_states_list.blp
Normal file
16
lact-gui/ui/oc_page/power_states_list.blp
Normal file
@@ -0,0 +1,16 @@
|
||||
using Gtk 4.0;
|
||||
|
||||
template $PowerStatesList: Frame {
|
||||
hexpand: true;
|
||||
|
||||
[label]
|
||||
Label {
|
||||
label: bind template.title;
|
||||
margin-start: 5;
|
||||
margin-end: 5;
|
||||
}
|
||||
|
||||
ListBox states_listbox {
|
||||
selection-mode: none;
|
||||
}
|
||||
}
|
||||
@@ -228,7 +228,7 @@ pub struct PowerStats {
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct PowerStates {
|
||||
pub core: Vec<PowerState<u64>>,
|
||||
pub memory: Vec<PowerState<u64>>,
|
||||
pub vram: Vec<PowerState<u64>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
|
||||
Reference in New Issue
Block a user