Files
appsandbox/tools/linux/wsl-mesa
James Stringer 194cadeaa6 NVENC/NVDEC userspace path + nvidia-smi shortcut
- systemd-user environment generator and appsandbox-gpu wrapper both
  append /usr/lib/wsl/lib to LD_LIBRARY_PATH. ldconfig has the .so.1
  entries cached, but the 9P mount is read-only so the unversioned
  symlinks ldconfig wants to create can't be written. dlopen() of
  unversioned names (libcuda.so, libnvidia-encode.so, libnvcuvid.so)
  needs the path on LD_LIBRARY_PATH — without it ffmpeg's h264_nvenc /
  h264_cuvid plugins fail with 'Cannot load libcuda.so.1'.

- setup.sh: symlink /usr/lib/wsl/lib/nvidia-smi to /usr/local/bin so
  the bare command works without env tweaks. Created unconditionally
  because the symlink target is resolved at exec time — the file
  appears under the agent's 9P mount on first boot regardless of when
  the symlink was created.
2026-05-19 22:09:52 -04:00
..
2026-05-19 20:21:43 -04:00
2026-05-19 20:21:43 -04:00

wsl-mesa — Mesa with d3d12 gallium + dzn Vulkan, prebuilt

Custom Mesa build that exposes Hyper-V GPU-PV (via /dev/dxg) to userspace OpenGL and Vulkan workloads on a Linux guest, with zero Microsoft proprietary blobs.

Meson flags:

-D gallium-drivers=llvmpipe,d3d12
-D vulkan-drivers=swrast,microsoft-experimental
-D microsoft-clc=enabled
-D video-codecs=all
-D glvnd=enabled

The two drivers we care about are both pure-open-source: Mesa's d3d12 gallium driver and the microsoft-experimental Vulkan driver (aka dzn, Direct3D 12 backend for Vulkan). Both reach the GPU partition adapter via /dev/dxg ioctls directly — they ship their own dxcore-equivalent code in src/microsoft/ so we don't need libdxcore.so/libd3d12.so/libdirectml.so from a WSL2 install.

Layout

tools/wsl-mesa/
├── README.md
├── build/
│   └── build-mesa.sh                   ← reproduces a build on any 26.04 VM
└── prebuilt/
    └── ubuntu-26.04-amd64/
        ├── wsl-mesa.tar.zst            ← /opt/wsl-mesa tarball
        └── BUILDINFO                   ← Mesa version, source commit, LLVM ver

Install on a Linux VM

sudo mkdir -p /opt/wsl-mesa
sudo zstd -d wsl-mesa.tar.zst -c | sudo tar -C / -x
echo /opt/wsl-mesa/lib/x86_64-linux-gnu | sudo tee /etc/ld.so.conf.d/wsl-mesa.conf
sudo ldconfig
# Vulkan ICD search:
sudo install -d /etc/vulkan/icd.d
sudo ln -sf /opt/wsl-mesa/share/vulkan/icd.d/dzn_icd.x86_64.json \
            /etc/vulkan/icd.d/dzn_icd.x86_64.json

To opt in per-process instead of system-wide:

export LD_LIBRARY_PATH=/opt/wsl-mesa/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
export VK_DRIVER_FILES=/opt/wsl-mesa/share/vulkan/icd.d/dzn_icd.x86_64.json
export __GLX_VENDOR_LIBRARY_NAME=mesa
export MESA_LOADER_DRIVER_OVERRIDE=d3d12

Why a separate prefix

Installing to /opt/wsl-mesa instead of /usr keeps Ubuntu's apt Mesa intact. apt upgrade mesa-* won't clobber our build, and we won't break apps that need stock Mesa. Switch is via ld.so.conf.d or per-process env vars.

Versioning

Prebuilt artifacts are keyed on <ubuntu-codename>-<arch> since the binaries are tied to glibc and libstdc++ ABIs, not kernel versions (unlike dxgkrnl). One subdir per supported distro tuple.

Rebuilding

Run build/build-mesa.sh on a VM with the target codename installed. Takes ~30 min on a 6-core machine. The script handles deps, source fetch, meson configure, ninja build, and install.