Vulkan

Vulkan is a cross-platform, open standard set of APIs that allows programs to use GPU hardware in various ways, from drawing on screen, to doing calculations, to decoding video via custom hardware accelerators. Rather than using a custom hardware accelerator present, these codecs are based on compute shaders, and work on any implementation of Vulkan 1.3. Decoders use the same hwaccel API and commands, so users do not need to do anything special to enable them, as enabling Vulkan decoding is sufficient to use them. - ffmpeg 8.0 / HN

# OS

# Check Availability

$ vulkaninfo --summary

$ vkcube    # showcase cube
$ sudo apt install vulkan-tools libvulkan1 

# Dev Setup πŸ“₯

Vulkan is a stack: driver (ICD) β†’ loader β†’ layers β†’ app + shader toolchain. Choice: the distro provides the GPU-facing runtime, nix provides the development / SDK side.

Piece Provider Why
vulkaninfo, vkcube system - vulkan-tools 1.3.275 must match the installed GPU driver to enumerate the real GPUs
vulkan-loader, vulkan-dev, vulkan.pc system - 1.3.275 the loader must NOT come from nix β€” see pitfall
vulkan-headers nix - 1.4.357 build-time headers only
vulkan-validation-layers nix - 1.4.357 version-matched to the nix loader, per-user, no sudo
glslang, shaderc, spirv-tools, spirv-cross nix shader β†’ SPIR-V toolchain
volk, vk-bootstrap, VMA, glm, glfw, sdl3 nix C++ helpers
caveat

# vulkan-tools

Why vulkan-tools is deliberately NOT taken from nix

The nix loader reads the same ICD manifests (via $XDG_DATA_DIRS/.../vulkan/icd.d) but cannot load the driver libraries they point at, so it sees zero GPUs:

$ nix shell nixpkgs#vulkan-tools -c vulkaninfo --summary
ERROR: [Loader Message] Code 0 : libvulkan_intel.so: cannot open shared object file
ERROR: [Loader Message] Code 0 : vkCreateInstance: Found no drivers!

$ vulkaninfo --summary | grep -cE 'deviceName.*(Intel|NVIDIA)'      # distro loader
2

So vulkaninfo / vkcube must stay the distro ones to talk to the real Intel/NVIDIA drivers.

# Validation layer

~/.nix-profile/share is on $XDG_DATA_DIRS, so the system loader lists the nix layer β€” but it cannot load it: the layer needs GLIBC_ABI_GNU2_TLS, a versioned symbol the distro glibc 2.42 does not export (nix glibc does).

$ VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation vulkaninfo --summary
ERROR: [Loader Message] Code 0 : libc.so.6: version `GLIBC_ABI_GNU2_TLS' not found
       (required by .../libVkLayer_khronos_validation.so)

Either run the app in a nix-gl-host environment (nix glibc + bound host drivers β€” as in DEV/Manim/shell.nix), or take the layer from the distro instead:

$ sudo apt install vulkan-validationlayers   # 1.3.275, loadable by the distro loader

# NO vulkan-loader

Pitfall: nix profile in RUNPATH

With nix cmake + system gcc, cmake finds the loader in the nix profile (~/.nix-profile/lib/libvulkan.so) and bakes that directory into the library’s RUNPATH:

$ readelf -d libggml-vulkan.so.0.25.3 | grep RUNPATH
  Library runpath: [/…/build/bin:/home/yves/.nix-profile/lib:]

RUNPATH is searched before system paths, so the nix loader wins and drags in nix libdl / nix libc β†’ a system-compiled binary dies at startup:

$ ./build/bin/llama
./build/bin/llama: /lib/x86_64-linux-gnu/libc.so.6: version
  `GLIBC_ABI_DT_X86_64_PLT' not found
  (required by /nix/store/…-glibc-2.42-84/lib/libdl.so.2)

Diagnosis: LD_DEBUG=libs showed libvulkan.so.1 resolved from ~/.nix-profile/lib, which carries RUNPATH=/nix/store/…-glibc/lib. Fix by forcing the distro loader (LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu made it run), then permanently by removing it from the profile.

Rule: the linker/loader for anything that must touch the real GPU comes from the distro. Keep ~/.nix-profile/lib free of libvulkan.so*.

For an already-built binary:

$ nix shell nixpkgs#patchelf -c patchelf --set-rpath '$ORIGIN' libggml-vulkan.so.0.25.3

or reconfigure so the loader is on a standard path (no RUNPATH gets written):

$ cmake -S . -B build -DGGML_VULKAN=ON \
    -DVulkan_INCLUDE_DIR=/usr/include \
    -DVulkan_LIBRARY=/usr/lib/x86_64-linux-gnu/libvulkan.so.1
nix config

# Nix Config

Via Home Manager

home.packages = with pkgs; [
  # Vulkan / GPU shader toolchain
  # NOTE: no vulkan-loader / vulkan-tools here β€” the distro provides the
  # loader + libvulkan-dev + vulkaninfo/vkcube (see pitfall above).
  vulkan-headers            # C/C++ headers
  vulkan-validation-layers  # VK_LAYER_KHRONOS_validation
  vulkan-extension-layer
  glslang                   # glslangValidator: GLSL/HLSL -> SPIR-V
  shaderc                   # glslc + libshaderc
  spirv-tools               # spirv-val, spirv-opt, spirv-as, spirv-dis
  spirv-headers
  spirv-cross               # SPIR-V -> GLSL/HLSL/MSL

  volk
  vk-bootstrap
  vulkan-memory-allocator
  glm
  glfw
  sdl3
];

# Check Dev

Shader toolchain (nix)

$ command -v glslangValidator glslc spirv-val spirv-opt spirv-cross
$ glslangValidator --version

Compile + validate a shader

$ printf '#version 450\nvoid main(){ gl_Position = vec4(0.0); }\n' > /tmp/t.vert
$ glslangValidator -V /tmp/t.vert -o /tmp/t.spv
$ spirv-val /tmp/t.spv

Distro tools still in use β€” real GPUs visible

$ command -v vulkaninfo vkcube                       # -> /usr/bin/...
$ vulkaninfo --summary | grep -iE 'deviceName'
	deviceName = Intel(R) UHD Graphics (CML GT2)
	deviceName = NVIDIA GeForce MX350
	deviceName = llvmpipe (LLVM 20.1.2, 256 bits)

# nix-supplied layers are enumerated from ~/.nix-profile/share (in $XDG_DATA_DIRS)
$ ls ~/.nix-profile/share/vulkan/explicit_layer.d/
VkLayer_khronos_validation.json

# see also

Written on August 22, 2025, Last update on August 14, 2026
vulkan gpu ffmpeg graphic