diff --git a/src/config.rs b/src/config.rs index c9b630d..b6a85ad 100644 --- a/src/config.rs +++ b/src/config.rs @@ -41,6 +41,8 @@ pub struct GlobalPreferences { pub use_min_frame_period: bool, /// XRT_DEBUG_GUI (1, 0) + XRT_CURATED_GUI (1, 0) pub monado_ui: bool, + /// U_PACING_COMP_TIME_FRACTIONPERCENT=95 + XRT_COMPOSITOR_USE_PRESENT_WAIT=1 + pub nvidia_mitigation: bool, #[serde(default)] pub env_vars: HashMap, } @@ -56,6 +58,7 @@ impl Default for GlobalPreferences { use_min_frame_period: false, monado_ui: false, env_vars: HashMap::default(), + nvidia_mitigation: false, } } } @@ -89,6 +92,10 @@ impl GlobalPreferences { (if self.monado_ui { 1 } else { 0 }).to_string(), ), ]); + if self.nvidia_mitigation { + res.insert("U_PACING_COMP_TIME_FRACTIONPERCENT".into(), "95".into()); + res.insert("XRT_COMPOSITOR_USE_PRESENT_WAIT".into(), "1".into()); + } res.extend(self.env_vars.clone()); res } diff --git a/src/ui/app.rs b/src/ui/app.rs index b83dfc0..f1e30b1 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -1240,6 +1240,7 @@ impl AsyncComponent for App { config: config.clone(), selected_profile: selected_profile.clone(), root_win: root.clone().into(), + has_nvidia: vkinfo.as_ref().is_some_and(|i| i.has_nvidia), }) .forward(sender.input_sender(), |message| match message { MainViewOutMsg::DoStartStopXRService => Msg::DoStartStopXRService, diff --git a/src/ui/main_view.rs b/src/ui/main_view.rs index 256efe9..155a22a 100644 --- a/src/ui/main_view.rs +++ b/src/ui/main_view.rs @@ -52,6 +52,11 @@ pub struct MainView { xrservice_ready: bool, show_setcap_warn: bool, root_win: gtk::Window, + + #[tracker::do_not_track] + has_nvidia: bool, + + show_nvidia_warning: bool, } #[derive(Debug)] @@ -67,6 +72,7 @@ pub enum MainViewMsg { UpdateXrServiceReady(bool), CheckSetcap, DoSetcap, + CheckNvidiaMitigation, } #[derive(Debug)] @@ -81,6 +87,7 @@ pub struct MainViewInit { pub config: Config, pub selected_profile: Profile, pub root_win: gtk::Window, + pub has_nvidia: bool, } #[relm4::component(pub async)] @@ -279,6 +286,25 @@ impl AsyncComponent for MainView { }, }, }, + warn_card(None, concat!( + "Nvidia GPU detected.\n\n", + "Please turn on \"Nvidia mitigation\" in the preferences.\n", + "Without it you might experience degraded performance." + )) -> gtk::Box { + #[track = "model.changed(Self::show_nvidia_warning())"] + set_visible: model.show_nvidia_warning, + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + set_spacing: 6, + gtk::Button { + set_halign: gtk::Align::Start, + set_label: "Refresh", + connect_clicked[sender] => move |_| { + sender.input(Self::Input::CheckNvidiaMitigation); + }, + }, + }, + }, warn_card(None, concat!( "The xr-hardware udev rules are missing. ", "This might cause communication problems with your ", @@ -421,6 +447,12 @@ impl AsyncComponent for MainView { }, ); } + Self::Input::CheckNvidiaMitigation => { + let config = Config::get_config(); + self.set_show_nvidia_warning( + self.has_nvidia && !config.global_preferences.nvidia_mitigation, + ) + } Self::Input::DoSetcap => { let config = Config::get_config(); if let Some(executable) = self.selected_profile.xrservice_binary(Some(&config)) { @@ -476,6 +508,9 @@ impl AsyncComponent for MainView { xrservice_ready: false, show_setcap_warn: false, root_win: init.root_win.clone(), + has_nvidia: init.has_nvidia, + show_nvidia_warning: init.has_nvidia + && !init.config.global_preferences.nvidia_mitigation, tracker: 0, }; let widgets = view_output!(); diff --git a/src/ui/preferences_window.rs b/src/ui/preferences_window.rs index 5f6b3bf..c00e043 100644 --- a/src/ui/preferences_window.rs +++ b/src/ui/preferences_window.rs @@ -125,6 +125,14 @@ impl AsyncComponent for PreferencesWindow { config.borrow_mut().global_preferences.monado_ui = v; }) ), + add: &switch_row( + "Nvidia mitigation", + Some("Performance mitigations for Nvidia GPUs"), + model.config.borrow().global_preferences.nvidia_mitigation, + clone!(#[strong(rename_to=config)] model.config, move |_, v| { + config.borrow_mut().global_preferences.nvidia_mitigation = v; + }) + ), }, }, add: advanced_page = &adw::PreferencesPage { diff --git a/src/vulkaninfo.rs b/src/vulkaninfo.rs index c769e57..862c1ca 100644 --- a/src/vulkaninfo.rs +++ b/src/vulkaninfo.rs @@ -6,9 +6,10 @@ use ash::{ #[derive(Debug, Clone)] pub struct VulkanInfo { pub gpu_names: Vec, + pub has_nvidia: bool, } -// const NVIDIA_VENDOR_ID: u32 = 0x10de; +const NVIDIA_VENDOR_ID: u32 = 0x10de; impl VulkanInfo { /// # Safety @@ -23,11 +24,16 @@ impl VulkanInfo { None, ) }?; + let mut has_nvidia = false; let gpu_names = unsafe { instance.enumerate_physical_devices() }? .into_iter() .filter_map(|d| { + let props = unsafe { instance.get_physical_device_properties(d) }; + if props.vendor_id == NVIDIA_VENDOR_ID { + has_nvidia = true; + } Some( - unsafe { instance.get_physical_device_properties(d) } + props .device_name_as_c_str() .ok()? .to_string_lossy() @@ -36,6 +42,9 @@ impl VulkanInfo { }) .collect(); unsafe { instance.destroy_instance(None) }; - Ok(Self { gpu_names }) + Ok(Self { + gpu_names, + has_nvidia, + }) } }