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 --summaryvulkaninfo 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 noThe 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_FILENAMESselects it;vulkaninfo --summaryconfirms.- Validate first:
VK_LAYER_KHRONOS_validationworks normally — lavapipe reports real validation errors. - Don’t time it — use
VK_EXT_headless_surface+vkAcquireNextImagefor frame-counting tests, not wall-clock latency. - Memory types differ (
DEVICE_LOCAL==HOST_VISIBLEon 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.
If this post helped you, please consider buying me a coffee or donating via PayPal to support research & publishing of new posts on TechOverflow