Skip to content

Instantly share code, notes, and snippets.

@lzlrd
Last active December 1, 2025 17:34
Show Gist options
  • Select an option

  • Save lzlrd/0d9b757d2122f551794fd00c7f0752d6 to your computer and use it in GitHub Desktop.

Select an option

Save lzlrd/0d9b757d2122f551794fd00c7f0752d6 to your computer and use it in GitHub Desktop.
How to get WSLg working with OpenGL, Vulkan, and CUDA on (Official) Arch Linux and Ubuntu WSL Instances.

WSLg with OpenGL, Vulkan, and CUDA on (Official) Arch Linux and Ubuntu WSL Instances

Note: I haven't documented CUDA here. I'm lazy (and haven't tested on Arch). See https://documentation.ubuntu.com/wsl/en/latest/howto/gpu-cuda for that on Ubuntu.

Context

microsoft/wslg#1312:

So I got this working on both Ubuntu, and Arch. First, start with a fresh install (of archlinux from https://gitlab.archlinux.org/archlinux/archlinux-wsl or Ubuntu from wsl --install Ubuntu or https://apps.microsoft.com/detail/9pdxgncfsczv).

Arch

  1. Install mesa and vulkan-dzn.
  2. Run echo "L+ /tmp/.X11-unix - - - - /mnt/wslg/.X11-unix" | sudo tee /etc/tmpfiles.d/wslg.conf. (Thanks to microsoft/wslg#43 (comment) for this.)
  3. Create your user account as per https://wiki.archlinux.org/title/Users_and_groups#User_management and confgure it as the default user for WSL as per https://wiki.archlinux.org/title/Install_Arch_Linux_on_WSL#Set_default_user.
  4. su into the user or open a new terminal tab/window.
  5. Run:
cat << EOF
export GALLIUM_DRIVER=d3d12

for i in "/mnt/wslg/runtime-dir/"*; do
  [ "$XDG_RUNTIME_DIR" = "$HOME" ] && XDG_RUNTIME_DIR="/var/run/user/$UID"
  if [ ! -L "$XDG_RUNTIME_DIR$(basename "$i")" ]; then
    [ -d "$XDG_RUNTIME_DIR$(basename "$i")" ] && rm -r "$XDG_RUNTIME_DIR$(basename "$i")"
    ln -s "$i" "$XDG_RUNTIME_DIR$(basename "$i")"
  fi
done
EOF | sudo tee /etc/profile.d/wslg.sh`
  1. Restart WSL with wsl --shutdown from CMD/PowerShell and you should see the following (given you install the relevant packages):
$ glxinfo | grep Device
    Device: D3D12 (NVIDIA GeForce RTX 4080 SUPER) (0xffffffff)

$ vulkaninfo | grep "GPU id"
WARNING: dzn is not a conformant Vulkan implementation, testing use only.
                GPU id = 0 (Microsoft Direct3D12 (NVIDIA GeForce RTX 4080 SUPER))
                GPU id = 1 (llvmpipe (LLVM 19.1.7, 256 bits))
                GPU id = 0 (Microsoft Direct3D12 (NVIDIA GeForce RTX 4080 SUPER))
                GPU id = 1 (llvmpipe (LLVM 19.1.7, 256 bits))
                GPU id = 0 (Microsoft Direct3D12 (NVIDIA GeForce RTX 4080 SUPER))
                GPU id = 1 (llvmpipe (LLVM 19.1.7, 256 bits))
GPU id : 0 (Microsoft Direct3D12 (NVIDIA GeForce RTX 4080 SUPER)):
GPU id : 1 (llvmpipe (LLVM 19.1.7, 256 bits)):

Ubuntu

  1. OpenGL should already be working. We'll add Vulkan support.
  2. Go to https://ppa.launchpadcontent.net/kisak/kisak-mesa/ubuntu/pool/main/m/mesa/.
  3. Look for mesa-vulkan-drivers_*.deb.
  4. You'll see ...<LETTER>_<ARCH>.deb. The letter corresponds to your Ubuntu version codename. In your case, "n" for Noble.
  5. Copy the link for the right package, https://ppa.launchpadcontent.net/kisak/kisak-mesa/ubuntu/pool/main/m/mesa/mesa-vulkan-drivers_25.0.1~kisak1~n_amd64.deb in your case.
  6. Run wget https://ppa.launchpadcontent.net/kisak/kisak-mesa/ubuntu/pool/main/m/mesa/mesa-vulkan-drivers_25.0.1~kisak1~n_amd64.deb anywhere you have write access to on the Ubuntu WSL instance.
  7. Run sudo apt install <PACKAGE> (in your case, sudo apt install mesa-vulkan-drivers_25.0.1~kisak1~n_amd64.deb.
  8. Run:
cat << EOF
export GALLIUM_DRIVER=d3d12

for i in "/mnt/wslg/runtime-dir/"*; do
  [ "$XDG_RUNTIME_DIR" = "$HOME" ] && XDG_RUNTIME_DIR="/var/run/user/$UID"
  if [ ! -L "$XDG_RUNTIME_DIR$(basename "$i")" ]; then
    [ -d "$XDG_RUNTIME_DIR$(basename "$i")" ] && rm -r "$XDG_RUNTIME_DIR$(basename "$i")"
    ln -s "$i" "$XDG_RUNTIME_DIR$(basename "$i")"
  fi
done
EOF | sudo tee /etc/profile.d/wslg.sh`
  1. You should see the following (given you install mesa-utils and vulkan-tools):
$ glxinfo | grep Device
WARNING: dzn is not a conformant Vulkan implementation, testing use only.
WARNING: Some incorrect rendering might occur because the selected Vulkan device (Microsoft Direct3D12 (NVIDIA GeForce RTX 4080 SUPER)) doesn't support base Zink requirements: feats.features.logicOp have_EXT_custom_border_color have_EXT_line_rasterization
    Device: D3D12 (NVIDIA GeForce RTX 4080 SUPER) (0xffffffff)

$ vulkaninfo | grep "GPU id"
WARNING: dzn is not a conformant Vulkan implementation, testing use only.
                GPU id = 0 (Microsoft Direct3D12 (NVIDIA GeForce RTX 4080 SUPER))
                GPU id = 1 (llvmpipe (LLVM 19.1.7, 256 bits))
                GPU id = 0 (Microsoft Direct3D12 (NVIDIA GeForce RTX 4080 SUPER))
                GPU id = 1 (llvmpipe (LLVM 19.1.7, 256 bits))
                GPU id = 0 (Microsoft Direct3D12 (NVIDIA GeForce RTX 4080 SUPER))
                GPU id = 1 (llvmpipe (LLVM 19.1.7, 256 bits))
GPU id : 0 (Microsoft Direct3D12 (NVIDIA GeForce RTX 4080 SUPER)):
GPU id : 1 (llvmpipe (LLVM 19.1.7, 256 bits)):

The reason we're using just the Vulkan driver from Kisak's repo. is that the mesa package causes llvmpipe to be used instead of D3D12. Maybe overring GALLIUM_DRIVER would work - I didn't try.

@djpremier
Copy link

djpremier commented Sep 20, 2025

Great gist. I'd just add that in latest WSL2 version with kernel 6.6.x there is a kernel module that is not loaded by default and it's needed in order to access to the /dev/dri/card0 device. (and that was probably @djpremier's issue) It's the module vgem. You can load it with: sudo modprobe vgem

Or if systemd is running you can load the module automatically adding vgem to the file /etc/modules-load.d/modules.conf

Hi, not yet ...

[djpremier@djpremier ~]$ modprobe vgem

[djpremier@djpremier ~]$ lsmod
Module                  Size  Used by
vgem                   12288  0
drm_shmem_helper       20480  1 vgem
intel_rapl_msr         16384  0
intel_rapl_common      32768  1 intel_rapl_msr
kvm_amd               126976  0
kvm                   970752  1 kvm_amd
cfg80211              958464  0
irqbypass              12288  1 kvm
crc32c_intel           16384  0
sch_fq_codel           16384  1
configfs               53248  1
autofs4                45056  0
br_netfilter           28672  0
bridge                282624  1 br_netfilter
stp                    12288  1 bridge
llc                    12288  2 bridge,stp
ip_tables              28672  0
tun                    53248  0

[djpremier@djpremier ~]$ vainfo --display drm --device /dev/dri/card0
Trying display: drm
Failed to open the given device!

But now other commands are working

[djpremier@djpremier ~]$ ls -la /dev/dri
total 0
drwxr-xr-x  3 root root        100 Sep 20 14:24 .
drwxr-xr-x 16 root root       3860 Sep 20 14:24 ..
drwxr-xr-x  2 root root         80 Sep 20 14:24 by-path
crw-rw----  1 root video  226,   0 Sep 20 14:24 card0
crw-rw-rw-  1 root render 226, 128 Sep 20 14:24 renderD128

[djpremier@djpremier ~]$ vulkaninfo
WARNING: dzn is not a conformant Vulkan implementation, testing use only.
WARNING: dzn is not a conformant Vulkan implementation, testing use only.
==========
VULKANINFO
==========

Vulkan Instance Version: 1.4.313


Instance Extensions: count = 25
===============================
...

@djpremier
Copy link

Without specify the device seems work

[djpremier@djpremier ~]$ vainfo --display drm
Trying display: drm
vainfo: VA-API version: 1.22 (libva 2.22.0)
vainfo: Driver version: Mesa Gallium driver 25.1.4-arch1.1 for D3D12 (NVIDIA GeForce RTX 3080 Ti)
vainfo: Supported profile and entrypoints
      VAProfileH264ConstrainedBaseline: VAEntrypointVLD
      VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice
      VAProfileH264Main               : VAEntrypointVLD
      VAProfileH264Main               : VAEntrypointEncSlice
      VAProfileH264High               : VAEntrypointVLD
      VAProfileH264High               : VAEntrypointEncSlice
      VAProfileHEVCMain               : VAEntrypointVLD
      VAProfileHEVCMain               : VAEntrypointEncSlice
      VAProfileHEVCMain10             : VAEntrypointVLD
      VAProfileHEVCMain10             : VAEntrypointEncSlice
      VAProfileVP9Profile0            : VAEntrypointVLD
      VAProfileVP9Profile2            : VAEntrypointVLD
      VAProfileAV1Profile0            : VAEntrypointVLD
      VAProfileNone                   : VAEntrypointVideoProc
image image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment