Problem: vulkaninfo fails to detect the hardware-backed WSLg GPU, falling back to the slow llvmpipe software renderer.
Root Cause: A hidden dependency chain failure.
- Mesa's D3D12 backend (
dozen) fails to loadlibd3d12.so. - Even after providing the
libd3d12.solibrary, it can detect the GPU but still fails to initialize it because the GPU driver (amdxc64.soin this case) provided by WSLg requires thelibssl.solibrary to be loaded, but it is also not found in the library search path.
Solution:
Explicitly add both the WSL driver path and the OpenSSL path to LD_LIBRARY_PATH.
Note: The OpenSSL library path may differ in your setup, so make sure to replace it with the correct path obtained from Nix.
LD_LIBRARY_PATH=/run/opengl-driver/lib:/nix/store/2p91cylbmdv4si5j818pnsg6qcbgin72-openssl-3.6.0/lib vulkaninfo --summaryThe Mesa version in this report is 25.3.5.
This is the latest version at the time of writing. The behavior may differ in other versions, so please check the corresponding source code if you are using a different version. All the links in this report are also based on this version, so if you are using a different version, please check the corresponding source code for that version.
Also, here's my setup for reference:
-
NixOS (
nixos-version): 25.11.20260117.72ac591 (Xantusia) -
GPU: AMD Radeon RX 6700 XT
-
WSL (
wsl.exe --version):WSL version: 2.6.3.0 Kernel version: 6.6.87.2-1 WSLg version: 1.0.71 MSRDC version: 1.2.6353 Direct3D version: 1.611.1-81528511 DXCore version: 10.0.26100.1-240331-1435.ge-release Windows version: 10.0.26200.7840
Let's start with the most basic test: running vulkaninfo --summary to see if it can detect the GPU provided by WSLg and get its information correctly.
# Get vulkaninfo from nixpkgs
nix shell nixpkgs#vulkan-tools
# Run vulkaninfo
vulkaninfo --summaryExpected Output:
The output should show that there are two GPUs available:
GPU0is the actual GPU provided by WSLg (e.g., AMD Radeon RX 6700 XT) using theDozendriver (Mesa's D3D12 backend).GPU1is the software rendererllvmpipe.
Actual Output:
WARNING: [Loader Message] Code 0 : terminator_CreateInstance: Received return code -9 from call to vkCreateInstance in ICD /nix/store/wy8xvqjn24y2hhwp5j483hjdbb869nkf-mesa-25.3.5/lib/libvulkan_dzn.so. Skipping this driver.
...
Devices:
========
GPU0:
deviceName = llvmpipe (LLVM 21.1.8, 256 bits)
driverName = llvmpipe
...
The system completely skipped the hardware GPU and fell back to llvmpipe (software rendering).
To understand why the driver was skipped, I used strace to intercept file system calls.
strace -v -e trace=%file,write -o vulkaninfo-summary-1.log vulkaninfo --summaryIn the log, I found libvulkan_dzn.so searching for libd3d12.so and failing:
openat(AT_FDCWD, "/.../libd3d12.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
...
write(2, "terminator_CreateInstance: Recei"..., 187) = 187
So the flow of the error is like this:
libvulkan_dzn.so(dzn_device.c):- Try loading
libd3d12.so: Not foundinstance->d3d12_mod = util_dl_open(UTIL_DL_PREFIX "d3d12" UTIL_DL_EXT);
- Return code:
-9(VK_ERROR_INCOMPATIBLE_DRIVER)
- Try loading
Solution (Part 1):
Provide the required library (libd3d12.so) in the search path. WSLg provides this in /usr/lib/wsl/lib. In NixOS-WSL with wsl.useWindowsDriver = true, these are also symlinked to /run/opengl-driver/lib.
LD_LIBRARY_PATH=/usr/lib/wsl/lib vulkaninfo --summary
# or
# LD_LIBRARY_PATH=/run/opengl-driver/lib vulkaninfo --summaryAfter adding the library path, vulkaninfo failed with a different error:
MESA: error: ID3D12DeviceFactory::CreateDevice failed
WARNING: [../src/microsoft/vulkan/dzn_device.c:1137] Code 0 : VK_ERROR_INITIALIZATION_FAILED
ERROR: [Loader Message] Code 0 : setup_loader_term_phys_devs: Call to 'vkEnumeratePhysicalDevices' in ICD /nix/store/wy8xvqjn24y2hhwp5j483hjdbb869nkf-mesa-25.3.5/lib/libvulkan_dzn.so failed with error code -3
I ran strace again with the new environment variable.
LD_LIBRARY_PATH=/usr/lib/wsl/lib strace -v -e trace=%file,write -o vulkaninfo-summary-2.log vulkaninfo --summaryThis time, libd3d12.so loaded fine. It also successfully loaded libd3d12core.so, libdxcore.so and /dev/dxg. However, deeper in the log:
openat(AT_FDCWD, "/usr/lib/wsl/drivers/u0198633.inf_amd64_f6ca42135bb94c90/B025777/amdxc64.so", O_RDONLY|O_CLOEXEC) = 7
...
openat(AT_FDCWD, "/usr/lib/wsl/lib/libssl.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/.../libssl.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
...
write(2, "MESA: error: ID3D12DeviceFactory"..., 54) = 54
The Windows/WSL AMD driver (amdxc64.so) is loaded by libd3d12core.so. This proprietary driver has a runtime dependency on OpenSSL (libssl.so). Because this driver is provided by WSLg and expected to run on a normal FHS environment, it doesn't know about Nix stores and fails to find libssl.so.
Confirming with a detailed trace:
LD_LIBRARY_PATH=/usr/lib/wsl/lib strace -f -tt -s 256 -yy -kk -e trace=openat,openat2 -o vulkaninfo-summary-2-update.log vulkaninfo --summaryThe stack trace showed amdxc64.so calling dlopen for libssl.so.
To solve this, provide the OpenSSL library path in LD_LIBRARY_PATH.
Get the path using:
nix eval --raw --expr 'with (import (builtins.getFlake "nixpkgs") {}); lib.makeLibraryPath [ openssl ]' --impure
# Or
nix-instantiate --raw --eval -E 'with (import <nixpkgs> {}); lib.makeLibraryPath [ openssl ]'Combining everything:
LD_LIBRARY_PATH=/usr/lib/wsl/lib:/nix/store/2p91cylbmdv4si5j818pnsg6qcbgin72-openssl-3.6.0/lib vulkaninfo --summaryThe hardware acceleration in WSLg relies on a specific chain of hand-offs:
- Application:
vulkaninfo - Mesa Loader:
libvulkan_dzn.so(The "Dozen" Vulkan driver)- Requirement: Needs
libd3d12.so(forwarding tolibd3d12core.so).
- Requirement: Needs
- DX12 Loader/Core:
libd3d12.so&libd3d12core.solibdxcore.so: Abstraction layer between Windows and Linux kernel communication (IOCTLs).libd3d12core.so: Actual implementation of DX12 API.libd3d12.so: Thin loader forwarding calls tolibd3d12core.so.
- Vendor Driver:
amdxc64.so(In/usr/lib/wsl/drivers/...)- Action: Loaded by
libd3d12core.so. - Requirement: Needs
libssl.so.
- Action: Loaded by
nix-ld works with unpatched binaries by providing a dynamic linker at standard paths. However, it doesn't work with patched binaries (like vulkaninfo from Nixpkgs) because they have already been patched with patchelf/autoPatchelfHook to have a hardcoded RPATH (not RUNPATH!). The dynamic linker prefers RPATH over LD_LIBRARY_PATH (unless configured otherwise), and nix-ld targets binaries that lack an interpreter/RPATH entirely.
Note: Remember to remove any /lib suffix from the string paths, it will be added automatically by lib.makeLibraryPath.
mkShell {
LD_LIBRARY_PATH = lib.makeLibraryPath [
"/usr/lib/wsl" # or "/run/opengl-driver"
pkgs.openssl
];
};- Microsoft Blog: DirectX Heart Linux
- Microsoft Blog: Getting Started with DX12 Agility SDK
- WSLg Architecture - Hardware Accelerated OpenGL
- Mesa GitLab: D3D12 Agility SDK support
- GPU selection in WSLg
This report was structured, grammar-checked, and refined with the assistance of an LLM to ensure clarity and professional presentation.