feat: check amd gpu power profile, show warning with instructions if not set to vr

This commit is contained in:
Gabriele Musco 2023-08-19 20:26:31 +00:00
parent 9918912992
commit b71e92fa2d
3 changed files with 174 additions and 0 deletions

89
src/gpu_profile.rs Normal file
View file

@ -0,0 +1,89 @@
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";
pub fn get_set_vr_pow_prof_cmd() -> String {
format!("sudo sh -c \"echo '4' > {}\"", POW_PROF_PATH)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GpuPowerProfile {
// 3D Full Screen, inverted cause can't start with number
Fullscreen3D,
PowerSaving,
Video,
VR,
Compute,
Custom,
}
#[derive(Debug)]
pub struct GpuPowerProfileParseErr;
impl GpuPowerProfileParseErr {
pub fn new() -> Self {
Self {}
}
}
impl Display for GpuPowerProfileParseErr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("GpuPowerProfileParseErr")
}
}
impl Error for GpuPowerProfileParseErr {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
fn cause(&self) -> Option<&dyn Error> {
self.source()
}
}
impl FromStr for GpuPowerProfile {
type Err = GpuPowerProfileParseErr;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
let s = s.trim();
if !s.contains('*') {
return Err(Self::Err::new());
}
if s.contains("3d_full_screen") {
return Ok(Self::Fullscreen3D);
}
if s.contains("power_saving") {
return Ok(Self::PowerSaving);
}
if s.contains("video") {
return Ok(Self::Video);
}
if s.contains("vr") {
return Ok(Self::VR);
}
if s.contains("compute") {
return Ok(Self::Compute);
}
if s.contains("custom") {
return Ok(Self::Custom);
}
Err(Self::Err::new())
}
}
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);
}
}
}
None
}

View file

@ -37,6 +37,7 @@ pub mod runner_pipeline;
pub mod steamvr_utils;
pub mod ui;
pub mod xr_devices;
pub mod gpu_profile;
fn restore_steam_xr_files() {
let active_runtime = get_current_active_runtime();

View file

@ -6,6 +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, GpuPowerProfile, get_set_vr_pow_prof_cmd};
use crate::profile::{LighthouseDriver, Profile};
use crate::steamvr_utils::chaperone_info_exists;
use crate::ui::app::{
@ -278,6 +279,89 @@ impl SimpleComponent for MainView {
set_wrap_mode: gtk::pango::WrapMode::Word,
}
},
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_hexpand: true,
set_vexpand: false,
set_spacing: 12,
set_margin_top: 12,
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),
gtk::Separator {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
},
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_margin_start: 12,
set_margin_end: 12,
set_spacing: 12,
set_hexpand: true,
gtk::Image {
set_icon_name: Some("dialog-warning-symbolic"),
add_css_class: "warning",
},
gtk::Label {
add_css_class: "warning",
add_css_class: "heading",
set_label: "Warning"
}
},
gtk::Label {
set_label: concat!(
"Your 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:",
),
set_margin_start: 12,
set_margin_end: 12,
add_css_class: "warning",
set_wrap: true,
set_wrap_mode: gtk::pango::WrapMode::Word,
},
gtk::Box {
set_margin_start: 12,
set_margin_end: 12,
set_orientation: gtk::Orientation::Horizontal,
set_spacing: 6,
gtk::ScrolledWindow {
add_css_class: "card",
set_vscrollbar_policy: gtk::PolicyType::Never,
set_overflow: gtk::Overflow::Hidden,
gtk::TextView {
set_hexpand: true,
set_vexpand: false,
set_monospace: true,
set_editable: false,
set_left_margin: 6,
set_right_margin: 6,
set_top_margin: 6,
set_bottom_margin: 18,
#[wrap(Some)]
set_buffer: cmdbuf = &gtk::TextBuffer {
set_text: get_set_vr_pow_prof_cmd().as_str(),
}
}
},
gtk::Button {
add_css_class: "flat",
add_css_class: "circular",
set_tooltip_text: Some("Copy"),
set_icon_name: "edit-copy-symbolic",
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());
}
},
},
},
model.steam_launch_options_box.widget(),
model.install_wivrn_box.widget(),
gtk::Box {