mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
wip
This commit is contained in:
parent
0eea61cc7d
commit
a796664029
@ -25,7 +25,6 @@ use header::{
|
|||||||
profile_rule_window::ProfileRuleWindowMsg, Header, HeaderMsg, PROFILE_RULE_WINDOW_BROKER,
|
profile_rule_window::ProfileRuleWindowMsg, Header, HeaderMsg, PROFILE_RULE_WINDOW_BROKER,
|
||||||
};
|
};
|
||||||
use lact_client::{ConnectionStatusMsg, DaemonClient};
|
use lact_client::{ConnectionStatusMsg, DaemonClient};
|
||||||
use lact_daemon::MODULE_CONF_PATH;
|
|
||||||
use lact_schema::{
|
use lact_schema::{
|
||||||
args::GuiArgs,
|
args::GuiArgs,
|
||||||
request::{ConfirmCommand, SetClocksCommand},
|
request::{ConfirmCommand, SetClocksCommand},
|
||||||
@ -33,8 +32,11 @@ use lact_schema::{
|
|||||||
};
|
};
|
||||||
use msg::AppMsg;
|
use msg::AppMsg;
|
||||||
use pages::{
|
use pages::{
|
||||||
info_page::InformationPage, oc_page::OcPage, software_page::SoftwarePage,
|
info_page::InformationPage,
|
||||||
thermals_page::ThermalsPage, PageUpdate,
|
oc_page::{OcPage, OcPageMsg},
|
||||||
|
software_page::SoftwarePage,
|
||||||
|
thermals_page::ThermalsPage,
|
||||||
|
PageUpdate,
|
||||||
};
|
};
|
||||||
use relm4::{
|
use relm4::{
|
||||||
actions::{RelmAction, RelmActionGroup},
|
actions::{RelmAction, RelmActionGroup},
|
||||||
@ -62,7 +64,7 @@ pub struct AppModel {
|
|||||||
graphs_window: relm4::Controller<GraphsWindow>,
|
graphs_window: relm4::Controller<GraphsWindow>,
|
||||||
|
|
||||||
info_page: relm4::Controller<InformationPage>,
|
info_page: relm4::Controller<InformationPage>,
|
||||||
oc_page: OcPage,
|
oc_page: relm4::Controller<OcPage>,
|
||||||
thermals_page: ThermalsPage,
|
thermals_page: ThermalsPage,
|
||||||
software_page: relm4::Controller<SoftwarePage>,
|
software_page: relm4::Controller<SoftwarePage>,
|
||||||
|
|
||||||
@ -101,7 +103,7 @@ impl AsyncComponent for AppModel {
|
|||||||
set_margin_end: 30,
|
set_margin_end: 30,
|
||||||
|
|
||||||
add_titled[Some("info_page"), "Information"] = model.info_page.widget(),
|
add_titled[Some("info_page"), "Information"] = model.info_page.widget(),
|
||||||
add_titled[Some("oc_page"), "OC"] = &model.oc_page.container.clone(),
|
add_titled[Some("oc_page"), "OC"] = model.oc_page.widget(),
|
||||||
add_titled[Some("thermals_page"), "Thermals"] = &model.thermals_page.container.clone(),
|
add_titled[Some("thermals_page"), "Thermals"] = &model.thermals_page.container.clone(),
|
||||||
add_titled[Some("software_page"), "Software"] = model.software_page.widget(),
|
add_titled[Some("software_page"), "Software"] = model.software_page.widget(),
|
||||||
},
|
},
|
||||||
@ -165,6 +167,7 @@ impl AsyncComponent for AppModel {
|
|||||||
.get_system_info()
|
.get_system_info()
|
||||||
.await
|
.await
|
||||||
.expect("Could not fetch system info");
|
.expect("Could not fetch system info");
|
||||||
|
let system_info = Rc::new(system_info);
|
||||||
|
|
||||||
let devices = daemon_client
|
let devices = daemon_client
|
||||||
.list_devices()
|
.list_devices()
|
||||||
@ -178,7 +181,9 @@ impl AsyncComponent for AppModel {
|
|||||||
|
|
||||||
let info_page = InformationPage::builder().launch(()).detach();
|
let info_page = InformationPage::builder().launch(()).detach();
|
||||||
|
|
||||||
let oc_page = OcPage::new(&system_info);
|
let oc_page = OcPage::builder()
|
||||||
|
.launch(system_info.clone())
|
||||||
|
.forward(sender.input_sender(), |msg| msg);
|
||||||
let thermals_page = ThermalsPage::new(&system_info);
|
let thermals_page = ThermalsPage::new(&system_info);
|
||||||
|
|
||||||
let software_page = SoftwarePage::builder()
|
let software_page = SoftwarePage::builder()
|
||||||
@ -193,13 +198,6 @@ impl AsyncComponent for AppModel {
|
|||||||
.launch(())
|
.launch(())
|
||||||
.forward(sender.input_sender(), |msg| msg);
|
.forward(sender.input_sender(), |msg| msg);
|
||||||
|
|
||||||
oc_page.clocks_frame.connect_clocks_reset(clone!(
|
|
||||||
#[strong]
|
|
||||||
sender,
|
|
||||||
move || {
|
|
||||||
sender.input(AppMsg::ResetClocks);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
thermals_page.connect_reset_pmfw(clone!(
|
thermals_page.connect_reset_pmfw(clone!(
|
||||||
#[strong]
|
#[strong]
|
||||||
sender,
|
sender,
|
||||||
@ -208,21 +206,6 @@ impl AsyncComponent for AppModel {
|
|||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
if let Some(ref button) = oc_page.enable_overclocking_button {
|
|
||||||
button.connect_clicked(clone!(
|
|
||||||
#[strong]
|
|
||||||
sender,
|
|
||||||
move |_| {
|
|
||||||
sender.input(AppMsg::ask_confirmation(
|
|
||||||
AppMsg::EnableOverdrive,
|
|
||||||
"Enable Overclocking",
|
|
||||||
format!("This will enable the overdrive feature of the amdgpu driver by creating a file at <b>{MODULE_CONF_PATH}</b> and updating the initramfs. Are you sure you want to do this?"),
|
|
||||||
gtk::ButtonsType::OkCancel,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let graphs_window = GraphsWindow::builder().launch(()).detach();
|
let graphs_window = GraphsWindow::builder().launch(()).detach();
|
||||||
|
|
||||||
let model = AppModel {
|
let model = AppModel {
|
||||||
@ -281,6 +264,9 @@ impl AppModel {
|
|||||||
) -> Result<(), Arc<anyhow::Error>> {
|
) -> Result<(), Arc<anyhow::Error>> {
|
||||||
match msg {
|
match msg {
|
||||||
AppMsg::Error(err) => return Err(err),
|
AppMsg::Error(err) => return Err(err),
|
||||||
|
AppMsg::SettingsChanged => {
|
||||||
|
self.apply_revealer.emit(ApplyRevealerMsg::Show);
|
||||||
|
}
|
||||||
AppMsg::ReloadProfiles { include_state } => {
|
AppMsg::ReloadProfiles { include_state } => {
|
||||||
self.reload_profiles(include_state).await?;
|
self.reload_profiles(include_state).await?;
|
||||||
sender.input(AppMsg::ReloadData { full: false });
|
sender.input(AppMsg::ReloadData { full: false });
|
||||||
@ -329,10 +315,14 @@ impl AppModel {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
AppMsg::Stats(stats) => {
|
AppMsg::Stats(stats) => {
|
||||||
self.info_page.emit(PageUpdate::Stats(stats.clone()));
|
let update = PageUpdate::Stats(stats.clone());
|
||||||
|
self.info_page.emit(update.clone());
|
||||||
|
self.oc_page.emit(OcPageMsg::Update {
|
||||||
|
update,
|
||||||
|
initial: false,
|
||||||
|
});
|
||||||
|
|
||||||
self.thermals_page.set_stats(&stats, false);
|
self.thermals_page.set_stats(&stats, false);
|
||||||
self.oc_page.set_stats(&stats, false);
|
|
||||||
|
|
||||||
self.graphs_window.emit(GraphsWindowMsg::Stats(stats));
|
self.graphs_window.emit(GraphsWindowMsg::Stats(stats));
|
||||||
}
|
}
|
||||||
@ -454,9 +444,12 @@ impl AppModel {
|
|||||||
sender.input(AppMsg::Error(Arc::new(anyhow!("Nvidia driver detected, but the management library could not be loaded. Check lact service status for more information."))));
|
sender.input(AppMsg::Error(Arc::new(anyhow!("Nvidia driver detected, but the management library could not be loaded. Check lact service status for more information."))));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.info_page.emit(PageUpdate::Info(info.clone()));
|
let update = PageUpdate::Info(info.clone());
|
||||||
|
self.info_page.emit(update.clone());
|
||||||
self.oc_page.set_info(&info);
|
self.oc_page.emit(OcPageMsg::Update {
|
||||||
|
update,
|
||||||
|
initial: true,
|
||||||
|
});
|
||||||
|
|
||||||
let vram_clock_ratio = info
|
let vram_clock_ratio = info
|
||||||
.drm_info
|
.drm_info
|
||||||
@ -493,10 +486,14 @@ impl AppModel {
|
|||||||
.context("Could not fetch stats")?;
|
.context("Could not fetch stats")?;
|
||||||
let stats = Arc::new(stats);
|
let stats = Arc::new(stats);
|
||||||
|
|
||||||
self.oc_page.set_stats(&stats, true);
|
|
||||||
self.thermals_page.set_stats(&stats, true);
|
self.thermals_page.set_stats(&stats, true);
|
||||||
|
|
||||||
self.info_page.emit(PageUpdate::Stats(stats));
|
let update = PageUpdate::Stats(stats.clone());
|
||||||
|
self.info_page.emit(update.clone());
|
||||||
|
self.oc_page.emit(OcPageMsg::Update {
|
||||||
|
update,
|
||||||
|
initial: true,
|
||||||
|
});
|
||||||
|
|
||||||
let maybe_clocks_table = match self.daemon_client.get_device_clocks_info(&gpu_id).await {
|
let maybe_clocks_table = match self.daemon_client.get_device_clocks_info(&gpu_id).await {
|
||||||
Ok(info) => info.table,
|
Ok(info) => info.table,
|
||||||
@ -505,7 +502,8 @@ impl AppModel {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.oc_page.set_clocks_table(maybe_clocks_table);
|
self.oc_page
|
||||||
|
.emit(OcPageMsg::ClocksTable(maybe_clocks_table));
|
||||||
|
|
||||||
let maybe_modes_table = match self
|
let maybe_modes_table = match self
|
||||||
.daemon_client
|
.daemon_client
|
||||||
@ -519,12 +517,12 @@ impl AppModel {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.oc_page
|
self.oc_page
|
||||||
.performance_frame
|
.emit(OcPageMsg::ProfileModesTable(maybe_modes_table));
|
||||||
.set_power_profile_modes(maybe_modes_table);
|
|
||||||
|
|
||||||
match self.daemon_client.get_power_states(&gpu_id).await {
|
match self.daemon_client.get_power_states(&gpu_id).await {
|
||||||
Ok(power_states) => {
|
Ok(power_states) => {
|
||||||
self.oc_page
|
self.oc_page
|
||||||
|
.model()
|
||||||
.power_states_frame
|
.power_states_frame
|
||||||
.set_power_states(power_states);
|
.set_power_states(power_states);
|
||||||
}
|
}
|
||||||
@ -544,8 +542,6 @@ impl AppModel {
|
|||||||
self.thermals_page
|
self.thermals_page
|
||||||
.connect_settings_changed(show_revealer.clone());
|
.connect_settings_changed(show_revealer.clone());
|
||||||
|
|
||||||
self.oc_page.connect_settings_changed(show_revealer);
|
|
||||||
|
|
||||||
self.apply_revealer
|
self.apply_revealer
|
||||||
.sender()
|
.sender()
|
||||||
.send(ApplyRevealerMsg::Hide)
|
.send(ApplyRevealerMsg::Hide)
|
||||||
@ -571,7 +567,8 @@ impl AppModel {
|
|||||||
|
|
||||||
debug!("applying settings on gpu {gpu_id}");
|
debug!("applying settings on gpu {gpu_id}");
|
||||||
|
|
||||||
if let Some(cap) = self.oc_page.get_power_cap() {
|
let cap = self.oc_page.model().get_power_cap();
|
||||||
|
if let Some(cap) = cap {
|
||||||
self.daemon_client
|
self.daemon_client
|
||||||
.set_power_cap(&gpu_id, Some(cap))
|
.set_power_cap(&gpu_id, Some(cap))
|
||||||
.await
|
.await
|
||||||
@ -593,7 +590,8 @@ impl AppModel {
|
|||||||
.await
|
.await
|
||||||
.context("Could not commit config")?;
|
.context("Could not commit config")?;
|
||||||
|
|
||||||
if let Some(level) = self.oc_page.get_performance_level() {
|
let performance_level = self.oc_page.model().get_performance_level();
|
||||||
|
if let Some(level) = performance_level {
|
||||||
self.daemon_client
|
self.daemon_client
|
||||||
.set_performance_level(&gpu_id, level)
|
.set_performance_level(&gpu_id, level)
|
||||||
.await
|
.await
|
||||||
@ -605,10 +603,12 @@ impl AppModel {
|
|||||||
|
|
||||||
let mode_index = self
|
let mode_index = self
|
||||||
.oc_page
|
.oc_page
|
||||||
|
.model()
|
||||||
.performance_frame
|
.performance_frame
|
||||||
.get_selected_power_profile_mode();
|
.get_selected_power_profile_mode();
|
||||||
let custom_heuristics = self
|
let custom_heuristics = self
|
||||||
.oc_page
|
.oc_page
|
||||||
|
.model()
|
||||||
.performance_frame
|
.performance_frame
|
||||||
.get_power_profile_mode_custom_heuristics();
|
.get_power_profile_mode_custom_heuristics();
|
||||||
|
|
||||||
@ -645,11 +645,11 @@ impl AppModel {
|
|||||||
.context("Could not commit config")?;
|
.context("Could not commit config")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let clocks_commands = self.oc_page.clocks_frame.get_commands();
|
let clocks_commands = self.oc_page.model().clocks_frame.get_commands();
|
||||||
|
|
||||||
debug!("applying clocks commands {clocks_commands:#?}");
|
debug!("applying clocks commands {clocks_commands:#?}");
|
||||||
|
|
||||||
let enabled_power_states = self.oc_page.get_enabled_power_states();
|
let enabled_power_states = self.oc_page.model().get_enabled_power_states();
|
||||||
|
|
||||||
for (kind, states) in enabled_power_states {
|
for (kind, states) in enabled_power_states {
|
||||||
if !states.is_empty() {
|
if !states.is_empty() {
|
||||||
|
@ -12,6 +12,7 @@ pub enum AppMsg {
|
|||||||
Stats(Arc<DeviceStats>),
|
Stats(Arc<DeviceStats>),
|
||||||
ApplyChanges,
|
ApplyChanges,
|
||||||
RevertChanges,
|
RevertChanges,
|
||||||
|
SettingsChanged,
|
||||||
ResetClocks,
|
ResetClocks,
|
||||||
ResetPmfw,
|
ResetPmfw,
|
||||||
ShowGraphsWindow,
|
ShowGraphsWindow,
|
||||||
|
@ -8,7 +8,7 @@ use gtk::{prelude::*, *};
|
|||||||
use lact_schema::{DeviceInfo, DeviceStats};
|
use lact_schema::{DeviceInfo, DeviceStats};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum PageUpdate {
|
pub enum PageUpdate {
|
||||||
Info(Arc<DeviceInfo>),
|
Info(Arc<DeviceInfo>),
|
||||||
Stats(Arc<DeviceStats>),
|
Stats(Arc<DeviceStats>),
|
||||||
|
223
lact-gui/src/app/pages/oc_page.rs
Normal file
223
lact-gui/src/app/pages/oc_page.rs
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
mod clocks_frame;
|
||||||
|
mod gpu_stats_section;
|
||||||
|
mod performance_frame;
|
||||||
|
mod power_cap_section;
|
||||||
|
mod power_profile;
|
||||||
|
mod power_states;
|
||||||
|
|
||||||
|
use super::PageUpdate;
|
||||||
|
use crate::app::msg::AppMsg;
|
||||||
|
use amdgpu_sysfs::gpu_handle::{
|
||||||
|
power_profile_mode::PowerProfileModesTable, PerformanceLevel, PowerLevelKind,
|
||||||
|
};
|
||||||
|
use clocks_frame::ClocksFrame;
|
||||||
|
use gpu_stats_section::GpuStatsSection;
|
||||||
|
use gtk::{
|
||||||
|
glib::clone,
|
||||||
|
pango,
|
||||||
|
prelude::{BoxExt, ButtonExt, FrameExt, OrientableExt, WidgetExt},
|
||||||
|
};
|
||||||
|
use lact_daemon::MODULE_CONF_PATH;
|
||||||
|
use lact_schema::{ClocksTable, SystemInfo};
|
||||||
|
use performance_frame::PerformanceFrame;
|
||||||
|
use power_cap_section::PowerCapSection;
|
||||||
|
use power_states::power_states_frame::PowerStatesFrame;
|
||||||
|
use relm4::{ComponentParts, ComponentSender, RelmWidgetExt};
|
||||||
|
use std::{collections::HashMap, rc::Rc};
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
|
const OVERCLOCKING_DISABLED_TEXT: &str = "Overclocking support is not enabled! \
|
||||||
|
You can still change basic settings, but the more advanced clocks and voltage control will not be available.";
|
||||||
|
|
||||||
|
pub struct OcPage {
|
||||||
|
stats_section: GpuStatsSection,
|
||||||
|
pub performance_frame: PerformanceFrame,
|
||||||
|
power_cap_section: PowerCapSection,
|
||||||
|
pub power_states_frame: PowerStatesFrame,
|
||||||
|
pub clocks_frame: ClocksFrame,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum OcPageMsg {
|
||||||
|
Update { update: PageUpdate, initial: bool },
|
||||||
|
ClocksTable(Option<ClocksTable>),
|
||||||
|
ProfileModesTable(Option<PowerProfileModesTable>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[relm4::component(pub)]
|
||||||
|
impl relm4::SimpleComponent for OcPage {
|
||||||
|
type Init = Rc<SystemInfo>;
|
||||||
|
type Input = OcPageMsg;
|
||||||
|
type Output = AppMsg;
|
||||||
|
|
||||||
|
view! {
|
||||||
|
gtk::ScrolledWindow {
|
||||||
|
set_hscrollbar_policy: gtk::PolicyType::Never,
|
||||||
|
|
||||||
|
gtk::Box {
|
||||||
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
set_spacing: 15,
|
||||||
|
set_margin_horizontal: 20,
|
||||||
|
|
||||||
|
gtk::Frame {
|
||||||
|
set_visible: system_info.amdgpu_overdrive_enabled == Some(false),
|
||||||
|
set_label_align: 0.3,
|
||||||
|
|
||||||
|
gtk::Box {
|
||||||
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
set_spacing: 2,
|
||||||
|
set_margin_all: 10,
|
||||||
|
|
||||||
|
gtk::Label {
|
||||||
|
set_markup: OVERCLOCKING_DISABLED_TEXT,
|
||||||
|
set_wrap: true,
|
||||||
|
set_wrap_mode: pango::WrapMode::Word,
|
||||||
|
},
|
||||||
|
|
||||||
|
gtk::Button {
|
||||||
|
set_label: "Enable Overclocking",
|
||||||
|
set_halign: gtk::Align::End,
|
||||||
|
|
||||||
|
connect_clicked[sender] => move |_| {
|
||||||
|
sender.output(AppMsg::ask_confirmation(
|
||||||
|
AppMsg::EnableOverdrive,
|
||||||
|
"Enable Overclocking",
|
||||||
|
format!("This will enable the overdrive feature of the amdgpu driver by creating a file at <b>{MODULE_CONF_PATH}</b> and updating the initramfs. Are you sure you want to do this?"),
|
||||||
|
gtk::ButtonsType::OkCancel,
|
||||||
|
)).expect("Channel closed");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
model.stats_section.clone(),
|
||||||
|
model.power_cap_section.clone(),
|
||||||
|
model.performance_frame.container.clone(),
|
||||||
|
model.power_states_frame.clone(),
|
||||||
|
model.clocks_frame.container.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(
|
||||||
|
system_info: Self::Init,
|
||||||
|
root: Self::Root,
|
||||||
|
sender: ComponentSender<Self>,
|
||||||
|
) -> ComponentParts<Self> {
|
||||||
|
let model = Self {
|
||||||
|
stats_section: GpuStatsSection::new(),
|
||||||
|
performance_frame: PerformanceFrame::new(),
|
||||||
|
power_cap_section: PowerCapSection::new(),
|
||||||
|
power_states_frame: PowerStatesFrame::new(),
|
||||||
|
clocks_frame: ClocksFrame::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let widgets = view_output!();
|
||||||
|
|
||||||
|
model.clocks_frame.connect_clocks_reset(move || {
|
||||||
|
sender.output(AppMsg::ResetClocks).expect("Channel closed")
|
||||||
|
});
|
||||||
|
|
||||||
|
ComponentParts { model, widgets }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) {
|
||||||
|
match msg {
|
||||||
|
OcPageMsg::Update { update, initial } => match update {
|
||||||
|
PageUpdate::Stats(stats) => {
|
||||||
|
self.stats_section.set_stats(&stats);
|
||||||
|
self.power_states_frame.set_stats(&stats);
|
||||||
|
if initial {
|
||||||
|
self.power_cap_section
|
||||||
|
.set_max_value(stats.power.cap_max.unwrap_or_default());
|
||||||
|
self.power_cap_section
|
||||||
|
.set_min_value(stats.power.cap_min.unwrap_or_default());
|
||||||
|
self.power_cap_section
|
||||||
|
.set_default_value(stats.power.cap_default.unwrap_or_default());
|
||||||
|
|
||||||
|
if let Some(current_cap) = stats.power.cap_current {
|
||||||
|
self.power_cap_section.set_initial_value(current_cap);
|
||||||
|
self.power_cap_section.set_visible(true);
|
||||||
|
} else {
|
||||||
|
self.power_cap_section.set_visible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
match stats.performance_level {
|
||||||
|
Some(profile) => {
|
||||||
|
self.performance_frame.show();
|
||||||
|
self.performance_frame.set_active_level(profile);
|
||||||
|
}
|
||||||
|
None => self.performance_frame.hide(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PageUpdate::Info(info) => {
|
||||||
|
let vram_clock_ratio = info
|
||||||
|
.drm_info
|
||||||
|
.as_ref()
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
OcPageMsg::ClocksTable(table) => match table {
|
||||||
|
Some(table) => match self.clocks_frame.set_table(table) {
|
||||||
|
Ok(()) => {
|
||||||
|
self.clocks_frame.show();
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!("got invalid clocks table: {err:?}");
|
||||||
|
self.clocks_frame.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
self.clocks_frame.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
OcPageMsg::ProfileModesTable(modes_table) => {
|
||||||
|
self.performance_frame.set_power_profile_modes(modes_table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let f = move || {
|
||||||
|
sender
|
||||||
|
.output(AppMsg::SettingsChanged)
|
||||||
|
.expect("Channel closed")
|
||||||
|
};
|
||||||
|
self.performance_frame.connect_settings_changed(f.clone());
|
||||||
|
self.power_cap_section.connect_current_value_notify(clone!(
|
||||||
|
#[strong]
|
||||||
|
f,
|
||||||
|
move |_| f()
|
||||||
|
));
|
||||||
|
self.clocks_frame.connect_clocks_changed(f.clone());
|
||||||
|
self.power_states_frame.connect_values_changed(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OcPage {
|
||||||
|
pub fn get_performance_level(&self) -> Option<PerformanceLevel> {
|
||||||
|
if self.performance_frame.get_visibility() {
|
||||||
|
let level = self.performance_frame.get_selected_performance_level();
|
||||||
|
Some(level)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_power_cap(&self) -> Option<f64> {
|
||||||
|
self.power_cap_section.get_user_cap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_enabled_power_states(&self) -> HashMap<PowerLevelKind, Vec<u8>> {
|
||||||
|
if self.performance_frame.get_selected_performance_level() == PerformanceLevel::Manual {
|
||||||
|
self.power_states_frame.get_enabled_power_states()
|
||||||
|
} else {
|
||||||
|
HashMap::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,222 +0,0 @@
|
|||||||
mod clocks_frame;
|
|
||||||
mod gpu_stats_section;
|
|
||||||
mod performance_frame;
|
|
||||||
mod power_cap_section;
|
|
||||||
mod power_profile;
|
|
||||||
mod power_states;
|
|
||||||
|
|
||||||
use self::power_cap_section::PowerCapSection;
|
|
||||||
use self::power_states::power_states_frame::PowerStatesFrame;
|
|
||||||
use amdgpu_sysfs::gpu_handle::{PerformanceLevel, PowerLevelKind};
|
|
||||||
use clocks_frame::ClocksFrame;
|
|
||||||
use gpu_stats_section::GpuStatsSection;
|
|
||||||
use gtk::*;
|
|
||||||
use gtk::{glib::clone, prelude::*};
|
|
||||||
use lact_client::schema::{DeviceInfo, DeviceStats, SystemInfo};
|
|
||||||
use lact_schema::ClocksTable;
|
|
||||||
use performance_frame::PerformanceFrame;
|
|
||||||
// use power_cap_frame::PowerCapFrame;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use tracing::warn;
|
|
||||||
|
|
||||||
const OVERCLOCKING_DISABLED_TEXT: &str = "Overclocking support is not enabled! \
|
|
||||||
You can still change basic settings, but the more advanced clocks and voltage control will not be available.";
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct OcPage {
|
|
||||||
pub container: ScrolledWindow,
|
|
||||||
stats_section: GpuStatsSection,
|
|
||||||
pub performance_frame: PerformanceFrame,
|
|
||||||
// power_cap_frame: PowerCapFrame,
|
|
||||||
power_cap_section: PowerCapSection,
|
|
||||||
pub power_states_frame: PowerStatesFrame,
|
|
||||||
pub clocks_frame: ClocksFrame,
|
|
||||||
pub enable_overclocking_button: Option<Button>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OcPage {
|
|
||||||
pub fn new(system_info: &SystemInfo) -> Self {
|
|
||||||
let container = ScrolledWindow::builder()
|
|
||||||
.hscrollbar_policy(PolicyType::Never)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let vbox = Box::builder()
|
|
||||||
.orientation(Orientation::Vertical)
|
|
||||||
.spacing(15)
|
|
||||||
.margin_start(20)
|
|
||||||
.margin_end(20)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let mut enable_overclocking_button = None;
|
|
||||||
|
|
||||||
if system_info.amdgpu_overdrive_enabled == Some(false) {
|
|
||||||
let (warning_frame, button) = oc_warning_frame();
|
|
||||||
enable_overclocking_button = Some(button);
|
|
||||||
vbox.append(&warning_frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
let stats_section = GpuStatsSection::new();
|
|
||||||
vbox.append(&stats_section);
|
|
||||||
|
|
||||||
let power_cap_section = PowerCapSection::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_configurable(level == PerformanceLevel::Manual);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
vbox.append(&power_cap_section);
|
|
||||||
vbox.append(&performance_level_frame.container);
|
|
||||||
vbox.append(&power_states_frame);
|
|
||||||
vbox.append(&clocks_frame.container);
|
|
||||||
|
|
||||||
container.set_child(Some(&vbox));
|
|
||||||
|
|
||||||
Self {
|
|
||||||
container,
|
|
||||||
stats_section,
|
|
||||||
performance_frame: performance_level_frame,
|
|
||||||
clocks_frame,
|
|
||||||
power_cap_section,
|
|
||||||
enable_overclocking_button,
|
|
||||||
power_states_frame,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_stats(&self, stats: &DeviceStats, initial: bool) {
|
|
||||||
self.stats_section.set_stats(stats);
|
|
||||||
self.power_states_frame.set_stats(stats);
|
|
||||||
if initial {
|
|
||||||
self.power_cap_section
|
|
||||||
.set_max_value(stats.power.cap_max.unwrap_or_default());
|
|
||||||
self.power_cap_section
|
|
||||||
.set_min_value(stats.power.cap_min.unwrap_or_default());
|
|
||||||
self.power_cap_section
|
|
||||||
.set_default_value(stats.power.cap_default.unwrap_or_default());
|
|
||||||
|
|
||||||
if let Some(current_cap) = stats.power.cap_current {
|
|
||||||
self.power_cap_section.set_initial_value(current_cap);
|
|
||||||
self.power_cap_section.set_visible(true);
|
|
||||||
} else {
|
|
||||||
self.power_cap_section.set_visible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.set_performance_level(stats.performance_level);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_clocks_table(&self, table: Option<ClocksTable>) {
|
|
||||||
match table {
|
|
||||||
Some(table) => match self.clocks_frame.set_table(table) {
|
|
||||||
Ok(()) => {
|
|
||||||
self.clocks_frame.show();
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
warn!("got invalid clocks table: {err:?}");
|
|
||||||
self.clocks_frame.hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
self.clocks_frame.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn connect_settings_changed<F: Fn() + 'static + Clone>(&self, f: F) {
|
|
||||||
self.performance_frame.connect_settings_changed(f.clone());
|
|
||||||
self.power_cap_section.connect_current_value_notify(clone!(
|
|
||||||
#[strong]
|
|
||||||
f,
|
|
||||||
move |_| 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>) {
|
|
||||||
match profile {
|
|
||||||
Some(profile) => {
|
|
||||||
self.performance_frame.show();
|
|
||||||
self.performance_frame.set_active_level(profile);
|
|
||||||
}
|
|
||||||
None => self.performance_frame.hide(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_performance_level(&self) -> Option<PerformanceLevel> {
|
|
||||||
if self.performance_frame.get_visibility() {
|
|
||||||
let level = self.performance_frame.get_selected_performance_level();
|
|
||||||
Some(level)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_power_cap(&self) -> Option<f64> {
|
|
||||||
self.power_cap_section.get_user_cap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_enabled_power_states(&self) -> HashMap<PowerLevelKind, Vec<u8>> {
|
|
||||||
if self.performance_frame.get_selected_performance_level() == PerformanceLevel::Manual {
|
|
||||||
self.power_states_frame.get_enabled_power_states()
|
|
||||||
} else {
|
|
||||||
HashMap::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn oc_warning_frame() -> (Frame, Button) {
|
|
||||||
let container = Frame::new(Some("Overclocking information"));
|
|
||||||
|
|
||||||
container.set_label_align(0.3);
|
|
||||||
|
|
||||||
let vbox = Box::builder()
|
|
||||||
.orientation(Orientation::Vertical)
|
|
||||||
.spacing(5)
|
|
||||||
.margin_top(10)
|
|
||||||
.margin_bottom(10)
|
|
||||||
.margin_start(10)
|
|
||||||
.margin_end(10)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let warning_label = Label::builder()
|
|
||||||
.use_markup(true)
|
|
||||||
.label(OVERCLOCKING_DISABLED_TEXT)
|
|
||||||
.wrap(true)
|
|
||||||
.wrap_mode(pango::WrapMode::Word)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let enable_button = Button::builder()
|
|
||||||
.label("Enable Overclocking")
|
|
||||||
.halign(Align::End)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
vbox.append(&warning_label);
|
|
||||||
vbox.append(&enable_button);
|
|
||||||
|
|
||||||
container.set_child(Some(&vbox));
|
|
||||||
|
|
||||||
(container, enable_button)
|
|
||||||
}
|
|
@ -2,13 +2,13 @@ use crate::{app::info_row::InfoRow, GUI_VERSION};
|
|||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use lact_client::schema::{SystemInfo, GIT_COMMIT};
|
use lact_client::schema::{SystemInfo, GIT_COMMIT};
|
||||||
use relm4::{ComponentParts, ComponentSender, SimpleComponent};
|
use relm4::{ComponentParts, ComponentSender, SimpleComponent};
|
||||||
use std::fmt::Write;
|
use std::{fmt::Write, rc::Rc};
|
||||||
|
|
||||||
pub struct SoftwarePage {}
|
pub struct SoftwarePage {}
|
||||||
|
|
||||||
#[relm4::component(pub)]
|
#[relm4::component(pub)]
|
||||||
impl SimpleComponent for SoftwarePage {
|
impl SimpleComponent for SoftwarePage {
|
||||||
type Init = (SystemInfo, bool);
|
type Init = (Rc<SystemInfo>, bool);
|
||||||
type Input = ();
|
type Input = ();
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ impl SimpleComponent for SoftwarePage {
|
|||||||
if embedded {
|
if embedded {
|
||||||
daemon_version.push_str("-embedded");
|
daemon_version.push_str("-embedded");
|
||||||
}
|
}
|
||||||
if let Some(commit) = system_info.commit {
|
if let Some(commit) = &system_info.commit {
|
||||||
write!(daemon_version, " (commit {commit})").unwrap();
|
write!(daemon_version, " (commit {commit})").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user