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

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