Commit 6118d58e7ed3
tarball1 file changed+59-10
@@ -87,17 +87,38 @@ impl Shared {
8787
.application_name(c"monolith")8888
.engine_name(c"monolith")8989
.api_version(vk::API_VERSION_1_3);90
- let instance = unsafe {91
- entry.create_instance(92
- &vk::InstanceCreateInfo::default().application_info(&app),93
- None,94
- )?95
- };9690
let wanted = std::env::var("MONOLITH_VK_DEVICE").ok();97
- let picked = unsafe { pick_physical(&instance, wanted.as_deref(), node) };98
- let Some((physical, queue_family, name)) = picked else {99
- unsafe { instance.destroy_instance(None) };100
- return Err(Error::NoSuitableDevice);91
+ let mut filter = node.and_then(icd_filter);92
+ let (instance, physical, queue_family, name) = loop {93
+ if let Some(glob) = filter {94
+ // SAFETY: the compositor creates its renderer before starting any95
+ // other thread, so nothing reads the environment concurrently.96
+ unsafe { std::env::set_var(DRIVERS_SELECT, glob) };97
+ }98
+ let instance = unsafe {99
+ entry.create_instance(100
+ &vk::InstanceCreateInfo::default().application_info(&app),101
+ None,102
+ )103
+ };104
+ if filter.is_some() {105
+ // SAFETY: as above. Removing it keeps clients from inheriting it.106
+ unsafe { std::env::remove_var(DRIVERS_SELECT) };107
+ }108
+ let instance = match instance {109
+ Ok(i) => i,110
+ Err(_) if filter.take().is_some() => continue,111
+ Err(e) => return Err(e.into()),112
+ };113
+ match unsafe { pick_physical(&instance, wanted.as_deref(), node) } {114
+ Some((p, f, n)) => break (instance, p, f, n),115
+ None => {116
+ unsafe { instance.destroy_instance(None) };117
+ if filter.take().is_none() {118
+ return Err(Error::NoSuitableDevice);119
+ }120
+ }121
+ }101122
};102123
let priorities = [1.0];103124
let available: Vec<_> = unsafe { instance.enumerate_device_extension_properties(physical) }@@ -216,6 +237,34 @@ unsafe fn serves_node(instance: &ash::Instance, physical: vk::PhysicalDevice, no
216237
|| (drm.has_render == vk::TRUE && (drm.render_major, drm.render_minor) == (major, minor))217238
}218239
240
+const DRIVERS_SELECT: &str = "VK_LOADER_DRIVERS_SELECT";241
+242
+/// A loader glob matching the ICD for the kernel driver behind `node`, unless243
+/// the user already picks drivers themselves. The loader keeps every ICD it244
+/// finds loaded for the instance's lifetime, and on NixOS that includes245
+/// lavapipe and its 26 MB of resident libLLVM.246
+fn icd_filter(node: u64) -> Option<&'static str> {247
+ let chosen = [248
+ DRIVERS_SELECT,249
+ "VK_LOADER_DRIVERS_DISABLE",250
+ "VK_DRIVER_FILES",251
+ "VK_ICD_FILENAMES",252
+ "VK_ADD_DRIVER_FILES",253
+ ];254
+ if chosen.iter().any(|v| std::env::var_os(v).is_some()) {255
+ return None;256
+ }257
+ let (major, minor) = (rustix::fs::major(node), rustix::fs::minor(node));258
+ let driver = std::fs::read_link(format!("/sys/dev/char/{major}:{minor}/device/driver")).ok()?;259
+ match driver.file_name()?.to_str()? {260
+ "nvidia" => Some("*nvidia*"),261
+ "amdgpu" | "radeon" => Some("*radeon*"),262
+ "i915" | "xe" => Some("*intel*"),263
+ "nouveau" => Some("*nouveau*"),264
+ _ => None,265
+ }266
+}267
+219268
/// The render node of `physical`, or its primary node when it has none.220269
unsafe fn drm_node(instance: &ash::Instance, physical: vk::PhysicalDevice) -> Option<u64> {221270
let mut drm = vk::PhysicalDeviceDrmPropertiesEXT::default();