atagen

monolith

public
Star0
Watch0

Commit b70469d195a1

tarball

atagen <boss@atagen.co>2026-10-19 06:28 UTC

1 file changed+62-27
render-vk: keep mesa egl out when nvidia has no x server

Without DISPLAY, NVIDIA's Vulkan ICD initialises through glvnd's libEGL inside vkCreateInstance, and glvnd loads every EGL vendor. Mesa's vendor links libgallium and libLLVM, about 40 MB resident on bare metal for code that never runs. __EGL_VENDOR_LIBRARY_FILENAMES now names only NVIDIA's vendor while the instance is created. With no vendor at all the ICD fails, so this cannot go further.
Modified file: crates/render-vk/src/device.rs+62 additions−27 deletions
@@ -89,12 +89,12 @@ impl Shared {
8989 .engine_name(c"monolith")
9090 .api_version(vk::API_VERSION_1_3);
9191 let wanted = std::env::var("MONOLITH_VK_DEVICE").ok();
92- let mut filter = node.and_then(icd_filter);
92+ let mut env = node.map(driver_env).unwrap_or_default();
9393 let (instance, physical, queue_family, name) = loop {
94- if let Some(glob) = filter {
94+ for (var, value) in &env {
9595 // SAFETY: the compositor creates its renderer before starting any
9696 // other thread, so nothing reads the environment concurrently.
97- unsafe { std::env::set_var(DRIVERS_SELECT, glob) };
97+ unsafe { std::env::set_var(var, value) };
9898 }
9999 let instance = unsafe {
100100 entry.create_instance(
@@ -102,20 +102,20 @@ impl Shared {
102102 None,
103103 )
104104 };
105- if filter.is_some() {
106- // SAFETY: as above. Removing it keeps clients from inheriting it.
107- unsafe { std::env::remove_var(DRIVERS_SELECT) };
105+ for (var, _) in &env {
106+ // SAFETY: as above. Removing them keeps clients from inheriting them.
107+ unsafe { std::env::remove_var(var) };
108108 }
109109 let instance = match instance {
110110 Ok(i) => i,
111- Err(_) if filter.take().is_some() => continue,
111+ Err(_) if !std::mem::take(&mut env).is_empty() => continue,
112112 Err(e) => return Err(e.into()),
113113 };
114114 match unsafe { pick_physical(&instance, wanted.as_deref(), node) } {
115115 Some((p, f, n)) => break (instance, p, f, n),
116116 None => {
117117 unsafe { instance.destroy_instance(None) };
118- if filter.take().is_none() {
118+ if std::mem::take(&mut env).is_empty() {
119119 return Err(Error::NoSuitableDevice);
120120 }
121121 }
@@ -240,32 +240,67 @@ unsafe fn serves_node(instance: &ash::Instance, physical: vk::PhysicalDevice, no
240240 || (drm.has_render == vk::TRUE && (drm.render_major, drm.render_minor) == (major, minor))
241241 }
242242
243-const DRIVERS_SELECT: &str = "VK_LOADER_DRIVERS_SELECT";
244-
245-/// A loader glob matching the ICD for the kernel driver behind `node`, unless
246-/// the user already picks drivers themselves. The loader keeps every ICD it
247-/// finds loaded for the instance's lifetime, and on NixOS that includes
248-/// lavapipe and its 26 MB of resident libLLVM.
249-fn icd_filter(node: u64) -> Option<&'static str> {
250- let chosen = [
251- DRIVERS_SELECT,
252- "VK_LOADER_DRIVERS_DISABLE",
253- "VK_DRIVER_FILES",
254- "VK_ICD_FILENAMES",
255- "VK_ADD_DRIVER_FILES",
256- ];
257- if chosen.iter().any(|v| std::env::var_os(v).is_some()) {
258- return None;
259- }
243+/// Variables set only while the instance is created, unless the user already
244+/// picks drivers themselves. The loader keeps every ICD it finds loaded for the
245+/// instance's lifetime, on NixOS including lavapipe and 26 MB of resident
246+/// libLLVM. Without an X server NVIDIA's ICD also initialises through glvnd's
247+/// libEGL, which loads every EGL vendor, and Mesa's pulls in LLVM again.
248+fn driver_env(node: u64) -> Vec<(&'static str, std::ffi::OsString)> {
249+ let set = |vars: &[&str]| vars.iter().any(|v| std::env::var_os(v).is_some());
260250 let (major, minor) = (rustix::fs::major(node), rustix::fs::minor(node));
261- let driver = std::fs::read_link(format!("/sys/dev/char/{major}:{minor}/device/driver")).ok()?;
262- match driver.file_name()?.to_str()? {
251+ let Ok(driver) = std::fs::read_link(format!("/sys/dev/char/{major}:{minor}/device/driver"))
252+ else {
253+ return Vec::new();
254+ };
255+ let driver = driver.file_name().and_then(|d| d.to_str()).unwrap_or_default();
256+ let mut env = Vec::new();
257+ let glob = match driver {
263258 "nvidia" => Some("*nvidia*"),
264259 "amdgpu" | "radeon" => Some("*radeon*"),
265260 "i915" | "xe" => Some("*intel*"),
266261 "nouveau" => Some("*nouveau*"),
267262 _ => None,
263+ };
264+ let loader = [
265+ "VK_LOADER_DRIVERS_SELECT",
266+ "VK_LOADER_DRIVERS_DISABLE",
267+ "VK_DRIVER_FILES",
268+ "VK_ICD_FILENAMES",
269+ "VK_ADD_DRIVER_FILES",
270+ ];
271+ if let Some(glob) = glob
272+ && !set(&loader)
273+ {
274+ env.push(("VK_LOADER_DRIVERS_SELECT", glob.into()));
268275 }
276+ let glvnd = ["__EGL_VENDOR_LIBRARY_FILENAMES", "__EGL_VENDOR_LIBRARY_DIRS"];
277+ if driver == "nvidia"
278+ && !set(&glvnd)
279+ && let Some(vendor) = nvidia_egl_vendor()
280+ {
281+ env.push(("__EGL_VENDOR_LIBRARY_FILENAMES", vendor.into()));
282+ }
283+ env
284+}
285+
286+/// NVIDIA's glvnd EGL vendor file, from glvnd's default search path.
287+fn nvidia_egl_vendor() -> Option<std::path::PathBuf> {
288+ [
289+ "/run/opengl-driver/share/glvnd/egl_vendor.d",
290+ "/etc/glvnd/egl_vendor.d",
291+ "/usr/share/glvnd/egl_vendor.d",
292+ ]
293+ .into_iter()
294+ .filter_map(|dir| std::fs::read_dir(dir).ok())
295+ .flatten()
296+ .filter_map(Result::ok)
297+ .map(|e| e.path())
298+ .find(|p| {
299+ p.extension().is_some_and(|e| e == "json")
300+ && p.file_name()
301+ .and_then(|n| n.to_str())
302+ .is_some_and(|n| n.contains("nvidia"))
303+ })
269304 }
270305
271306 /// The render node of `physical`, or its primary node when it has none.