mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-08-07 08:38:46 +00:00
feat: detect nvidia gpu; if detected and monado vk layers not found show warning
This commit is contained in:
parent
0543408a2f
commit
4fad4f37d5
4 changed files with 122 additions and 31 deletions
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
device_prober::PhysicalXRDevice,
|
device_prober::PhysicalXRDevice,
|
||||||
linux_distro::LinuxDistro,
|
linux_distro::LinuxDistro,
|
||||||
vulkaninfo::gpu_names,
|
vulkaninfo::VulkanInfo,
|
||||||
xdg::XDG,
|
xdg::XDG,
|
||||||
};
|
};
|
||||||
use relm4::prelude::*;
|
use relm4::prelude::*;
|
||||||
|
@ -25,7 +25,7 @@ pub fn create_about_dialog() -> adw::AboutDialog {
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn populate_debug_info(dialog: &adw::AboutDialog) {
|
pub fn populate_debug_info(dialog: &adw::AboutDialog, vkinfo: Option<&VulkanInfo>) {
|
||||||
if dialog.debug_info().len() > 0 {
|
if dialog.debug_info().len() > 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -58,9 +58,14 @@ pub fn populate_debug_info(dialog: &adw::AboutDialog) {
|
||||||
),
|
),
|
||||||
format!(
|
format!(
|
||||||
"GPUs: {}",
|
"GPUs: {}",
|
||||||
unsafe { gpu_names() }
|
vkinfo
|
||||||
.ok()
|
.map(|i| i.gpu_names.join(", "))
|
||||||
.map(|names| names.join(", "))
|
.unwrap_or("unknown".into())
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"Monado Vulkan Layers: {}",
|
||||||
|
vkinfo
|
||||||
|
.map(|i| i.has_monado_vulkan_layers.to_string())
|
||||||
.unwrap_or("unknown".into())
|
.unwrap_or("unknown".into())
|
||||||
),
|
),
|
||||||
format!("Detected XR Devices: {}", {
|
format!("Detected XR Devices: {}", {
|
||||||
|
|
|
@ -47,6 +47,7 @@ use crate::{
|
||||||
restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile,
|
restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile,
|
||||||
},
|
},
|
||||||
util::file_utils::{setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd},
|
util::file_utils::{setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd},
|
||||||
|
vulkaninfo::VulkanInfo,
|
||||||
xr_devices::XRDevice,
|
xr_devices::XRDevice,
|
||||||
};
|
};
|
||||||
use adw::{prelude::*, ResponseAppearance};
|
use adw::{prelude::*, ResponseAppearance};
|
||||||
|
@ -86,6 +87,7 @@ pub struct App {
|
||||||
configure_wivrn_action: gtk::gio::SimpleAction,
|
configure_wivrn_action: gtk::gio::SimpleAction,
|
||||||
openxr_prober_worker: Option<JobWorker>,
|
openxr_prober_worker: Option<JobWorker>,
|
||||||
xrservice_ready: bool,
|
xrservice_ready: bool,
|
||||||
|
vkinfo: Option<VulkanInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -861,6 +863,16 @@ impl AsyncComponent for App {
|
||||||
};
|
};
|
||||||
let selected_profile = config.get_selected_profile(&profiles);
|
let selected_profile = config.get_selected_profile(&profiles);
|
||||||
|
|
||||||
|
let vkinfo = {
|
||||||
|
match VulkanInfo::get() {
|
||||||
|
Ok(info) => Some(info),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to get Vulkan info: {e:#?}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut model = App {
|
let mut model = App {
|
||||||
application: init.application,
|
application: init.application,
|
||||||
app_win: root.clone(),
|
app_win: root.clone(),
|
||||||
|
@ -870,6 +882,7 @@ impl AsyncComponent for App {
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
selected_profile: selected_profile.clone(),
|
selected_profile: selected_profile.clone(),
|
||||||
root_win: root.clone().into(),
|
root_win: root.clone().into(),
|
||||||
|
vkinfo: vkinfo.clone(),
|
||||||
})
|
})
|
||||||
.forward(sender.input_sender(), |message| match message {
|
.forward(sender.input_sender(), |message| match message {
|
||||||
MainViewOutMsg::DoStartStopXRService => Msg::DoStartStopXRService,
|
MainViewOutMsg::DoStartStopXRService => Msg::DoStartStopXRService,
|
||||||
|
@ -879,6 +892,7 @@ impl AsyncComponent for App {
|
||||||
MainViewOutMsg::SaveProfile(p) => Msg::SaveProfile(p),
|
MainViewOutMsg::SaveProfile(p) => Msg::SaveProfile(p),
|
||||||
MainViewOutMsg::OpenLibsurviveSetup => Msg::OpenLibsurviveSetup,
|
MainViewOutMsg::OpenLibsurviveSetup => Msg::OpenLibsurviveSetup,
|
||||||
}),
|
}),
|
||||||
|
vkinfo,
|
||||||
debug_view: DebugView::builder()
|
debug_view: DebugView::builder()
|
||||||
.launch(DebugViewInit {
|
.launch(DebugViewInit {
|
||||||
profile: selected_profile,
|
profile: selected_profile,
|
||||||
|
@ -926,8 +940,10 @@ impl AsyncComponent for App {
|
||||||
model.about_dialog,
|
model.about_dialog,
|
||||||
#[strong(rename_to = app_win)]
|
#[strong(rename_to = app_win)]
|
||||||
model.app_win,
|
model.app_win,
|
||||||
|
#[strong(rename_to = vkinfo)]
|
||||||
|
model.vkinfo,
|
||||||
move |_| {
|
move |_| {
|
||||||
populate_debug_info(&about_dialog);
|
populate_debug_info(&about_dialog, vkinfo.as_ref());
|
||||||
about_dialog.present(Some(&app_win));
|
about_dialog.present(Some(&app_win));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,8 +19,11 @@ use crate::{
|
||||||
paths::{get_data_dir, get_home_dir},
|
paths::{get_data_dir, get_home_dir},
|
||||||
profile::{LighthouseDriver, Profile, XRServiceType},
|
profile::{LighthouseDriver, Profile, XRServiceType},
|
||||||
stateless_action,
|
stateless_action,
|
||||||
util::file_utils::{get_writer, mount_has_nosuid},
|
util::{
|
||||||
util::steamvr_utils::chaperone_info_exists,
|
file_utils::{get_writer, mount_has_nosuid},
|
||||||
|
steamvr_utils::chaperone_info_exists,
|
||||||
|
},
|
||||||
|
vulkaninfo::VulkanInfo,
|
||||||
xr_devices::XRDevice,
|
xr_devices::XRDevice,
|
||||||
};
|
};
|
||||||
use adw::{prelude::*, ResponseAppearance};
|
use adw::{prelude::*, ResponseAppearance};
|
||||||
|
@ -65,6 +68,8 @@ pub struct MainView {
|
||||||
#[tracker::do_not_track]
|
#[tracker::do_not_track]
|
||||||
profile_export_action: gtk::gio::SimpleAction,
|
profile_export_action: gtk::gio::SimpleAction,
|
||||||
xrservice_ready: bool,
|
xrservice_ready: bool,
|
||||||
|
#[tracker::do_not_track]
|
||||||
|
vkinfo: Option<VulkanInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -104,6 +109,7 @@ pub struct MainViewInit {
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
pub selected_profile: Profile,
|
pub selected_profile: Profile,
|
||||||
pub root_win: gtk::Window,
|
pub root_win: gtk::Window,
|
||||||
|
pub vkinfo: Option<VulkanInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MainView {
|
impl MainView {
|
||||||
|
@ -328,6 +334,34 @@ impl SimpleComponent for MainView {
|
||||||
set_wrap_mode: gtk::pango::WrapMode::Word,
|
set_wrap_mode: gtk::pango::WrapMode::Word,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
gtk::Box {
|
||||||
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
set_hexpand: true,
|
||||||
|
set_vexpand: false,
|
||||||
|
set_spacing: 12,
|
||||||
|
add_css_class: "card",
|
||||||
|
add_css_class: "padded",
|
||||||
|
set_visible: model
|
||||||
|
.vkinfo
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(
|
||||||
|
|i| i.has_nvidia_gpu && !i.has_monado_vulkan_layers
|
||||||
|
),
|
||||||
|
warning_heading(),
|
||||||
|
gtk::Label {
|
||||||
|
set_label: concat!(
|
||||||
|
"An Nvidia GPU has been detected, but it ",
|
||||||
|
"seems you don't have the Monado Vulkan Layers ",
|
||||||
|
"installed on your system.\n\nInstall the ",
|
||||||
|
"Monado Vulkan Layers or your XR session will ",
|
||||||
|
"crash."
|
||||||
|
),
|
||||||
|
add_css_class: "warning",
|
||||||
|
set_xalign: 0.0,
|
||||||
|
set_wrap: true,
|
||||||
|
set_wrap_mode: gtk::pango::WrapMode::Word,
|
||||||
|
}
|
||||||
|
},
|
||||||
gtk::Box {
|
gtk::Box {
|
||||||
set_orientation: gtk::Orientation::Vertical,
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
set_hexpand: true,
|
set_hexpand: true,
|
||||||
|
@ -812,6 +846,7 @@ impl SimpleComponent for MainView {
|
||||||
xrservice_ready: false,
|
xrservice_ready: false,
|
||||||
profile_delete_action,
|
profile_delete_action,
|
||||||
profile_export_action,
|
profile_export_action,
|
||||||
|
vkinfo: init.vkinfo,
|
||||||
tracker: 0,
|
tracker: 0,
|
||||||
};
|
};
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
|
|
|
@ -3,27 +3,62 @@ use ash::{
|
||||||
Entry,
|
Entry,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// # Safety
|
#[derive(Debug, Clone)]
|
||||||
///
|
pub struct VulkanInfo {
|
||||||
/// Dlopens the vulkan library, so this is inherently unsafe. Should be fine in
|
pub has_nvidia_gpu: bool,
|
||||||
/// most circumstances
|
pub has_monado_vulkan_layers: bool,
|
||||||
pub unsafe fn gpu_names() -> anyhow::Result<Vec<String>> {
|
pub gpu_names: Vec<String>,
|
||||||
let entry = Entry::load()?;
|
}
|
||||||
let instance = entry.create_instance(
|
|
||||||
&InstanceCreateInfo::default().application_info(&ApplicationInfo::default()),
|
const NVIDIA_VENDOR_ID: u32 = 0x10de;
|
||||||
None,
|
|
||||||
)?;
|
impl VulkanInfo {
|
||||||
let names = instance
|
/// # Safety
|
||||||
.enumerate_physical_devices()?
|
///
|
||||||
.into_iter()
|
/// Dlopens the vulkan library, so this is inherently unsafe. Should be fine in
|
||||||
.filter_map(|d| {
|
/// most circumstances
|
||||||
instance
|
pub fn get() -> anyhow::Result<Self> {
|
||||||
.get_physical_device_properties(d)
|
let entry = unsafe { Entry::load() }?;
|
||||||
.device_name_as_c_str()
|
let instance = unsafe {
|
||||||
.ok()
|
entry.create_instance(
|
||||||
.map(|cs| cs.to_string_lossy().to_string())
|
&InstanceCreateInfo::default().application_info(&ApplicationInfo::default()),
|
||||||
})
|
None,
|
||||||
.collect();
|
)
|
||||||
instance.destroy_instance(None);
|
}?;
|
||||||
Ok(names)
|
let mut has_nvidia_gpu = false;
|
||||||
|
let mut has_monado_vulkan_layers = 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_gpu = true;
|
||||||
|
}
|
||||||
|
if !has_monado_vulkan_layers {
|
||||||
|
has_monado_vulkan_layers =
|
||||||
|
unsafe { instance.enumerate_device_layer_properties(d) }
|
||||||
|
.ok()
|
||||||
|
.map(|layerprops| {
|
||||||
|
layerprops.iter().any(|lp| {
|
||||||
|
lp.layer_name_as_c_str().is_ok_and(|name| {
|
||||||
|
name.to_string_lossy()
|
||||||
|
== "VK_LAYER_MND_enable_timeline_semaphore"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
== Some(true);
|
||||||
|
}
|
||||||
|
props
|
||||||
|
.device_name_as_c_str()
|
||||||
|
.ok()
|
||||||
|
.map(|cs| cs.to_string_lossy().to_string())
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
unsafe { instance.destroy_instance(None) };
|
||||||
|
Ok(Self {
|
||||||
|
gpu_names,
|
||||||
|
has_nvidia_gpu,
|
||||||
|
has_monado_vulkan_layers,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue