Software Vulkan with lavapipe: run shaders and pipelines without a GPU

No GPU on the CI box? Mesa ships lavapipe (lvp) — a complete Vulkan implementation on the CPU. It’s slow but it’s real Vulkan: same SPIR-V, same validation, same API. For testing pipeline setup, shader compilation, and resource lifetime it’s invaluable.

Enabling it

run.sh
# lavapipe ships with mesa-vulkan-drivers; it's a normal ICD:
ls /usr/share/vulkan/icd.d/lvp_icd.*.json

# point the loader at it explicitly:
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/lvp_icd.x86_64.json
./vulkanocam -c test.ini   # or: vulkaninfo --summary

vulkaninfo under it reports deviceType = CPU, apiVersion 1.3+, and real limits — no special-casing needed in the app.

What it supports

caps.txt
core Vulkan 1.3 + most of 1.4-era features
compute shaders — full SPIR-V (runs on llvm JIT)
graphics pipelines — rasterization, depth, blending in software
transfers, images, buffers, sync — all semantically correct
VK_KHR_display?      yes on recent mesa — headless "display" for tests
VK_EXT_headless_surface — yes
video encode/decode    partial — VK_KHR_video_queue on newer mesa
ray tracing            no

The catch is performance: a 1080p scene that takes a real GPU 2 ms takes lavapipe 200–2000 ms. Use it for correctness checks, not benchmarks.

Where it earns its keep

uses.txt
CI:           run the real app in a container with no GPU —
              catches validation errors, pipeline-creation bugs,
              resource-leak paths that unit tests miss
dev laptops:  write/test shaders on a machine without discrete GPU
comparisons:  bug reproduces under lavapipe → app bug;
              only under radv → driver bug (bisect, see GFXRecon post)

Wiring it into a test

test.cpp
// the test sees a normal physical device — just pick it:
auto devs = inst.enumeratePhysicalDevices();
for (auto& d : devs)
    if (d.getProperties().deviceType == vk::PhysicalDeviceType::eCpu)
        phys = d;   // lavapipe
// every vk* call works — fences, semaphores, events — same semantics

Practical rules

  • VK_ICD_FILENAMES selects it; vulkaninfo --summary confirms.
  • Validate first: VK_LAYER_KHRONOS_validation works normally — lavapipe reports real validation errors.
  • Don’t time it — use VK_EXT_headless_surface + vkAcquireNextImage for frame-counting tests, not wall-clock latency.
  • Memory types differ (DEVICE_LOCAL==HOST_VISIBLE on CPU) — test that your memory-type picking doesn’t assume a discrete GPU.
  • Newer mesa versions (24+) expose VK_KHR_video_decode_queue — h264 decode on CPU for pipeline testing, not for throughput.

Check out similar posts by category: Vulkan Linux