feat: somewhat working ui

This commit is contained in:
Ilya Zlobintsev
2022-11-18 19:35:31 +02:00
parent 1a5e456c5b
commit 37cdb8160a
9 changed files with 108 additions and 71 deletions

2
Cargo.lock generated
View File

@@ -26,7 +26,7 @@ dependencies = [
[[package]]
name = "amdgpu-sysfs"
version = "0.5.0"
source = "git+https://github.com/ilya-zlobintsev/amdgpu-sysfs-rs?branch=blocking#55ddcc95cddde27e5c5147d9b5ee4831b5d7aaf8"
source = "git+https://github.com/ilya-zlobintsev/amdgpu-sysfs-rs?branch=blocking#0308d4c475f5091f7e8bc4b7b5d8c101f8dd40d7"
dependencies = [
"serde",
]

View File

@@ -80,7 +80,8 @@ impl App {
});
}
let devices = self.daemon_client.list_devices()?;
let devices_buf = self.daemon_client.list_devices()?;
let devices = devices_buf.inner()?;
self.header.set_devices(&devices);
// Show apply button on setting changes
@@ -96,10 +97,10 @@ impl App {
let apply_revealer = self.apply_revealer.clone();
self.root_stack.oc_page.connect_settings_changed(move || {
debug!("Settings changed, showing apply button");
apply_revealer.show();
});
// self.root_stack.oc_page.connect_settings_changed(move || {
// debug!("Settings changed, showing apply button");
// apply_revealer.show();
// });
}
{
@@ -185,13 +186,17 @@ impl App {
}
fn set_info(&self, gpu_id: &str) {
let info = self.daemon_client.get_device_info(gpu_id).unwrap();
let info_buf = self
.daemon_client
.get_device_info(gpu_id)
.expect("Could not fetch info");
let info = info_buf.inner().unwrap();
trace!("Setting info {info:?}");
self.root_stack.info_page.set_info(&info);
trace!("Setting clocks");
self.root_stack.oc_page.set_info(&info);
// trace!("Setting clocks");
// self.root_stack.oc_page.set_info(&info);
// TODO: this should be stats
/*trace!("Setting performance level {:?}", info.power_profile);
@@ -221,15 +226,15 @@ impl App {
let ppfeaturemask: u64 =
u64::from_str_radix(ppfeaturemask, 16).expect("Invalid ppfeaturemask");
if (ppfeaturemask & PP_OVERDRIVE_MASK as u64) > 0 {
/*if (ppfeaturemask & PP_OVERDRIVE_MASK as u64) > 0 {
self.root_stack.oc_page.warning_frame.hide();
} else {
self.root_stack.oc_page.warning_frame.show();
}
}*/
}
Err(_) => {
info!("Failed to read feature mask! This is expected if your system doesn't have an AMD GPU.");
self.root_stack.oc_page.warning_frame.hide();
// self.root_stack.oc_page.warning_frame.hide();
}
}
}
@@ -249,7 +254,10 @@ impl App {
thread::spawn(move || loop {
let gpu_id = current_gpu_id.read().unwrap();
match daemon_connection.get_device_stats(&gpu_id) {
match daemon_connection
.get_device_stats(&gpu_id)
.and_then(|stats| stats.inner())
{
Ok(stats) => {
sender.send(GuiUpdateMsg::GpuStats(stats)).unwrap();
}
@@ -264,14 +272,14 @@ impl App {
// Receiving stats into the gui event loop
{
let thermals_page = self.root_stack.thermals_page.clone();
let oc_page = self.root_stack.oc_page.clone();
// let oc_page = self.root_stack.oc_page.clone();
receiver.attach(None, move |msg| {
match msg {
GuiUpdateMsg::GpuStats(stats) => {
trace!("New stats received, updating {stats:?}");
thermals_page.set_stats(&stats);
oc_page.set_stats(&stats);
// oc_page.set_stats(&stats);
} /*GuiUpdateMsg::FanControlInfo(fan_control_info) => {
thermals_page.set_ventilation_info(fan_control_info)
}*/

View File

@@ -1,5 +1,5 @@
mod info_page;
mod oc_page;
// mod oc_page;
mod software_page;
mod thermals_page;
@@ -7,7 +7,7 @@ use gtk::prelude::*;
use gtk::*;
use info_page::InformationPage;
use oc_page::OcPage;
// use oc_page::OcPage;
use software_page::SoftwarePage;
use thermals_page::ThermalsPage;
@@ -17,7 +17,7 @@ pub struct RootStack {
pub info_page: InformationPage,
pub thermals_page: ThermalsPage,
pub software_page: SoftwarePage,
pub oc_page: OcPage,
// pub oc_page: OcPage,
}
impl RootStack {
@@ -28,9 +28,9 @@ impl RootStack {
container.add_titled(&info_page.container, "info_page", "Information");
let oc_page = OcPage::new();
// let oc_page = OcPage::new();
container.add_titled(&oc_page.container, "oc_page", "OC");
// container.add_titled(&oc_page.container, "oc_page", "OC");
let thermals_page = ThermalsPage::new();
@@ -44,7 +44,7 @@ impl RootStack {
container,
info_page,
thermals_page,
oc_page,
// oc_page,
software_page,
}
}

View File

@@ -151,11 +151,13 @@ impl InformationPage {
pub fn set_info(&self, gpu_info: &DeviceInfo) {
let gpu_name = gpu_info
.pci_info
.as_ref()
.and_then(|pci_info| {
pci_info
.subsystem_pci_info
.model
.or_else(|| pci_info.device_pci_info.model)
.as_deref()
.or_else(|| pci_info.device_pci_info.model.as_deref())
})
.unwrap_or_default();
self.gpu_name_label
@@ -163,43 +165,48 @@ impl InformationPage {
let gpu_manufacturer = gpu_info
.pci_info
.as_ref()
.and_then(|pci_info| {
pci_info
.subsystem_pci_info
.vendor
.or_else(|| pci_info.device_pci_info.model)
.as_deref()
.or_else(|| pci_info.device_pci_info.model.as_deref())
})
.unwrap_or_default();
self.gpu_manufacturer_label
.set_markup(&format!("<b>{gpu_manufacturer}</b>",));
let vbios_version = gpu_info.vbios_version.as_deref().unwrap_or("<unknown>");
let vbios_version = gpu_info.vbios_version.as_deref().unwrap_or("unknown");
self.vbios_version_label
.set_markup(&format!("<b>{vbios_version}</b>",));
self.driver_label
.set_markup(&format!("<b>{}</b>", gpu_info.driver));
let vram_size = gpu_info
.vram_size
.map_or_else(|| "<unknown>".to_owned(), |size| size.to_string());
self.vram_size_label
.set_markup(&format!("<b>{vram_size}</b>"));
// TODO
// let vram_size = gpu_info
// .vram_size
// .map_or_else(|| "unknown".to_owned(), |size| size.to_string());
// self.vram_size_label
// .set_markup(&format!("<b>{vram_size}</b>"));
let link_speed = gpu_info
.link_info
.current_speed
.as_deref()
.unwrap_or("<unknown>");
.unwrap_or("unknown");
let link_width = gpu_info
.link_info
.current_width
.as_deref()
.unwrap_or("<unknown>");
.unwrap_or("unknown");
self.link_speed_label
.set_markup(&format!("<b>{link_speed} x{link_width}</b>",));
self.vulkan_info_frame.set_info(&gpu_info.vulkan_info);
if let Some(vulkan_info) = &gpu_info.vulkan_info {
self.vulkan_info_frame.set_info(vulkan_info);
}
self.container.show_all();
}

View File

@@ -1,12 +1,10 @@
mod clocks_frame;
// mod clocks_frame;
mod performance_level_frame;
mod power_cap_frame;
mod stats_grid;
mod warning_frame;
use amdgpu_sysfs::gpu_handle::PerformanceLevel;
use clocks_frame::ClocksFrame;
use clocks_frame::ClocksSettings;
use gtk::prelude::*;
use gtk::*;
use lact_schema::{DeviceInfo, DeviceStats};
@@ -21,7 +19,7 @@ pub struct OcPage {
stats_grid: StatsGrid,
performance_level_frame: PowerProfileFrame,
power_cap_frame: PowerCapFrame,
clocks_frame: ClocksFrame,
// clocks_frame: ClocksFrame,
pub warning_frame: WarningFrame,
}
@@ -45,15 +43,15 @@ impl OcPage {
container.pack_start(&power_profile_frame.container, false, true, 0);
let clocks_frame = ClocksFrame::new();
// let clocks_frame = ClocksFrame::new();
container.pack_start(&clocks_frame.container, false, true, 0);
// container.pack_start(&clocks_frame.container, false, true, 0);
Self {
container,
stats_grid,
performance_level_frame: power_profile_frame,
clocks_frame,
// clocks_frame,
warning_frame,
power_cap_frame,
}
@@ -100,9 +98,12 @@ impl OcPage {
}
}
pub fn get_power_profile(&self) -> Option<PowerProfile> {
pub fn get_performance_level(&self) -> Option<PowerProfile> {
match self.performance_level_frame.get_visibility() {
true => Some(self.performance_level_frame.get_selected_power_profile()),
true => Some(
self.performance_level_frame
.get_selected_performance_level(),
),
false => None,
}
}

View File

@@ -1,4 +1,3 @@
use daemon::gpu_controller::ClocksTable;
use gtk::prelude::*;
use gtk::*;

View File

@@ -1,4 +1,4 @@
use daemon::gpu_controller::PowerProfile;
use amdgpu_sysfs::gpu_handle::PerformanceLevel;
use gtk::prelude::*;
use gtk::*;
@@ -57,11 +57,12 @@ impl PowerProfileFrame {
}
}
pub fn set_active_profile(&self, profile: &PowerProfile) {
match profile {
PowerProfile::Auto => self.combo_box.set_active_id(Some("0")),
PowerProfile::High => self.combo_box.set_active_id(Some("1")),
PowerProfile::Low => self.combo_box.set_active_id(Some("2")),
pub fn set_active_profile(&self, level: PerformanceLevel) {
match level {
PerformanceLevel::Auto => self.combo_box.set_active_id(Some("0")),
PerformanceLevel::High => self.combo_box.set_active_id(Some("1")),
PerformanceLevel::Low => self.combo_box.set_active_id(Some("2")),
PerformanceLevel::Manual => todo!(),
};
}
@@ -71,11 +72,11 @@ impl PowerProfileFrame {
});
}
pub fn get_selected_power_profile(&self) -> PowerProfile {
pub fn get_selected_performance_level(&self) -> PerformanceLevel {
match self.combo_box.active().unwrap() {
0 => PowerProfile::Auto,
1 => PowerProfile::High,
2 => PowerProfile::Low,
0 => PerformanceLevel::Auto,
1 => PerformanceLevel::High,
2 => PerformanceLevel::Low,
_ => unreachable!(),
}
}

View File

@@ -1,7 +1,7 @@
use std::collections::BTreeMap;
use gtk::prelude::*;
use gtk::*;
use std::collections::BTreeMap;
use tracing::debug;
#[derive(Clone)]
pub struct FanCurveFrame {
@@ -189,12 +189,12 @@ impl FanCurveFrame {
}
pub fn show(&self) {
log::info!("Manual fan control enaged, showing fan curve");
debug!("Manual fan control enaged, showing fan curve");
self.container.set_visible(true);
}
pub fn hide(&self) {
log::info!("Manual fan control disenaged, hiding fan curve");
debug!("Manual fan control disenaged, hiding fan curve");
self.container.set_visible(false);
}

View File

@@ -1,9 +1,11 @@
use anyhow::{anyhow, Context};
use lact_schema::{request::Request, response::Response, DeviceInfo, DeviceListEntry, DeviceStats};
use nix::unistd::getuid;
use serde::de::DeserializeOwned;
use serde::{de::DeserializeOwned, Deserialize};
use std::{
io::{BufRead, BufReader, Write},
marker::PhantomData,
ops::DerefMut,
os::unix::net::UnixStream,
path::PathBuf,
sync::{Arc, Mutex},
@@ -26,8 +28,12 @@ impl DaemonClient {
})
}
fn make_request<T: DeserializeOwned>(&self, request: Request) -> anyhow::Result<T> {
let (reader, writer) = *self.stream.lock().map_err(|err| anyhow!("{err}"))?;
fn make_request<'a, T: Deserialize<'a>>(
&self,
request: Request,
) -> anyhow::Result<ResponseBuffer<T>> {
let mut stream_guard = self.stream.lock().map_err(|err| anyhow!("{err}"))?;
let (reader, writer) = stream_guard.deref_mut();
if !reader.buffer().is_empty() {
return Err(anyhow!("Another request was not processed properly"));
@@ -38,30 +44,29 @@ impl DaemonClient {
writer.write_all(b"\n")?;
let mut response_payload = String::new();
reader.read_line(&mut response_payload);
reader.read_line(&mut response_payload)?;
let response: Response<T> = serde_json::from_str(&response_payload)
.context("Could not deserialize response from daemon")?;
match response {
Response::Ok(data) => Ok(data),
Response::Error(error) => Err(anyhow!("Error from daemon: {error}")),
}
Ok(ResponseBuffer {
buf: response_payload,
_phantom: PhantomData,
})
}
pub fn list_devices<'a>(&self) -> anyhow::Result<Vec<DeviceListEntry<'a>>> {
pub fn list_devices<'a>(&self) -> anyhow::Result<ResponseBuffer<Vec<DeviceListEntry<'a>>>> {
self.make_request(Request::ListDevices)
}
pub fn set_fan_control(&self, id: &str, enabled: bool) -> anyhow::Result<()> {
self.make_request(Request::SetFanControl { id, enabled })
self.make_request::<()>(Request::SetFanControl { id, enabled })?
.inner()?;
Ok(())
}
pub fn get_device_info(&self, id: &str) -> anyhow::Result<DeviceInfo> {
pub fn get_device_info(&self, id: &str) -> anyhow::Result<ResponseBuffer<DeviceInfo>> {
self.make_request(Request::DeviceInfo { id })
}
pub fn get_device_stats(&self, id: &str) -> anyhow::Result<DeviceStats> {
pub fn get_device_stats(&self, id: &str) -> anyhow::Result<ResponseBuffer<DeviceStats>> {
self.make_request(Request::DeviceStats { id })
}
}
@@ -82,3 +87,19 @@ fn get_socket_path() -> Option<PathBuf> {
None
}
}
pub struct ResponseBuffer<T> {
buf: String,
_phantom: PhantomData<T>,
}
impl<'a, T: Deserialize<'a>> ResponseBuffer<T> {
pub fn inner(&'a self) -> anyhow::Result<T> {
let response: Response<T> = serde_json::from_str(&self.buf)
.context("Could not deserialize response from daemon")?;
match response {
Response::Ok(data) => Ok(data),
Response::Error(err) => Err(anyhow!("Got error from daemon: {err}")),
}
}
}