Skip to content

Find a GPU driver on hosts without /run/opengl-driver - #1

Merged
pcasaretto merged 1 commit into
pcasaretto:nix-flakefrom
donk-shopify:finds-gpu-driver-without-opengl-driver
Sep 25, 2026
Merged

pcasaretto merged 1 commit into
pcasaretto:nix-flakefrom
donk-shopify:finds-gpu-driver-without-opengl-driver

Conversation

@donk-shopify

Copy link
Copy Markdown

Builds on your nix-flake branch (tobi#26 on tobi/disktree), so it's aimed at your branch rather than main — merge it and tobi#26 picks it up.

The symptom

On Arch (Omarchy/Hyprland, Radeon 890M, Wayland) nix run github:pcasaretto/disktree/nix-flake never draws a window:

thread 'main' panicked at crates/disktree-app/src/main.rs:140:18:
open the disktree window: Failed to create surface: Failed to create surface for any enabled backend: {}

The empty brace set is the tell: wgpu isn't reporting a backend that failed, it's reporting that it had no backend to try.

Why

The patchelf --add-rpath in postFixup is doing its job — dlopen("libvulkan.so.1") resolves to the closure's vulkan-loader. The loader then has to find a driver, which it discovers through an ICD manifest, and a Nix-built loader looks for those under /run/opengl-driver/share/vulkan/icd.d. Only NixOS creates that path. With VK_LOADER_DEBUG=error:

[Vulkan Loader] ERROR | DRIVER: vkCreateInstance: Found no drivers!

The host's own Mesa can't be borrowed to fix it. /usr/share/vulkan/icd.d/radeon_icd.json names its library relatively (libvulkan_radeon.so) and Nix's glibc doesn't read /etc/ld.so.cache, so it isn't found; rewriting the manifest with an absolute path then fails on libLLVM.so.22.1 for the same reason; and LD_LIBRARY_PATH=/usr/lib shadows glibc itself and kills the process outright (/usr/lib/libc.so.6: undefined symbol: __pointer_chk_guard, version GLIBC_PRIVATE). The driver has to come from the closure.

The change

postFixup gains two lines' worth of work:

  • addDriverRunpath $out/bin/disktree — appends /run/opengl-driver/lib, so NixOS and proprietary-NVIDIA hosts keep working exactly as before.
  • a wrapProgram offering this closure's Mesa as an additional driver source: VK_ADD_DRIVER_FILES for Vulkan, __EGL_VENDOR_LIBRARY_DIRS and LIBGL_DRIVERS_PATH for GL.

Everything is --suffix, and VK_ADD_DRIVER_FILES (rather than VK_DRIVER_FILES) is searched after the ICDs the loader discovers for itself — so a working system driver still wins and NixOS behaviour is unchanged. addDriverRunpath and makeWrapper join nativeBuildInputs under the existing isLinux guard.

A machine driven by the proprietary NVIDIA stack is still out of scope — Mesa cannot drive that card, so those hosts need nixGL. The comment above postFixup says so.

Verified

nix build .#disktree on the pinned nixpkgs, then both $out/bin/disktree and nix run .#disktree open the window on Arch with no environment variables set. readelf -d on .disktree-wrapped shows /run/opengl-driver/lib first in the RUNPATH, and the desktop entry's Exec still resolves to the wrapper rather than the inner binary.

Two smaller things I left alone

  • fontconfig, freetype, libx11, libxcursor, libxi and libxrandr appear in neither NEEDED nor the RUNPATH of the built binary (which wants only libxcb, libxkbcommon, libxkbcommon-x11, libgcc_s, libm, libc), and the only dlopened names in the binary are libvulkan.so.1, libEGL.so.1 and libwayland-client.so.0. They may well be build-time pkg-config needs, but if they aren't, dropping them would stop the input list implying an X11 story the RUNPATH doesn't support.
  • $out/bin/disktree --help exits 0 without a display, so an installCheckPhase one-liner would catch a broken wrapper in future.

A Nix-built vulkan-loader looks for its ICD manifests under
/run/opengl-driver/share/vulkan/icd.d, a path that only NixOS creates, so
on any other distribution the loader found no drivers at all, wgpu came up
with no enabled backend, and the app died in create_surface with "Failed to
create surface for any enabled backend: {}" before a window was shown. The
host's own Mesa cannot fill the gap — its ICD names the vendor library
relatively and Nix's glibc does not read /etc/ld.so.cache, while forcing
the issue with LD_LIBRARY_PATH shadows glibc itself and breaks the process
— so the driver has to come from the closure.

- postFixup now runs addDriverRunpath on the binary, keeping NixOS and
  proprietary-NVIDIA hosts working through /run/opengl-driver/lib
- postFixup wraps the binary so this closure's Mesa is offered as an
  additional driver source: VK_ADD_DRIVER_FILES for Vulkan,
  __EGL_VENDOR_LIBRARY_DIRS and LIBGL_DRIVERS_PATH for GL, all suffixed so
  a driver the loader discovers for itself still wins
- addDriverRunpath and makeWrapper join nativeBuildInputs under the
  existing isLinux guard
- the comment above postFixup explains driver discovery, not just the
  dlopened loaders, and records that NVIDIA's proprietary stack still
  needs nixGL
@pcasaretto
pcasaretto merged commit f442d18 into pcasaretto:nix-flake Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants