fix: show amd gpu power profile warning only on amd gpus and with the correct card index

This commit is contained in:
Gabriele Musco 2023-08-29 15:24:53 +00:00
parent 5c2e5b26b4
commit 528afe12ab
2 changed files with 86 additions and 18 deletions

View file

@ -1,10 +1,14 @@
use crate::file_utils::get_reader;
use std::{error::Error, fmt::Display, io::Read, str::FromStr};
const POW_PROF_PATH: &str = "/sys/class/drm/card0/device/pp_power_profile_mode";
// const POW_PROF_PATH: &str = "/sys/class/drm/card0/device/pp_power_profile_mode";
pub fn get_set_vr_pow_prof_cmd() -> String {
format!("sudo sh -c \"echo '4' > {}\"", POW_PROF_PATH)
fn power_profile_mode_file(card_dir: &str) -> String {
format!("{}/device/pp_power_profile_mode", card_dir)
}
pub fn get_set_amd_vr_pow_prof_cmd(card_dir: &str) -> String {
format!("sudo sh -c \"echo '4' > {}\"", power_profile_mode_file(card_dir))
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -75,13 +79,53 @@ impl FromStr for GpuPowerProfile {
}
}
pub fn get_gpu_power_profile() -> Option<GpuPowerProfile> {
if let Some(mut reader) = get_reader(&POW_PROF_PATH.into()) {
let mut txt = String::new();
reader.read_to_string(&mut txt).ok()?;
for line in txt.split('\n') {
if let Ok(pp) = GpuPowerProfile::from_str(line) {
return Some(pp);
const AMD_VENDOR_ID: &str = "0x1002";
// TODO: add these other ids
// const INTEL_VENDOR_ID: &str = "0xGGGG";
// const NVIDIA_VENDOR_ID: &str = "0xGGGG";
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GpuSysDrm {
Amd(String),
Intel(String),
Nvidia(String),
Other(String),
}
fn list_gpus() -> Vec<GpuSysDrm> {
let mut res = vec![];
for i in 0..5 { // arbitrary range, find a better way
let card_dir = format!("/sys/class/drm/card{}", i);
let vendor_file = format!("{}/device/vendor", card_dir);
if let Some(mut reader) = get_reader(&vendor_file) {
let mut buf = String::new();
if reader.read_to_string(&mut buf).is_ok() {
res.push(match buf.to_lowercase().trim() {
AMD_VENDOR_ID => GpuSysDrm::Amd(card_dir),
_ => GpuSysDrm::Other(card_dir),
});
}
}
}
res
}
pub fn get_first_amd_gpu() -> Option<GpuSysDrm> {
list_gpus().iter().filter(|g| matches!(g, GpuSysDrm::Amd(_))).next().cloned()
}
pub fn get_amd_gpu_power_profile() -> Option<GpuPowerProfile> {
let amd_gpu = get_first_amd_gpu();
if let Some(GpuSysDrm::Amd(card_dir)) = amd_gpu {
if let Some(mut reader) = get_reader(&power_profile_mode_file(card_dir.as_str())) {
let mut txt = String::new();
reader.read_to_string(&mut txt).ok()?;
for line in txt.split('\n') {
if let Ok(pp) = GpuPowerProfile::from_str(line) {
return Some(pp);
}
}
}
}

View file

@ -6,7 +6,7 @@ use super::steam_launch_options_box::{SteamLaunchOptionsBox, SteamLaunchOptionsB
use crate::config::Config;
use crate::constants::APP_NAME;
use crate::file_utils::mount_has_nosuid;
use crate::gpu_profile::{get_gpu_power_profile, get_set_vr_pow_prof_cmd, GpuPowerProfile};
use crate::gpu_profile::{get_amd_gpu_power_profile, get_set_amd_vr_pow_prof_cmd, GpuPowerProfile, get_first_amd_gpu, GpuSysDrm};
use crate::profile::{LighthouseDriver, Profile};
use crate::steamvr_utils::chaperone_info_exists;
use crate::ui::app::{
@ -57,6 +57,7 @@ pub enum MainViewMsg {
SetSelectedProfile(u32),
ProfileSelected(u32),
UpdateSelectedProfile(Profile),
TickSelectedProfileTracker,
EditProfile,
CreateProfile,
DeleteProfile,
@ -290,7 +291,11 @@ impl SimpleComponent for MainView {
set_margin_bottom: 12,
// TODO: maybe add manual refresh btn?
#[track = "model.changed(Self::selected_profile())"]
set_visible: get_gpu_power_profile() != Some(GpuPowerProfile::VR),
set_visible: match get_amd_gpu_power_profile() {
None => false,
Some(GpuPowerProfile::VR) => false,
Some(_) => true,
},
gtk::Separator {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
@ -313,7 +318,7 @@ impl SimpleComponent for MainView {
},
gtk::Label {
set_label: concat!(
"Your GPU Power Profile is not set to VR. ",
"Your AMD GPU Power Profile is not set to VR. ",
"This will cause noticeable stutter when running XR ",
"applications. Activate the VR profile witrh the ",
"following command:",
@ -344,7 +349,14 @@ impl SimpleComponent for MainView {
set_bottom_margin: 18,
#[wrap(Some)]
set_buffer: cmdbuf = &gtk::TextBuffer {
set_text: get_set_vr_pow_prof_cmd().as_str(),
set_text: &{
let mut res = String::new();
if let Some(GpuSysDrm::Amd(d)) = get_first_amd_gpu() {
let ds = d.as_str();
res = get_set_amd_vr_pow_prof_cmd(ds);
}
res
}
}
}
},
@ -356,13 +368,22 @@ impl SimpleComponent for MainView {
set_vexpand: false,
set_valign: gtk::Align::Center,
connect_clicked => move |_| {
gtk::gdk::Display::default()
.expect("Could not find default display")
.clipboard()
.set_text(get_set_vr_pow_prof_cmd().as_str());
if let Some(GpuSysDrm::Amd(d)) = get_first_amd_gpu() {
gtk::gdk::Display::default()
.expect("Could not find default display")
.clipboard()
.set_text(get_set_amd_vr_pow_prof_cmd(d.as_str()).as_str());
}
}
},
},
gtk::Button {
set_halign: gtk::Align::Start,
set_label: "Refresh",
connect_clicked[sender] => move |_| {
sender.input(Self::Input::TickSelectedProfileTracker);
}
},
},
model.steam_launch_options_box.widget(),
model.install_wivrn_box.widget(),
@ -537,6 +558,9 @@ impl SimpleComponent for MainView {
.sender()
.emit(InstallWivrnBoxMsg::UpdateSelectedProfile(prof.clone()));
}
Self::Input::TickSelectedProfileTracker => {
self.set_selected_profile(self.selected_profile.clone());
}
Self::Input::UpdateProfiles(profiles, config) => {
self.set_profiles(profiles);
// why send another message to set the dropdown selection?