This document describes how to debug the class of issue that motivated
virgl-vaapi-compat: VA-API decode is selected, but decoded surface export to
DMABUF fails because the client rejects the exported DRM PRIME descriptor shape.
A prior investigation found:
- The original motivating browser client used VA-API for this hardware decode
path rather than the
virtio_media/dev/video0V4L2 M2M path directly. - Enabling
graphics.virglVideo = truemade the guest virtio-gpu VA-API driver expose H.264 profiles. - The client selected H.264 VA-API decode but rejected the exported DMABUF descriptor, then fell back to software decode.
- The root cause was virgl exporting
DRM_PRIME_2VA_FOURCC_I420descriptors while the client rejected that descriptor before reaching its lower DMABUF YUV import path. - A first workaround patched the client allowlist. This project is the preferred wrapper/shim approach because it leaves clients unpatched.
Known stack versions from that investigation:
| Component | Version / revision |
|---|---|
| nixpkgs | 331800de5053fcebacf6813adb5db9c9dca22a0c |
| libva | 2.23.0 (__vaDriverInit_1_23) |
| Mesa | 26.1.1 |
| virglrenderer | 1.3.0 |
| crosvm | 4c80bf3523cf84114054209d88a7af3eefd8423f |
| Cloud Hypervisor | 52.0 |
First separate three different acceleration paths:
- V4L2 M2M such as
virtio_mediaand/dev/video0 - VA-API through libva and
virtio_gpu_drv_video.so - Software decode
For the motivating browser client, the relevant hardware decode path was VA-API.
Seeing a virtio_media node was not enough because that client did not directly
use the V4L2 M2M path for this class of decode.
Inside the guest, verify that libva can load the virtio-gpu VA driver and that H.264 profiles are advertised:
LIBVA_DRIVER_NAME=virtio_gpu vainfoUseful variants:
LIBVA_MESSAGING_LEVEL=2 LIBVA_DRIVER_NAME=virtio_gpu vainfo
LIBVA_TRACE=va.trace LIBVA_DRIVER_NAME=virtio_gpu vainfoLook for:
- the driver name/path libva loaded
- the libva version and backend ABI
- H.264 decode profiles such as
VAProfileH264MainorVAProfileH264High VAEntrypointVLD
If H.264 profiles are absent, fix the virtio-gpu/virgl video stack first. The shim cannot create decoder capabilities.
The shim exports a libva init symbol derived at build time. For libva 2.23.x, the expected symbol is:
__vaDriverInit_1_23
If libva cannot initialize the shim, confirm that the build-time libva headers
and runtime libva agree. Rebuild with the target system's pkg-config and libva
headers when in doubt.
The failure this shim targets has a specific shape:
- VA-API decode is selected.
- The virtio-gpu VA driver successfully decodes or prepares surfaces.
- The client requests
vaExportSurfaceHandle()withDRM_PRIME_2. - The exported descriptor is planar
VA_FOURCC_I420with separate Y, U, and V layer entries. - The client rejects the descriptor before its lower DMABUF YUV import path.
- Playback falls back to software decode.
If the client never selects VA-API, if the driver cannot export DMABUFs at all, or if another format is failing, this shim may not help.
Enable shim logging per process:
VIRGL_VAAPI_COMPAT_DEBUG=1 \
LIBVA_DRIVER_NAME=virtio_gpu \
LIBVA_DRIVERS_PATH=/path/to/shim/lib/dri${LIBVA_DRIVERS_PATH:+:$LIBVA_DRIVERS_PATH} \
vainfoFor an affected client, include the same shim variables in the launch environment. When the hook is installed and a matching export occurs, stderr may include lines like:
virgl-vaapi-compat: installed VA export descriptor compatibility hook
virgl-vaapi-compat: exported surface fourcc=0x30323449 layers=3 objects=...
virgl-vaapi-compat: rewrote I420 descriptor to YV12 with U/V layer swap
If you only see initialization messages and no export messages, the client may
not be reaching vaExportSurfaceHandle(), may be using another driver, or may
not be decoding with VA-API.
If you see I420 exports left unchanged because too few layers were present, the descriptor does not match the known safe translation case and should be analyzed before extending the shim.
Always capture both sides:
# Baseline
LIBVA_DRIVER_NAME=virtio_gpu app
# With descriptor shim
VIRGL_VAAPI_COMPAT_DEBUG=1 \
LIBVA_DRIVER_NAME=virtio_gpu \
LIBVA_DRIVERS_PATH=/path/to/shim/lib/dri${LIBVA_DRIVERS_PATH:+:$LIBVA_DRIVERS_PATH} \
appA successful result for this project is not merely that playback works. The important evidence is:
- VA-API is selected in both cases
- the baseline fails at DMABUF/image/surface export
- the shim sees and rewrites the I420
DRM_PRIME_2descriptor - the client continues on the hardware decode path after the rewrite