mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-08-07 00:28:48 +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,
|
||||
linux_distro::LinuxDistro,
|
||||
vulkaninfo::gpu_names,
|
||||
vulkaninfo::VulkanInfo,
|
||||
xdg::XDG,
|
||||
};
|
||||
use relm4::prelude::*;
|
||||
|
@ -25,7 +25,7 @@ pub fn create_about_dialog() -> adw::AboutDialog {
|
|||
.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 {
|
||||
return;
|
||||
}
|
||||
|
@ -58,9 +58,14 @@ pub fn populate_debug_info(dialog: &adw::AboutDialog) {
|
|||
),
|
||||
format!(
|
||||
"GPUs: {}",
|
||||
unsafe { gpu_names() }
|
||||
.ok()
|
||||
.map(|names| names.join(", "))
|
||||
vkinfo
|
||||
.map(|i| i.gpu_names.join(", "))
|
||||
.unwrap_or("unknown".into())
|
||||
),
|
||||
format!(
|
||||
"Monado Vulkan Layers: {}",
|
||||
vkinfo
|
||||
.map(|i| i.has_monado_vulkan_layers.to_string())
|
||||
.unwrap_or("unknown".into())
|
||||
),
|
||||
format!("Detected XR Devices: {}", {
|
||||
|
|
|
@ -47,6 +47,7 @@ use crate::{
|
|||
restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile,
|
||||
},
|
||||
util::file_utils::{setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd},
|
||||
vulkaninfo::VulkanInfo,
|
||||
xr_devices::XRDevice,
|
||||
};
|
||||
use adw::{prelude::*, ResponseAppearance};
|
||||
|
@ -86,6 +87,7 @@ pub struct App {
|
|||
configure_wivrn_action: gtk::gio::SimpleAction,
|
||||
openxr_prober_worker: Option<JobWorker>,
|
||||
xrservice_ready: bool,
|
||||
vkinfo: Option<VulkanInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -861,6 +863,16 @@ impl AsyncComponent for App {
|
|||
};
|
||||
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 {
|
||||
application: init.application,
|
||||
app_win: root.clone(),
|
||||
|
@ -870,6 +882,7 @@ impl AsyncComponent for App {
|
|||
config: config.clone(),
|
||||
selected_profile: selected_profile.clone(),
|
||||
root_win: root.clone().into(),
|
||||
vkinfo: vkinfo.clone(),
|
||||
})
|
||||
.forward(sender.input_sender(), |message| match message {
|
||||
MainViewOutMsg::DoStartStopXRService => Msg::DoStartStopXRService,
|
||||
|
@ -879,6 +892,7 @@ impl AsyncComponent for App {
|
|||
MainViewOutMsg::SaveProfile(p) => Msg::SaveProfile(p),
|
||||
MainViewOutMsg::OpenLibsurviveSetup => Msg::OpenLibsurviveSetup,
|
||||
}),
|
||||
vkinfo,
|
||||
debug_view: DebugView::builder()
|
||||
.launch(DebugViewInit {
|
||||
profile: selected_profile,
|
||||
|
@ -926,8 +940,10 @@ impl AsyncComponent for App {
|
|||
model.about_dialog,
|
||||
#[strong(rename_to = app_win)]
|
||||
model.app_win,
|
||||
#[strong(rename_to = vkinfo)]
|
||||
model.vkinfo,
|
||||
move |_| {
|
||||
populate_debug_info(&about_dialog);
|
||||
populate_debug_info(&about_dialog, vkinfo.as_ref());
|
||||
about_dialog.present(Some(&app_win));
|
||||
}
|
||||
)
|
||||
|
|
|
@ -19,8 +19,11 @@ use crate::{
|
|||
paths::{get_data_dir, get_home_dir},
|
||||
profile::{LighthouseDriver, Profile, XRServiceType},
|
||||
stateless_action,
|
||||
util::file_utils::{get_writer, mount_has_nosuid},
|
||||
util::steamvr_utils::chaperone_info_exists,
|
||||
util::{
|
||||
file_utils::{get_writer, mount_has_nosuid},
|
||||
steamvr_utils::chaperone_info_exists,
|
||||
},
|
||||
vulkaninfo::VulkanInfo,
|
||||
xr_devices::XRDevice,
|
||||
};
|
||||
use adw::{prelude::*, ResponseAppearance};
|
||||
|
@ -65,6 +68,8 @@ pub struct MainView {
|
|||
#[tracker::do_not_track]
|
||||
profile_export_action: gtk::gio::SimpleAction,
|
||||
xrservice_ready: bool,
|
||||
#[tracker::do_not_track]
|
||||
vkinfo: Option<VulkanInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -104,6 +109,7 @@ pub struct MainViewInit {
|
|||
pub config: Config,
|
||||
pub selected_profile: Profile,
|
||||
pub root_win: gtk::Window,
|
||||
pub vkinfo: Option<VulkanInfo>,
|
||||
}
|
||||
|
||||
impl MainView {
|
||||
|
@ -328,6 +334,34 @@ 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,
|
||||
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 {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_hexpand: true,
|
||||
|
@ -812,6 +846,7 @@ impl SimpleComponent for MainView {
|
|||
xrservice_ready: false,
|
||||
profile_delete_action,
|
||||
profile_export_action,
|
||||
vkinfo: init.vkinfo,
|
||||
tracker: 0,
|
||||
};
|
||||
let widgets = view_output!();
|
||||
|
|
|
@ -3,27 +3,62 @@ use ash::{
|
|||
Entry,
|
||||
};
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Dlopens the vulkan library, so this is inherently unsafe. Should be fine in
|
||||
/// most circumstances
|
||||
pub unsafe fn gpu_names() -> anyhow::Result<Vec<String>> {
|
||||
let entry = Entry::load()?;
|
||||
let instance = entry.create_instance(
|
||||
&InstanceCreateInfo::default().application_info(&ApplicationInfo::default()),
|
||||
None,
|
||||
)?;
|
||||
let names = instance
|
||||
.enumerate_physical_devices()?
|
||||
.into_iter()
|
||||
.filter_map(|d| {
|
||||
instance
|
||||
.get_physical_device_properties(d)
|
||||
.device_name_as_c_str()
|
||||
.ok()
|
||||
.map(|cs| cs.to_string_lossy().to_string())
|
||||
})
|
||||
.collect();
|
||||
instance.destroy_instance(None);
|
||||
Ok(names)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VulkanInfo {
|
||||
pub has_nvidia_gpu: bool,
|
||||
pub has_monado_vulkan_layers: bool,
|
||||
pub gpu_names: Vec<String>,
|
||||
}
|
||||
|
||||
const NVIDIA_VENDOR_ID: u32 = 0x10de;
|
||||
|
||||
impl VulkanInfo {
|
||||
/// # Safety
|
||||
///
|
||||
/// Dlopens the vulkan library, so this is inherently unsafe. Should be fine in
|
||||
/// most circumstances
|
||||
pub fn get() -> anyhow::Result<Self> {
|
||||
let entry = unsafe { Entry::load() }?;
|
||||
let instance = unsafe {
|
||||
entry.create_instance(
|
||||
&InstanceCreateInfo::default().application_info(&ApplicationInfo::default()),
|
||||
None,
|
||||
)
|
||||
}?;
|
||||
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