Repository navigation
direct: export multi-plane YUV as one dma-buf object per plane - #446
Conversation
The single-buffer export packs every plane into one dma-buf with the chroma plane at a non-zero byte offset inside a shared block-linear buffer. Chromium's multi-plane import handles that, but per-plane importers (mpv/GStreamer/ffmpeg, which import each layer as a standalone dma-buf) can't detile a tiled plane that starts at a byte offset, so NV12 chroma came out scrambled/stretched under mpv --hwdec=vaapi. Since the direct backend is now the default, this broke hardware decode for every non-Chromium VA-API client. Allocate each plane in its own dma-buf object at offset 0 instead, while still forcing a single shared block height across planes (via the existing unified layout) so all objects report one DRM modifier -- the invariant Chromium's one-modifier-per-buffer rule needs. Per-plane importers now detile the chroma plane correctly, and Chromium keeps working (num_objects>1 with a common modifier is accepted). The plane's CUDA array is created at the block-aligned height so CUDA tiles it with the advertised block height (same guard as the 144p green-chroma fix). The single-buffer layout stays available behind NVD_SINGLE_BUFFER for comparison. Verified on RTX 5080: mpv --hwdec=vaapi now renders NV12 correctly at 144p/720p/ 1080p (was corrupt), Chrome still HW-decodes 720p with no GPU-process crash, and H264/VP9/AV1/HEVC10 decode is unchanged.
|
Quick follow-up on the 10-bit (P010) note I made earlier β I dug into it and it turns out not to be a driver bug, so I wanted to correct the record. 10-bit actually plays fine on the direct backend with mpv's OpenGL interop: mpv --hwdec=vaapi --vo=gpu --gpu-api=opengl <10bit file> The hang only happens with mpv's Vulkan/libplacebo interop. Looking at the exported descriptors (both planes share the same block-linear modifier), the difference is just the chroma layer's format: NV12 chroma is RG88 and imports fine, but P010 chroma is RG1616, and NVIDIA's Vulkan can't import an R16G16 dma-buf with the block-linear modifier (plain R16, as in the luma plane, is fine). When the Vulkan import fails, mpv falls back to inserting scale_vaapi (p010 -> nv12), and that VPP pass fails too because this driver's VideoProc only outputs ARGB, not NV12 β which is what surfaces as "error on filtering" and the stuck first frame. So it's a Vulkan-interop limitation rather than something wrong in the driver: decode and export are fine (OpenGL interop and plain ffmpeg decode both work). Workaround for anyone hitting it is --gpu-api=opengl. I also noticed the driver advertises VAEntrypointVideoProc but never fills in vtable_vpp, so vaQueryVideoProcPipelineCaps returns UNIMPLEMENTED. Wiring that up is harmless and helps clients that query VPP caps (e.g. ffmpeg's scale_vaapi), but it doesn't change the mpv Vulkan case (that dies later at the actual VPP render), so I've left it out of this PR β happy to send it separately if you think it's worth having. |
|
works great on my tu106. |
|
Great to hear, thanks for testing! Good to know it works on TU106 as well. |
The direct backend called getenv("NVD_SINGLE_BUFFER") on every surface
allocation. Read it once in the constructor like every other NVD_* env
and expose it via nvdSingleBufferForced().
|
Thanks for this, it fixes it for me aswell. |
The single-buffer export packs every plane into one dma-buf with the chroma plane at a non-zero byte offset inside a shared block-linear buffer. Chromium's multi-plane import handles that, but per-plane importers (mpv/GStreamer/ffmpeg, which import each layer as a standalone dma-buf) can't detile a tiled plane that starts at a byte offset, so NV12 chroma came out scrambled/stretched under mpv --hwdec=vaapi. Since the direct backend is now the default, this broke hardware decode for every non-Chromium VA-API client.
Allocate each plane in its own dma-buf object at offset 0 instead, while still forcing a single shared block height across planes (via the existing unified layout) so all objects report one DRM modifier -- the invariant Chromium's one-modifier-per-buffer rule needs. Per-plane importers now detile the chroma plane correctly, and Chromium keeps working (num_objects>1 with a common modifier is accepted). The plane's CUDA array is created at the block-aligned height so CUDA tiles it with the advertised block height (same guard as the 144p green-chroma fix). The single-buffer layout stays available behind NVD_SINGLE_BUFFER for comparison.
Verified on RTX 5080: mpv --hwdec=vaapi now renders NV12 correctly at 144p/720p/ 1080p (was corrupt), Chrome still HW-decodes 720p with no GPU-process crash, and H264/VP9/AV1/HEVC10 decode is unchanged.