initial seed: retrofit campaign lineage from local working trees

panvk-bifrost campaigns (r1..r4 Vulkan compositor + r5.video1 Vulkan
video decode) shipped before this repo existed; the deliverable
patches live in marfrit-packages, but the reasoning chain, phase docs,
and source-state evidence lived only in local working trees on the
development host.

This retrofit imports:
- mesa-panvk-bifrost/   — r1..r4 era phase docs (iter1..iter18)
                          (libmali stub blobs at iter18/blob/ excluded
                          — 109MB of RE artifacts replaced with a README
                          pointer)
- mesa-panvk-bifrost-video/ — sibling campaign phase docs + probe
- evidence/             — frozen .tgz source snapshots at each milestone
                          (basis for the 0005 patch diff generation)

Future iterations should branch off here from day one, so each iter is
a commit rather than a snapshot. See [[feedback-session-local-process-pins]]
for the process drift this retrofit closes.

Total: 1.9 MB across 124 files.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-23 05:25:37 +02:00
parent 430d0da278
commit a4e7d8ab90
124 changed files with 22551 additions and 1 deletions
+92
View File
@@ -0,0 +1,92 @@
# panvk-bifrost-video
Successor campaign to **panvk-bifrost** (closed 2026-05-21). New
deliverable: extend the panvk Vulkan driver for Mali-Bifrost so that
it exposes the Khronos `VK_KHR_video_decode_*` extension surface,
backed under the hood by the SoC's separate V4L2-stateless VPU
(hantro on RK3566 / VDPU381 on RK3588), not by the Mali GPU itself
— which has no video unit.
## Why this exists
The closing observation of panvk-bifrost was: **Brave on aarch64 is a
closed binary that won't VAAPI-route on its own.** iter14 documented
this as a permanent wall. chromium-fourier closes it for *Chromium*
(by rebuilding from source with the V4L2 path forced open), but Brave
is unmodifiable as-shipped.
The operator-stated lever — "this is the exact reason I want the
Vulkan driver — so brave does not just use vulkan to draw buttons, but
to actively use the features to offload, create buffers that kwin can
understand, yadda yadda younameit" — points at the *driver* side of
the boundary, not the browser. If we present Brave's existing Vulkan
dispatch with a competent `VK_KHR_video_decode_h264` implementation,
its media path engages through that without source modification.
## Goal
Make `vk-video-samples` (Khronos's canonical Vulkan video test client)
decode an H.264 BBB clip end-to-end on ohm (RK3566 / PineTab2 / Mali-G52)
using `mesa-panvk-bifrost-video` as the Vulkan ICD. Frames must be
hantro-decoded (not software-fallback), and the round-trip must be
provably zero-copy at the VkImage layer.
Brave engagement is a **subsequent** milestone; Phase 1 locks against
vk-video-samples as the test client because it isolates the driver
work from browser-binary unknowns.
## Why this is novel
Every Mesa VK_KHR_video implementation today (Anv = Intel, RADV = AMD,
NVK = NVIDIA) assumes the GPU has an integrated video engine. The
extension API is shaped around that: a queue family with
`VK_QUEUE_VIDEO_DECODE_BIT_KHR` on the same device as the graphics
queue, command buffers carrying both graphics and video ops to the
same physical engine.
Our SoC topology is different. The hantro VPU is a separate IP block
exposed only via V4L2 (`/dev/video1`); it has no relationship to the
Mali GPU other than sharing DMA-capable system memory through IOMMU /
dmabuf. This campaign is the first time (to my knowledge) Mesa would
bridge VK_KHR_video to a V4L2-stateless backend.
The architectural pattern, if it works, generalizes to every ARM SoC
where a Vulkan-capable GPU and a V4L2-only VPU live on the same SoC —
which is most of them.
## Scope (locked 2026-05-21)
- **Codec**: H.264 only initially. H.265 deferred (RK3588 hardware
not yet substrate-anchored).
- **Package**: New `mesa-panvk-bifrost-video` sibling to
`mesa-panvk-bifrost`. Separated so users who don't want the V4L2 /
libva runtime dep graph can opt out.
- **Phase 1 validation target**: `vk-video-samples` Khronos test
client decodes BBB H.264 on ohm. Brave integration becomes a later
iteration milestone.
## Inherits
- `mesa-panvk-bifrost` r4 (campaign-close 2026-05-21).
`/usr/lib/panvk-bifrost/libvulkan_panfrost.so` is the active Vulkan
ICD on ohm via `VK_ICD_FILENAMES`.
- `libva-v4l2-request-fourier` on ohm — proves the V4L2 stateless
H.264 decode path on hantro works at 1.16× realtime (lower-stack
measurement). Reference for the V4L2 ↔ H.264 mapping. **Device
ownership question lives here** (only one userspace can hold
`/dev/video1` at a time).
- 9(+1)-phase Claude-Assisted Development Process (see
`~/.claude/projects/-home-mfritsche-src/memory/feedback_dev_process.md`).
## Non-goals (explicit)
- No Mesa upstream MR (permanent rule: never upstream).
- No H.265, no AV1, no VP9 in this campaign.
- No Brave-side modification.
- No rebuild of Brave from source (chromium-fourier exists for the
open-source case; this campaign exists *because* Brave isn't).
- No re-implementation of libva — `libva-v4l2-request-fourier` stays
the libva backend, this is the Vulkan backend, they coexist via
device-arbitration policy (TBD in Phase 0).
— claude-noether, 2026-05-21
@@ -0,0 +1,59 @@
Hardware acceleration methods:
vdpau
vaapi
drm
vulkan
v4l2request
---
Valid values (with alternative full names):
vulkan (dpx-vulkan)
vulkan (ffv1-vulkan)
vulkan (h264-vulkan)
vulkan (hevc-vulkan)
vulkan (prores-vulkan)
vulkan (prores_raw-vulkan)
vulkan (vp9-vulkan)
vulkan (av1-vulkan)
vaapi (h263-vaapi)
vaapi (h263p-vaapi)
vaapi (h264-vaapi)
vaapi (hevc-vaapi)
vaapi (mjpeg-vaapi)
vaapi (mpeg2video-vaapi)
vaapi (mpeg4-vaapi)
vaapi (vc1-vaapi)
vaapi (vp8-vaapi)
vaapi (vp9-vaapi)
vaapi (vvc-vaapi)
vaapi (wmv3-vaapi)
vaapi (av1-vaapi)
vdpau (h263-vdpau)
vdpau (h263p-vdpau)
vdpau (h264-vdpau)
---
Plugin Details:
Name vulkan
Description Vulkan plugin
Filename /usr/lib/gstreamer-1.0/libgstvulkan.so
Version 1.28.3
License LGPL
Source module gst-plugins-bad
Documentation https://gstreamer.freedesktop.org/documentation/vulkan/
Source release date 2026-05-11
Binary package Arch Linux GStreamer 1.28.3-1
Origin URL https://www.archlinux.org/
vulkancolorconvert: Vulkan Color Convert
vulkandeviceprovider: Vulkan Device Provider
vulkandownload: Vulkan Downloader
vulkanimageidentity: Vulkan Image Identity
vulkanoverlaycompositor: Vulkan Overlay Compositor
vulkanshaderspv: Vulkan Shader SPV
vulkanupload: Vulkan Uploader
vulkanviewconvert: Vulkan View Convert
8 features:
+-- 7 elements
+-- 1 device providers
@@ -0,0 +1,10 @@
WARNING: panvk is not a conformant Vulkan implementation, testing use only.
[info] device[0]: Mali-G52 r1 MC1 (vendor=13b5 device=74021000)
[FAIL] VK_KHR_video_queue
[FAIL] VK_KHR_video_decode_queue
[FAIL] VK_KHR_video_decode_h264
[info] qf[0]: flags=0x00000007 count=1
[FAIL] queue family with VK_QUEUE_VIDEO_DECODE_BIT_KHR
[FAIL] queue family advertising DECODE_H264 codec op
=== OVERALL: FAIL (Phase 3 baseline expected) ===
@@ -0,0 +1,11 @@
WARNING: panvk is not a conformant Vulkan implementation, testing use only.
[info] device[0]: Mali-G52 r1 MC1 (vendor=13b5 device=74021000)
[PASS] VK_KHR_video_queue
[PASS] VK_KHR_video_decode_queue
[PASS] VK_KHR_video_decode_h264
[info] qf[0]: flags=0x00000007 count=1
[info] qf[1]: flags=0x00000024 count=1
[PASS] queue family with VK_QUEUE_VIDEO_DECODE_BIT_KHR
[PASS] queue family advertising DECODE_H264 codec op
=== OVERALL: PASS ===
@@ -0,0 +1,427 @@
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libxcb.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libxcb.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/usr/lib/libxcb.so.1", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libSM.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libSM.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/lib/libSM.so.6", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libICE.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libICE.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/lib/libICE.so.6", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libX11.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libX11.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/lib/libX11.so.6", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libXext.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libXext.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/lib/libXext.so.6", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libwayland-client.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libwayland-client.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/lib/libwayland-client.so.0", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libvulkan.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libvulkan.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/lib/libvulkan.so.1", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libshaderc_shared.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libshaderc_shared.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/lib/libshaderc_shared.so.1", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libvkvideo-decoder.so.1", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libstdc++.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/lib/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libm.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/lib/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/lib/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/usr/lib/libXau.so.6", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/usr/lib/libXdmcp.so.6", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/usr/lib/libuuid.so.1", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/usr/lib/libffi.so.8", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/usr/lib/libSPIRV-Tools.so", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/usr/lib/libglslang.so.16", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/usr/lib/libSPIRV-Tools-opt.so", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/lib/libnvidia-vkvideo-parser.so.1", O_RDONLY|O_CLOEXEC) = 3
47729 openat(AT_FDCWD, "/tmp/bbb_1080p30.h264", O_RDONLY) = 3
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d/renderdoc_capture.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_anti_lag.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d/renderdoc_capture.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_anti_lag.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_MESA_screenshot.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_MESA_overlay.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_INTEL_nullhw.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_MESA_vram_report_limit.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d/renderdoc_capture.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_anti_lag.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d/renderdoc_capture.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_anti_lag.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_MESA_screenshot.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_MESA_overlay.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_INTEL_nullhw.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_MESA_vram_report_limit.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d/renderdoc_capture.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_anti_lag.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/tmp/iter17_icd.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/panvk-patched-libs/libvulkan_panfrost.so", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libdrm.so.2", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libz.so.1", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libzstd.so.1", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libX11-xcb.so.1", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libxcb-dri3.so.0", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libxcb-present.so.0", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libxcb-xfixes.so.0", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libxcb-sync.so.1", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libxcb-randr.so.0", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libxcb-shm.so.0", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libxshmfence.so.1", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libxcb-keysyms.so.1", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libdisplay-info.so.3", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libudev.so.1", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libexpat.so.1", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/tmp/iter17_icd.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d/renderdoc_capture.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_anti_lag.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d/renderdoc_capture.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_anti_lag.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/tmp/iter17_icd.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d/renderdoc_capture.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_anti_lag.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/etc/vulkan/implicit_layer.d/renderdoc_capture.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_anti_lag.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/implicit_layer.d/VkLayer_MESA_device_select.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/home/mfritsche/.config/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/xdg/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/etc/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/home/mfritsche/.local/share/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/share/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_MESA_screenshot.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_MESA_overlay.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_INTEL_nullhw.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/usr/share/vulkan/explicit_layer.d/VkLayer_MESA_vram_report_limit.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/tmp/iter17_icd.json", O_RDONLY) = 4
47729 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/lib/libVkLayer_MESA_device_select.so", O_RDONLY|O_CLOEXEC) = 4
47729 openat(AT_FDCWD, "/usr/local/share/drirc.d", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/usr/local/etc/drirc", O_RDONLY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/home/mfritsche/.drirc", O_RDONLY) = -1 ENOENT (No such file or directory)
47729 openat(AT_FDCWD, "/dev/dri", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
47729 openat(AT_FDCWD, "/sys/dev/char/226:1/device/uevent", O_RDONLY) = 5
47729 openat(AT_FDCWD, "/sys/dev/char/226:1/device/uevent", O_RDONLY) = 5
47729 openat(AT_FDCWD, "/sys/dev/char/226:1/device/uevent", O_RDONLY) = 5
47729 openat(AT_FDCWD, "/sys/dev/char/226:1/device/uevent", O_RDONLY) = 5
47729 openat(AT_FDCWD, "/sys/dev/char/226:128/device/uevent", O_RDONLY) = 5
47729 openat(AT_FDCWD, "/sys/dev/char/226:128/device/uevent", O_RDONLY) = 5
47729 openat(AT_FDCWD, "/sys/dev/char/226:128/device/uevent", O_RDONLY) = 5
47729 openat(AT_FDCWD, "/sys/dev/char/226:128/device/uevent", O_RDONLY) = 5
47729 openat(AT_FDCWD, "/sys/dev/char/226:0/device/uevent", O_RDONLY) = 5
47729 openat(AT_FDCWD, "/sys/dev/char/226:0/device/uevent", O_RDONLY) = 5
47729 openat(AT_FDCWD, "/sys/dev/char/226:0/device/uevent", O_RDONLY) = 5
47729 openat(AT_FDCWD, "/dev/dri/renderD128", O_RDWR|O_CLOEXEC) = 4
47729 ioctl(4, DRM_IOCTL_VERSION, 0xaaaaf8921470) = 0
47729 ioctl(4, DRM_IOCTL_VERSION, 0xaaaaf8921470) = 0
47729 ioctl(4, DRM_IOCTL_VERSION, 0xaaaaf8921470) = 0
47729 ioctl(4, DRM_IOCTL_VERSION, 0xaaaaf8921470) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64add68) = 0
47729 ioctl(4, DRM_IOCTL_GET_CAP, 0xffffe64add78) = 0
47729 ioctl(4, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64adcc0) = 0
47729 ioctl(4, DRM_IOCTL_SYNCOBJ_WAIT, 0xffffe64adca0) = 0
47729 ioctl(4, DRM_IOCTL_SYNCOBJ_DESTROY, 0xffffe64adcd0) = 0
47729 openat(AT_FDCWD, "/home/mfritsche/.cache/mesa_shader_cache/index", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 5
47729 openat(AT_FDCWD, "/sys/class/drm/card0/device/boot_vga", O_RDONLY <unfinished ...>
47730 openat(AT_FDCWD, "/sys/devices/system/cpu/possible", O_RDONLY|O_CLOEXEC <unfinished ...>
47729 <... openat resumed>) = -1 ENOENT (No such file or directory)
47730 <... openat resumed>) = 6
47729 openat(AT_FDCWD, "/sys/class/drm/card0/device/boot_vga", O_RDONLY) = -1 ENOENT (No such file or directory)
47730 openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cpu_capacity", O_RDONLY) = 5
47730 openat(AT_FDCWD, "/sys/devices/system/cpu/cpu1/cpu_capacity", O_RDONLY) = 5
47730 openat(AT_FDCWD, "/sys/devices/system/cpu/cpu2/cpu_capacity", O_RDONLY) = 5
47730 openat(AT_FDCWD, "/sys/devices/system/cpu/cpu3/cpu_capacity", O_RDONLY <unfinished ...>
47729 ioctl(6, DRM_IOCTL_VERSION, 0xaaaaf89211e0 <unfinished ...>
47730 <... openat resumed>) = 5
47729 <... ioctl resumed>) = 0
47729 ioctl(6, DRM_IOCTL_VERSION, 0xaaaaf89211e0) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_EXYNOS_GEM_GET or DRM_IOCTL_PANFROST_GET_PARAM or DRM_IOCTL_QXL_GETPARAM or DRM_IOCTL_TEGRA_SYNCPT_WAIT or DRM_IOCTL_V3D_GET_PARAM or DRM_IOCTL_VC4_MMAP_BO, 0xffffe64ae598) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae540) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae540) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae540) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae578) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae540) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae578) = 0
47729 ioctl(6, DRM_IOCTL_GET_CAP, 0xffffe64ae5d8) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64afd90) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64afde8) = 0
47729 openat(AT_FDCWD, "/dev/video1", O_RDWR|O_NONBLOCK) = 5
47729 openat(AT_FDCWD, "/dev/media0", O_RDWR|O_NONBLOCK) = 7
47729 ioctl(5, VIDIOC_QUERYCAP, {driver="hantro-vpu", card="rockchip,rk3568-vpu-dec", bus_info="platform:fdea0000.video-codec", version=KERNEL_VERSION(7, 0, 0), capabilities=V4L2_CAP_VIDEO_M2M_MPLANE|V4L2_CAP_EXT_PIX_FORMAT|V4L2_CAP_STREAMING|V4L2_CAP_DEVICE_CAPS, device_caps=V4L2_CAP_VIDEO_M2M_MPLANE|V4L2_CAP_EXT_PIX_FORMAT|V4L2_CAP_STREAMING}) = 0
47729 ioctl(5, VIDIOC_S_FMT, {type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, fmt.pix_mp={width=1920, height=1088, pixelformat=v4l2_fourcc('S', '2', '6', '4') /* V4L2_PIX_FMT_H264_SLICE */, field=V4L2_FIELD_ANY, colorspace=V4L2_COLORSPACE_DEFAULT, plane_fmt=[{sizeimage=4194304, bytesperline=0}], num_planes=1}} => {fmt.pix_mp={width=1920, height=1088, pixelformat=v4l2_fourcc('S', '2', '6', '4') /* V4L2_PIX_FMT_H264_SLICE */, field=V4L2_FIELD_NONE, colorspace=V4L2_COLORSPACE_DEFAULT, plane_fmt=[{sizeimage=4194304, bytesperline=0}], num_planes=1}}) = 0
47729 ioctl(5, VIDIOC_S_FMT, {type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, fmt.pix_mp={width=1920, height=1088, pixelformat=v4l2_fourcc('N', 'V', '1', '2') /* V4L2_PIX_FMT_NV12 */, field=V4L2_FIELD_ANY, colorspace=V4L2_COLORSPACE_DEFAULT, plane_fmt=[{sizeimage=0, bytesperline=0}], num_planes=1}} => {fmt.pix_mp={width=1920, height=1088, pixelformat=v4l2_fourcc('N', 'V', '1', '2') /* V4L2_PIX_FMT_NV12 */, field=V4L2_FIELD_NONE, colorspace=V4L2_COLORSPACE_DEFAULT, plane_fmt=[{sizeimage=3655712, bytesperline=1920}], num_planes=1}}) = 0
47729 ioctl(5, VIDIOC_REQBUFS, {type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, memory=V4L2_MEMORY_DMABUF, count=18 => 18}) = 0
47729 ioctl(5, VIDIOC_REQBUFS, {type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, memory=V4L2_MEMORY_MMAP, count=18 => 18}) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(7, MEDIA_IOC_REQUEST_ALLOC, 0xffffe64ad5cc) = 0
47729 ioctl(5, VIDIOC_S_EXT_CTRLS, {ctrl_class=0 /* V4L2_CTRL_CLASS_??? */, count=2, controls=[{id=0xa40900 /* V4L2_CID_??? */, size=0, value=1, value64=1}, {id=0xa40901 /* V4L2_CID_??? */, size=0, value=1, value64=1}]} => {controls=[{id=0xa40900 /* V4L2_CID_??? */, size=0, value=1, value64=1}, {id=0xa40901 /* V4L2_CID_??? */, size=0, value=1, value64=1}]}) = 0
47729 ioctl(5, VIDIOC_STREAMON, [V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE]) = 0
47729 ioctl(5, VIDIOC_STREAMON, [V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE]) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ae410) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae230) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae1b0) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae3d0) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae408) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae310) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae368) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae310) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae368) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae310) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae368) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae310) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae368) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae310) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae368) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae310) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae368) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae310) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae368) = 0
47729 ioctl(6, DRM_IOCTL_AMDXDNA_CONFIG_HWCTX or DRM_IOCTL_IVPU_BO_CREATE or DRM_IOCTL_PANFROST_CREATE_BO, 0xffffe64ae310) = 0
47729 ioctl(6, DRM_IOCTL_ETNAVIV_GEM_INFO or DRM_IOCTL_OMAP_GEM_NEW or DRM_IOCTL_PANFROST_MMAP_BO or DRM_IOCTL_V3D_MMAP_BO or DRM_IOCTL_VC4_CREATE_BO or DRM_IOCTL_VIRTGPU_GETPARAM, 0xffffe64ae368) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_WAIT, 0xffffe64ac1c0) = 0
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_RESET, 0xffffe64ac3d8) = 0
47729 ioctl(6, DRM_IOCTL_PRIME_HANDLE_TO_FD, 0xffffe64abc08) = 0
47729 ioctl(6, DRM_IOCTL_PRIME_HANDLE_TO_FD, 0xffffe64abc08) = 0
47729 ioctl(5, VIDIOC_S_EXT_CTRLS, {ctrl_class=0xf010000 /* V4L2_CTRL_CLASS_??? */, count=4, controls=[{id=0xa40902 /* V4L2_CID_??? */, size=1048, string="M\0)\0\1\0\0\1\0\3\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...}, {id=0xa40903 /* V4L2_CID_??? */, size=12, string="\0\0\0\0\0\0\2\0\0\0\n\0"}, {id=0xa40907 /* V4L2_CID_??? */, size=560, string="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...}, {id=0xa40904 /* V4L2_CID_??? */, size=480, string="\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20"...}]} => {controls=[{id=0xa40902 /* V4L2_CID_??? */, size=1048, string="M\0)\0\1\0\0\1\0\3\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...}, {id=0xa40903 /* V4L2_CID_??? */, size=12, string="\0\0\0\0\0\0\2\0\0\0\n\0"}, {id=0xa40907 /* V4L2_CID_??? */, size=560, string="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...}, {id=0xa40904 /* V4L2_CID_??? */, size=480, string="\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20\20"...}]}) = 0
47729 ioctl(5, VIDIOC_QBUF, {type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, index=0, memory=V4L2_MEMORY_DMABUF, length=1, bytesused=0, flags=V4L2_BUF_FLAG_IN_REQUEST|V4L2_BUF_FLAG_REQUEST_FD|V4L2_BUF_FLAG_TIMESTAMP_COPY|V4L2_BUF_FLAG_TSTAMP_SRC_EOF, ...}) = 0
47729 ioctl(5, VIDIOC_QBUF, {type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, index=0, memory=V4L2_MEMORY_MMAP, m.offset=0xe64ab9e8, length=1, bytesused=0, flags=V4L2_BUF_FLAG_QUEUED|V4L2_BUF_FLAG_TIMESTAMP_COPY|V4L2_BUF_FLAG_TSTAMP_SRC_EOF, ...}) = 0
47729 ioctl(8, MEDIA_REQUEST_IOC_QUEUE, 0xffffe64ab990) = -1 EINVAL (Invalid argument)
47729 ioctl(6, DRM_IOCTL_SYNCOBJ_CREATE, 0xffffe64ac320) = 0
47729 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
47730 +++ killed by SIGSEGV (core dumped) +++
47729 +++ killed by SIGSEGV (core dumped) +++
@@ -0,0 +1,23 @@
Enter decoder test
WARNING: panvk is not a conformant Vulkan implementation, testing use only.
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_ycbcr_2plane_444_formats is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_descriptor_buffer is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_KHR_video_maintenance1 is missing for device with name: Mali-G52 r1 MC1
WARNING: videoMaintenance1 feature not supported
Test Video Input Information
Codec : decode h.264
Coded size : [1920, 1080]
Chroma Subsampling: 420, LUMA: 8-bit, CHROMA: 8-bit,
Video Input Information
Codec : AVC/H.264
Frame rate : 0/0 = 0 fps
Sequence : Progressive
Coded size : [1920, 1088]
Display area : [0, 0, 1920, 1080]
Chroma : YCbCr 420
Bit depth : 8
Video Decoding Params:
Num Surfaces : 13
Resize : 1920 x 1088
MESA: info: panvk_video: decoded frame #0 (slot=0 refs=0 src=6273)
timeout: the monitored command dumped core
@@ -0,0 +1,24 @@
Enter decoder test
WARNING: panvk is not a conformant Vulkan implementation, testing use only.
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_ycbcr_2plane_444_formats is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_descriptor_buffer is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_KHR_video_maintenance1 is missing for device with name: Mali-G52 r1 MC1
WARNING: videoMaintenance1 feature not supported
Test Video Input Information
Codec : decode h.264
Coded size : [1920, 1080]
Chroma Subsampling: 420, LUMA: 8-bit, CHROMA: 8-bit,
Video Input Information
Codec : AVC/H.264
Frame rate : 0/0 = 0 fps
Sequence : Progressive
Coded size : [1920, 1088]
Display area : [0, 0, 1920, 1080]
Chroma : YCbCr 420
Bit depth : 8
Video Decoding Params:
Num Surfaces : 13
Resize : 1920 x 1088
MESA: info: panvk_v4l2: CAPTURE[0] first 16 Y bytes 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (checksum 0-255: 0)
MESA: info: panvk_video: decoded frame #0 (slot=0 refs=0 src=6273)
timeout: the monitored command dumped core
@@ -0,0 +1,22 @@
Enter decoder test
WARNING: panvk is not a conformant Vulkan implementation, testing use only.
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_ycbcr_2plane_444_formats is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_descriptor_buffer is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_KHR_video_maintenance1 is missing for device with name: Mali-G52 r1 MC1
WARNING: videoMaintenance1 feature not supported
Test Video Input Information
Codec : decode h.264
Coded size : [1920, 1080]
Chroma Subsampling: 420, LUMA: 8-bit, CHROMA: 8-bit,
Video Input Information
Codec : AVC/H.264
Frame rate : 0/0 = 0 fps
Sequence : Interlaced
Coded size : [32, 2976]
Display area : [0, 0, 32, 2976]
Chroma : YCbCr 420
Bit depth : 8
Video Decoding Params:
Num Surfaces : 25
Resize : 32 x 2976
timeout: the monitored command dumped core
@@ -0,0 +1,22 @@
Enter decoder test
WARNING: panvk is not a conformant Vulkan implementation, testing use only.
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_ycbcr_2plane_444_formats is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_descriptor_buffer is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_KHR_video_maintenance1 is missing for device with name: Mali-G52 r1 MC1
WARNING: videoMaintenance1 feature not supported
Test Video Input Information
Codec : decode h.264
Coded size : [1920, 1080]
Chroma Subsampling: 420, LUMA: 8-bit, CHROMA: 8-bit,
Video Input Information
Codec : AVC/H.264
Frame rate : 0/0 = 0 fps
Sequence : Progressive
Coded size : [1920, 1088]
Display area : [0, 0, 1920, 1080]
Chroma : YCbCr 420
Bit depth : 8
Video Decoding Params:
Num Surfaces : 13
Resize : 1920 x 1088
timeout: the monitored command dumped core
@@ -0,0 +1,22 @@
Enter decoder test
WARNING: panvk is not a conformant Vulkan implementation, testing use only.
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_ycbcr_2plane_444_formats is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_descriptor_buffer is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_KHR_video_maintenance1 is missing for device with name: Mali-G52 r1 MC1
WARNING: videoMaintenance1 feature not supported
Test Video Input Information
Codec : decode h.264
Coded size : [1920, 1080]
Chroma Subsampling: 420, LUMA: 8-bit, CHROMA: 8-bit,
Video Input Information
Codec : AVC/H.264
Frame rate : 0/0 = 0 fps
Sequence : Progressive
Coded size : [1920, 1088]
Display area : [0, 0, 1920, 1080]
Chroma : YCbCr 420
Bit depth : 8
Video Decoding Params:
Num Surfaces : 13
Resize : 1920 x 1088
timeout: the monitored command dumped core
@@ -0,0 +1,26 @@
Enter decoder test
WARNING: panvk is not a conformant Vulkan implementation, testing use only.
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_ycbcr_2plane_444_formats is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_descriptor_buffer is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_KHR_video_maintenance1 is missing for device with name: Mali-G52 r1 MC1
WARNING: videoMaintenance1 feature not supported
Test Video Input Information
Codec : decode h.264
Coded size : [1920, 1080]
Chroma Subsampling: 420, LUMA: 8-bit, CHROMA: 8-bit,
Video Input Information
Codec : AVC/H.264
Frame rate : 0/0 = 0 fps
Sequence : Progressive
Coded size : [1920, 1088]
Display area : [0, 0, 1920, 1080]
Chroma : YCbCr 420
Bit depth : 8
Video Decoding Params:
Num Surfaces : 13
Resize : 1920 x 1088
MESA: info: panvk_video: CmdBeginVideoCoding entered (stub)
MESA: info: panvk_video: CmdControlVideoCoding entered (stub) flags=0x1
MESA: info: panvk_video: CmdDecodeVideo frame#0 sps_id=0 pps_id=0 flags=0x0 refs=0 src_offset=0 src_size=6273
MESA: info: panvk_video: CmdEndVideoCoding entered (stub)
timeout: the monitored command dumped core
@@ -0,0 +1,25 @@
Enter decoder test
WARNING: panvk is not a conformant Vulkan implementation, testing use only.
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_ycbcr_2plane_444_formats is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_descriptor_buffer is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_KHR_video_maintenance1 is missing for device with name: Mali-G52 r1 MC1
WARNING: videoMaintenance1 feature not supported
Test Video Input Information
Codec : decode h.264
Coded size : [1920, 1080]
Chroma Subsampling: 420, LUMA: 8-bit, CHROMA: 8-bit,
Video Input Information
Codec : AVC/H.264
Frame rate : 0/0 = 0 fps
Sequence : Progressive
Coded size : [1920, 1088]
Display area : [0, 0, 1920, 1080]
Chroma : YCbCr 420
Bit depth : 8
Video Decoding Params:
Num Surfaces : 13
Resize : 1920 x 1088
MESA: error: panvk_v4l2: QBUF CAPTURE failed: Bad address
MESA: error: panvk_video: decode submit failed rc=-14
timeout: the monitored command dumped core
bash: line 6: 47380 Segmentation fault timeout 10 ./vk_video_decoder/test/vulkan-video-dec-simple-test --codec h264 -i /tmp/bbb_1080p30.h264 --noPresent 2>&1
@@ -0,0 +1,10 @@
Enter decoder test
WARNING: panvk is not a conformant Vulkan implementation, testing use only.
HasAllDeviceExtensions: ERROR: required device extension VK_KHR_video_queue is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions: ERROR: required device extension VK_KHR_video_decode_queue is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions: ERROR: required device extension VK_KHR_video_decode_h264 is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_ycbcr_2plane_444_formats is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_EXT_descriptor_buffer is missing for device with name: Mali-G52 r1 MC1
HasAllDeviceExtensions : WARNING: requested optional device extension VK_KHR_video_maintenance1 is missing for device with name: Mali-G52 r1 MC1
ERROR: Found physical device with name: Mali-G52 r1 MC1, vendor ID: 13b5, and device ID: 74021000 NOT having the required extensions!
Error creating video decoder
+307
View File
@@ -0,0 +1,307 @@
# Phase 0 — substrate / motivation / inventory for panvk-bifrost-video
## Research question (one sentence)
**Can `mesa-panvk-bifrost-video` expose `VK_KHR_video_decode_h264`
(plus its supporting extensions `VK_KHR_video_queue`,
`VK_KHR_video_decode_queue`, `VK_KHR_video_maintenance1`) backed by
the RK3566 hantro V4L2 stateless VPU, such that Khronos
`vk-video-samples` decodes a 1080p H.264 BBB clip on ohm end-to-end
with hantro engagement provable via `fuser /dev/video1`?**
## Operator-supplied mechanism (load-bearing claim — verbatim from session)
> "brave is closed source and walled off from v4l2-request (checks for
> CHROME_OS at build time) and walled off from vaapi (expects a Vulkan
> output device I think). This is the exact reason I want the Vulkan
> driver - so brave does not just use vulkan to draw buttons, but to
> actively use the features to offload, create buffers that kwin can
> understand, yadda yadda younameit."
The structural insight: the unmodifiable consumer (Brave) speaks
Vulkan natively as its compositor + GPU process buffer broker. If
Vulkan grows a decode capability, Brave's existing dispatch hits it
without changes. The bridge to actual decoder hardware (V4L2-stateless
hantro) lives on the *driver* side of the boundary.
The structural claim has three parts that the campaign relies on:
1. **H.264 spec parameters map across protocols.** Both
`VkVideoDecodeH264PictureInfoKHR` / `VkVideoDecodeH264DpbSlotInfoKHR`
(Vulkan side) and the V4L2 stateless H264 controls
(`V4L2_CID_STATELESS_H264_SPS|PPS|DECODE_PARAMS|SLICE_PARAMS|
PRED_WEIGHTS|SCALING_MATRIX`) carry the same underlying H.264 spec
fields. The mapping is a tedious but mechanical translation, not a
semantic gap.
2. **Buffers can move across protocols zero-copy.** Both Vulkan
(`VkBuffer` / `VkImage` with `VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT`)
and V4L2 (`V4L2_MEMORY_DMABUF`) speak dmabuf. The compressed
bitstream buffer (Vulkan side) → V4L2 OUTPUT queue, and the V4L2
CAPTURE queue → decoded NV12 VkImage, can both route through
dmabuf fd handoffs.
3. **No GPU-side computation is required for the actual decode.**
The hantro is autonomous; once parameters and buffers are queued
via V4L2 ioctls, the VPU executes asynchronously. panvk's role
is *protocol translation*, not GPU shader execution.
## Predecessor carry-over (panvk-bifrost campaign close)
**State carried forward**:
- `mesa-panvk-bifrost` r4 installed on ohm:
`/usr/lib/panvk-bifrost/libvulkan_panfrost.so` (md5
7810235db2a8379323acf8d2d521be9a)
- ICD JSON at `/usr/lib/panvk-bifrost/icd.json`
- `VK_ICD_FILENAMES` opt-in pattern (via `brave-vulkan` launcher or
direct env)
- `PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1` requirement (still in force —
panvk's self-non-conformance gate)
- `libva-v4l2-request-fourier` installed on ohm (proves V4L2 H.264
decode path on hantro)
- Source pointers: NIR pass + sysval pattern in
`~/src/panvk-bifrost/iter17/applied_state/panvk_vX_xfb_lower.c`;
PKGBUILD shape in
`~/src/marfrit-packages/arch/mesa-panvk-bifrost/`
**Data NOT carried forward** (reference history only):
- iter15's 75.7% CTS pass — wrong metric for this campaign.
- iter17's 91.7% post-XFB-decomp — wrong metric.
- libva-v4l2-request-fourier 1.16× realtime — wrong protocol layer.
This campaign measures **VK_KHR_video_decode engagement + decode
throughput + frame correctness** in its own metric space. Phase 1
hypothesis goes here, Phase 3 measures fresh.
## Tooling and measurement-instrument inventory
### What's installed on ohm right now (live verification, not paper)
- `mesa-panvk-bifrost` r4-1 — Vulkan ICD substrate
- `vulkan-headers` (presumably — to be live-checked)
- `libva-v4l2-request-fourier` — currently holding `/dev/video1`
while running. **Coexistence policy needed.**
- `ffmpeg-v4l2-request-fourier` — uses libva path, same device
contention
- `mpv-fourier`, `kwin-fourier`, `qt6-base-fourier` — display stack
- Kernel: `linux-fresnel-fourier` — provides hantro v4l2 stateless
driver and the `dma_resv` patches
### What needs verification (Phase 0 open items)
- Does `vulkaninfo` on ohm enumerate ANY video queue family today?
Likely no, but baseline the no.
- Is the Vulkan loader on ohm new enough to support the `VK_KHR_video_*`
extension surface negotiation? (Vulkan headers 1.3.221+ minimum.)
- Are vk-video-samples buildable on aarch64 today?
Khronos repo `KhronosGroup/Vulkan-Samples` and
`nvpro-samples/vk_video_samples`. Build deps + cmake config.
- Does Mesa ship `src/vulkan/runtime/vk_video.c` helpers in
26.0.6, and are they usable from a video-queue-bearing driver?
- What's the device-ownership policy between `libva-v4l2-request-fourier`
(currently using `/dev/video1`) and `panvk-bifrost-video` if both
want decode access? V4L2 m2m allows only one process at a time.
### Reference implementations to read (not copy)
- **Mesa NVK** — `src/nouveau/vulkan/nvk_video.c` and surrounding.
Most recent Mesa VK_KHR_video implementation. Uses NVIDIA's NVDEC
via class methods. Read for: extension advertisement shape,
queue family registration, session/command lifecycle, DPB
management state machine.
- **Mesa Anv** — `src/intel/vulkan/anv_video.c`. Intel VCN. Mature.
Read for: parameter object handling, multi-decoder DPB tracking.
- **Mesa RADV** — `src/amd/vulkan/radv_video.c`. AMD UVD/VCN.
Read for: a third reference point on the abstractions Mesa's
`vk_video.c` runtime helper expects from a driver.
**Crucial**: do NOT copy these. Each driver dispatches into the
GPU's video engine via a tightly bound submit path. Our submit path
is `ioctl(VIDIOC_QBUF)` to /dev/video1, a fundamentally different
shape. Read the high-level structure (extension surface, queue
family bring-up, session object lifecycle), then implement against
the V4L2 backend ourselves.
### Reference for the V4L2 side (proven-working)
- `libva-v4l2-request-fourier` on github → marfrit fork on
packages.reauktion.de. Specifically:
- H.264 frame-based path (single CTRL_REQ, full frame in one slice)
- DECODE_PARAMS / SPS / PPS / SLICE_PARAMS / PRED_WEIGHTS /
SCALING_MATRIX control marshalling
- dmabuf import/export for CAPTURE queue
- Kernel v4l2-request docs: `Documentation/userspace-api/media/v4l/
ext-ctrls-codec-stateless.rst` — authoritative H.264 control
reference.
- `hantro_h264.c` in the kernel — read assemble_scaling_list,
reference_picture_list builder for the actual per-decode hardware
ops, gives a sense of what V4L2 will accept.
## In-session baseline anchor (per Phase 0 dev_process rule)
Predecessor's reference floors that must replicate at N=3 before
binding cells anchor to them:
1. `mesa-panvk-bifrost` r4 enumerates a Vulkan device and
`probe_winding` passes 3/3 topologies. → **Verified earlier this
session at 14:30 UTC** with packaged r4-1; sufficient as session
anchor.
2. `libva-v4l2-request-fourier` decodes BBB H.264 via hantro. → **Verified
2026-05-21**: ffmpeg `-hwaccel vaapi` + libva = 1.56× realtime on the
same BBB file used in this session's brave instrumentation run.
ffmpeg `-hwaccel v4l2request` (direct, bypassing libva) = 1.73× realtime.
Both paths green at N=1 each; N=3 anchor still pending but the
single-rep result reproduces the iter14 measurement at same magnitude
so likely-stable.
3. `vulkaninfo` reports advertised extensions and queue families. →
**Measured 2026-05-21** with `VK_ICD_FILENAMES=/usr/lib/panvk-bifrost/icd.json`
`PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1`: Vulkan 1.4.350 loader; 19
instance extensions; **zero `VK_KHR_video_*` extensions**; single queue
family, queueCount=1; no `VK_QUEUE_VIDEO_DECODE_BIT` anywhere. Clean
baseline — campaign deliverable is 0→1 queue family + extensions on
panvk-bifrost.
If (2) or (3) fail to anchor, loop back: investigate the rig before
moving to Phase 1.
## Open questions for Phase 1 to resolve
These are *known unknowns* — they don't block Phase 0 close, but
Phase 1's metric choice depends on the answer.
### Q1 — Device ownership: how do libva and panvk-bifrost-video coexist?
`/dev/video1` (hantro m2m) accepts one process at a time. Options:
- **A. Mutually exclusive use**: only one runtime holds the device at
a time; user picks via env var (`LIBVA_DRIVER_NAME=null` → Vulkan
path, etc.).
- **B. Shared-device daemon**: a small userspace daemon owns
`/dev/video1` and arbitrates V4L2 requests from multiple clients
via a custom IPC protocol. Complex. Not for Phase 1.
- **C. Drop libva entirely for the consumers we care about**: brave
uses Vulkan; firefox-fourier already uses V4L2-direct, not libva;
mpv-fourier uses ffmpeg-v4l2-request-fourier. If libva-v4l2-request
isn't the path for any consumer in scope, drop it from the running
set for video tasks.
**Recommendation for Phase 1**: lock A. Document the env-toggle.
Defer B to later iteration if real workloads need it.
### Q2 — Does Brave even probe VK_KHR_video_decode_h264 today? — ANSWERED 2026-05-21
**No, and won't engage even if we offer it.** `strings /opt/brave-bin/*`
returns **zero hits** for `VK_KHR_video` / `VulkanVideoDecoder`.
Chromium's VulkanVideoDecoder is a Khronos design draft (Dec 2025,
13-week implementation plan, not merged) — see
[Vulkan Video Integration into Chromium](https://www.khronos.org/vulkan/chrome-video/vulkan_video_integration.html).
Beyond probing, brave-bin on PineTab2 is structurally unable to engage
HW video decode at all due to the chromeos-pipeline ImageProcessor wall —
see [[fourier:brave_arm64_vaapi_wall]] on DokuWiki or
`~/src/brave-vaapi-fourier/DEFINITIVE_FINDING.md` (measured 2026-05-21).
**Implication for this campaign**: Brave is NOT a Phase 1 consumer.
The immediate consumer story:
- **mpv with `--hwdec=vulkan`** — enumerated today on ohm for h264 /
hevc / vp9 / av1 (mpv hwdec=help confirms). Uses libavcodec's
`hwcontext_vulkan.c` path. Once panvk-bifrost-video exposes
`VK_KHR_video_decode_h264`, mpv-fourier becomes an immediate consumer.
- **ffmpeg with `-hwaccel vulkan`** — first-class hwaccel method,
confirmed in `ffmpeg -hwaccels` on ohm.
- **gstreamer 1.28.3 `vulkan` plugin** — gst-plugins-bad ships
`vulkan{h264,h265,av1}dec` (per-codec presence on this build TBD).
- **Future Brave**: gets it free when chromium upstream lands
VulkanVideoDecoder (months/year-ish).
Phase 1 milestone stays **vk-video-samples** as the test client (isolates
driver work from consumer-side bugs). Phase 8 close-criteria will add
"mpv-fourier `--hwdec=vulkan` decodes BBB H.264 on ohm with fuser
showing /dev/video1 engagement" — the real-world consumer proof.
### Q3 — Vulkan ↔ V4L2 DPB management mismatch
Vulkan API thinks of DPB (Decoded Picture Buffer) as an array of
`VkImage` slots owned by the driver, with the application telling the
driver which slot is the output frame, which slots are references
for the current decode, and when a slot can be reused.
V4L2 stateless H.264 thinks of DPB as a runtime data structure
encoded in `V4L2_CID_STATELESS_H264_DECODE_PARAMS` (the `dpb[16]`
array of `v4l2_h264_dpb_entry`), pointing at indices of frames in
the CAPTURE queue.
The mapping is doable but not trivial. The Mesa NVK/Anv/RADV
implementations have abstractions around this in
`src/vulkan/runtime/vk_video.c`. Phase 0 close: read that file end
to end, decide whether it's a usable harness for our V4L2 backend
or whether we need a parallel set of helpers.
### Q4 — Vulkan video queue family expectations vs panvk's job manager
panvk on Bifrost is JM-class (Job Manager). Job Manager has graphics
+ compute + fragment ringbuffers; it has no concept of a separate
video ring. The Vulkan API expects a queue family with
`VK_QUEUE_VIDEO_DECODE_BIT_KHR` and an associated `VkQueue` instance
you submit decode commands to.
Our submit path won't actually go to the JM at all — it'll go to
V4L2. So the panvk video queue is "fake" from the GPU's perspective:
it's a userspace queue that translates command-buffer-recorded video
ops into V4L2 ioctls. This is fine architecturally but needs the
queue infrastructure (synchronization, timeline semaphores between
graphics and video families) to be wired up correctly. NVK probably
has the cleanest reference for this since NVDEC is also
architecturally separate from the graphics scheduler on Nvidia.
### Q5 — Hantro per-stream device contention vs concurrent decodes
VK_KHR_video allows multiple `VkVideoSessionKHR` instances per device.
If two of them concurrently want to decode different streams, the
hantro m2m driver serializes them via the V4L2 queueing model, but
performance contention is a real issue. Phase 1's target is a single
decode session; multi-session concurrency is a Phase >>1 problem.
## Predecessor inheritance summary
| Inherited | Source | How used |
|---|---|---|
| Vulkan ICD substrate (`libvulkan_panfrost.so` r4) | panvk-bifrost campaign | The library we extend with video |
| PKGBUILD pattern for `mesa-panvk-bifrost-*` packages | marfrit-packages/arch/mesa-panvk-bifrost | Template for new `mesa-panvk-bifrost-video` |
| V4L2 stateless H.264 control marshalling | libva-v4l2-request-fourier | Reference; not linked into panvk |
| Kernel `dma_resv` patches | linux-fresnel-fourier | Buffer fence correctness on V4L2 producers |
| Build/CI on Gitea Actions aarch64 runner | marfrit-packages | Same pipeline, new package |
| Dev process 9(+1)-phase loop | `feedback_dev_process.md` | This campaign follows |
## Phase 0 close criteria (when this loop step is done)
- [x] Research question + mechanism locked
- [x] Predecessor state vs data categorized
- [x] Live verification on ohm — vulkaninfo baselined, libva-v4l2-request
re-anchored via ffmpeg side-by-side (1.56×/1.73× realtime confirmed)
- [x] Open questions tabled — Q1 (device ownership, lock A: mutex with env),
Q2 (Brave probe — ANSWERED: no, won't engage, see DokuWiki finding),
Q3 (DPB mapping — Phase 1 reads Mesa NVK reference),
Q4 (video queue family on JM — Phase 1 design item),
Q5 (multi-session concurrency — Phase >>1 scope, lock single-session for now)
- [ ] vk-video-samples build attempt on aarch64 — **PENDING**, last
gating item for Phase 0 close
- [ ] Phase 0 evidence dir populated with anchored measurements
(`phase0_evidence/`) — **PENDING** packaging the raw measurements
## What Phase 1 will lock against
After Phase 0 closes, Phase 1 will state the success metric in
measurable terms. Tentative: *"vk-video-samples (or equivalent
Khronos Vulkan video test client, version locked) decodes a
1080p H.264 sample to NV12 frames on ohm using mesa-panvk-bifrost-video,
with `fuser /dev/video1` confirming hantro engagement, with no
software fallback in `chrome://media-internals`-equivalent
diagnostics, at no worse than 1.0× realtime."*
The 1.0× threshold is conservative; libva-v4l2-request-fourier
already does 1.16× via the same V4L2 path. The driver-bridge cost
should be a few percent at worst. Anything below 0.7× indicates a
buffer-copy regression to investigate.
— claude-noether, 2026-05-21
@@ -0,0 +1,669 @@
# Phase 1 Source Map — VK_KHR_video_decode_h264 on panvk-bifrost (V4L2/Hantro backend)
**Campaign**: panvk-bifrost-video (successor to panvk-bifrost r4)
**Mesa version**: 26.0.6 (source tree on ohm at `/home/mfritsche/mesa-build/mesa-26.0.6/`)
**Phase 1 goal**: vk-video-samples simple-test passes `HasAllDeviceExtensions`, creates a `VkVideoSessionKHR`, submits one `VkCmdDecodeVideoKHR`. Decode correctness is Phase 7.
**Backend**: V4L2-stateless `hantro` VPU on RK3566/PineTab2 via `/dev/video1` + `/dev/media0`. Mali GPU is not the decode engine.
> Convention used throughout: every file path is **on ohm** unless otherwise stated. Cite as `FILE:LINE`. When citing libva-v4l2-request-fourier (the reference for V4L2-side bridging), the path is on the **workstation** at `/home/mfritsche/src/libva-v4l2-request-fourier/`.
---
## Executive summary
The Mesa 26.0.6 video stack is structured in three layers:
1. **Shared runtime helpers**`src/vulkan/runtime/vk_video.{c,h}` (3413 + 436 lines). Owns: `vk_video_session_init`/`finish`, `vk_video_session_parameters_{create,update,destroy}`, H.264 SPS/PPS storage as `struct vk_video_h264_{sps,pps}`, and the `vk_common_{Create,Update,Destroy}VideoSessionParametersKHR` entrypoints (full dispatch coverage of the parameters object). Codec parameter parsing helpers (`vk_video_get_h264_parameters`, `vk_video_find_h264_dec_std_{sps,pps}`).
2. **Driver-side video** — anv (`src/intel/vulkan/anv_video.c` + `genX_cmd_video.c`) and radv (`src/amd/vulkan/radv_video.c`). Each driver owns: extension advertisement, queue-family advertisement, `GetPhysicalDeviceVideoCapabilitiesKHR`, `GetPhysicalDeviceVideoFormatPropertiesKHR`, `Create/DestroyVideoSessionKHR`, `GetVideoSessionMemoryRequirementsKHR`, `BindVideoSessionMemoryKHR`, and the per-frame `CmdBeginVideoCodingKHR`/`CmdControlVideoCodingKHR`/`CmdDecodeVideoKHR`/`CmdEndVideoCodingKHR` recording.
3. **HW codegen** — driver emits register packets into a command stream during the `CmdDecodeVideoKHR` record; the existing GPU queue submit path then ships that stream to the video engine.
**Critical mismatch for our backend**: layer 3 does not exist for us. The Hantro VPU has no Mali-side command stream. It has its own kernel device node (`/dev/video1` + `/dev/media0`) with a request-API ioctl interface. So we keep layer 1 verbatim (huge win — all H.264 SPS/PPS parsing comes free), reuse layer 2's *interface contracts*, and replace layer 2's command-stream codegen with deferred V4L2 control marshalling + submit-time `VIDIOC_QBUF`/`POLL`/`VIDIOC_DQBUF`.
**vk-video-samples simple-test trinity** of required extensions:
- `VK_KHR_video_queue` (spec v8) — shared base
- `VK_KHR_video_decode_queue` (spec v8) — decode-specific commands
- `VK_KHR_video_decode_h264` (spec v9) — H.264 profile
None are advertised in panvk-bifrost r4 today (Mesa 26.0.6 `src/panfrost/vulkan/panvk_vX_physical_device.c:539-540` explicitly sets `unifiedImageLayoutsVideo = false` and leaves all `KHR_video_*` extension flags unset / default-false).
---
## A. Extension surface
### A.1 Where extensions are advertised
panvk extension table is built by `panvk_per_arch(get_physical_device_extensions)` in `src/panfrost/vulkan/panvk_vX_physical_device.c:35-160`. This is a single struct-literal that fills a `struct vk_device_extension_table` field-by-field. To add the three required extensions we extend the literal between (alphabetical sort by KHR_):
```
.KHR_video_decode_h264 = true, /* gated on hantro probe success */
.KHR_video_decode_queue = true,
.KHR_video_queue = true,
```
The natural insertion point is between `.KHR_vertex_attribute_divisor = true,` (line ~123) and `.KHR_vulkan_memory_model = true,` (line ~124).
Anv reference for comparison: `src/intel/vulkan/anv_physical_device.c:262-274`:
```c
.KHR_video_queue = video_decode_enabled || video_encode_enabled,
.KHR_video_decode_queue = video_decode_enabled,
.KHR_video_decode_h264 = VIDEO_CODEC_H264DEC && video_decode_enabled,
```
where `video_decode_enabled` is `device->instance->debug & ANV_DEBUG_VIDEO_DECODE` (`anv_physical_device.c:153`). Anv gates this behind a debug flag because anv-side decode is still considered experimental. We probably want the same gating pattern, except keyed on hantro probe success rather than a debug flag — so the extension is advertised only if `/dev/video1` opens and reports H.264 OUTPUT format support.
### A.2 Feature struct fields
vk-video-samples simple-test requires `VK_KHR_video_queue` and friends advertised. The strictly-required feature struct fields are:
- `VkPhysicalDeviceVideoMaintenance1FeaturesKHR::videoMaintenance1`**only if** we advertise `KHR_video_maintenance1`. For Phase 1, the simple-test does NOT require maintenance1 — confirmed by reading test harness expectations. Skip in Phase 1.
- `VkPhysicalDeviceUnifiedImageLayoutsFeaturesKHR::unifiedImageLayoutsVideo` — currently `false` at `panvk_vX_physical_device.c:540`. Stays `false` for Phase 1 (transition rules still apply).
The shared `vk_video_session` struct (`vk_video.h:80-115`) carries the per-session profile bookkeeping that gets driven by the codec ops `pNext`. No driver-side feature toggles needed beyond the three extension booleans for Phase 1.
### A.3 vkGetPhysicalDeviceVideoCapabilitiesKHR routing
This is a **direct driver entrypoint** — there is no `vk_common_GetPhysicalDeviceVideoCapabilitiesKHR` in `src/vulkan/runtime/`. Verified: `grep -rn "vk_common_GetPhysicalDeviceVideo" /home/mfritsche/mesa-build/mesa-26.0.6/src/` returns no hits.
Driver-side, the entrypoint is generated via `vk_entrypoints_gen` from `vk_api.xml` (per `panvk/vulkan/meson.build:7-19`). The panvk symbol resolution uses the `panvk` prefix and per-arch shims `panvk_v6` / `panvk_v7` / `panvk_v9` / `panvk_v10` / `panvk_v12` / `panvk_v13`. So the symbol we need to provide is one of:
- `panvk_GetPhysicalDeviceVideoCapabilitiesKHR` (in `panvk_physical_device.c`) — common (arch-agnostic), since physical-device caps don't vary across Mali archs for V4L2-side decode (the VPU is on a separate engine entirely). **Recommended.**
- `panvk_per_arch(GetPhysicalDeviceVideoCapabilitiesKHR)` in a new `panvk_vX_video_decode.c` — only needed if the answer varies per arch, which it doesn't here.
Reference shape from anv (`anv_video.c:183-291`): the function takes `pVideoProfile` and fills `pCapabilities` (`maxCodedExtent`, `maxDpbSlots`, `maxActiveReferencePictures`, `minBitstreamBufferOffsetAlignment`, `stdHeaderVersion`), then walks the codec-specific `pNext` chain. For H.264-decode, that means `VkVideoDecodeH264CapabilitiesKHR` (anv lines 213-225) with `maxLevelIdc` and `fieldOffsetGranularity`. Also fills `VkVideoDecodeCapabilitiesKHR::flags = VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR` (anv line 205) — which is what we'll want too, because the Hantro CAPTURE buffers ARE the DPB (no separate scratch).
The hantro driver's real limits (4K H.264 decode confirmed on RK3566) drive these values; we want to be conservative for Phase 1 and use `maxCodedExtent = 1920x1088`, `maxDpbSlots = 17` (one more than `STD_VIDEO_H264_MAX_NUM_LIST_REF=16`, matches `ANV_VIDEO_H264_MAX_DPB_SLOTS` at `anv_private.h:6581`), `maxActiveReferencePictures = 16`.
### A.4 vkGetPhysicalDeviceVideoFormatPropertiesKHR routing
Same routing pattern as A.3 — direct driver entrypoint, no shared common path. Implement as `panvk_GetPhysicalDeviceVideoFormatPropertiesKHR` in `panvk_physical_device.c`.
Reference shape from anv (`anv_video.c:393-481`): walks `VkVideoProfileListInfoKHR` from `pVideoFormatInfo->pNext`, validates each profile, then outputs format entries. For H.264 8-bit, anv reports `VK_FORMAT_G8_B8R8_2PLANE_420_UNORM` (NV12-equivalent, anv:460).
This is exactly what we need. The hantro driver returns NV12 as `V4L2_PIX_FMT_NV12` on the CAPTURE queue (confirmed in libva-v4l2-request-fourier `src/h264.c` and via `v4l2_find_format` calls in `src/request.c:864-865` showing format-probe pattern). The dst usage flag merge in anv at lines 410-419 (where `VIDEO_DECODE_DST` triggers added flags including `SAMPLED_BIT | TRANSFER_DST_BIT`) is universal vulkan-video pattern and applies verbatim. Set:
- `format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM` (NV12)
- `imageType = VK_IMAGE_TYPE_2D`
- `imageTiling = VK_IMAGE_TILING_OPTIMAL` — but see G.2 below about how the underlying memory comes from V4L2, so this is a "logical" tiling decision
- `imageUsageFlags = VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR | VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT`
- `imageCreateFlags = VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR | VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT`
---
## B. Queue family registration
### B.1 Current state (r4)
`src/panfrost/vulkan/panvk_device.h:46-48`:
```
enum panvk_queue_family {
PANVK_QUEUE_FAMILY_GPU,
PANVK_QUEUE_FAMILY_BIND,
PANVK_QUEUE_FAMILY_COUNT,
};
```
Queue-family-properties query at `panvk_physical_device.c:557-595`:
```
[PANVK_QUEUE_FAMILY_GPU] = {
.queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT,
...
},
[PANVK_QUEUE_FAMILY_BIND] = {
.queueFlags = VK_QUEUE_SPARSE_BINDING_BIT,
.queueCount = 1,
},
```
Queue dispatch in `panvk_vX_device.c`:
- line 253-258 — `panvk_queue_check_status` switches on `queue->queue_family_index` to call `gpu_queue_check_status` or `bind_queue_check_status`
- line 269 — `panvk_device_check_status` iterates `for (uint32_t qfi = 0; qfi < PANVK_QUEUE_FAMILY_COUNT; qfi++)`
- line 305-313 — `panvk_queue_create` switches on `create_info->queueFamilyIndex` to dispatch to `panvk_per_arch(create_gpu_queue)` or `panvk_per_arch(create_bind_queue)`
- line 320-329 — `panvk_queue_destroy` symmetric
- line 546-561 — `panvk_per_arch(create_device)` iterates `pCreateInfo->queueCreateInfoCount`, calls `panvk_queue_create` for each
### B.2 What to add
Add a third enum value `PANVK_QUEUE_FAMILY_VIDEO_DECODE`. Slot ordering matters: Vulkan apps query queue families by index and the test client *typically* iterates looking for `VK_QUEUE_VIDEO_DECODE_BIT_KHR`. Index value is opaque so adding at end is safe.
```
enum panvk_queue_family {
PANVK_QUEUE_FAMILY_GPU,
PANVK_QUEUE_FAMILY_BIND,
PANVK_QUEUE_FAMILY_VIDEO_DECODE, /* NEW */
PANVK_QUEUE_FAMILY_COUNT,
};
```
Then in `panvk_physical_device.c:557-595` extend the props table:
```
[PANVK_QUEUE_FAMILY_VIDEO_DECODE] = {
.queueFlags = VK_QUEUE_VIDEO_DECODE_BIT_KHR | VK_QUEUE_TRANSFER_BIT,
.queueCount = 1,
.minImageTransferGranularity = {1, 1, 1}, /* match VPU mb alignment if needed */
},
```
Anv reference for this pattern: `src/intel/vulkan/anv_physical_device.c:2556-2576` (queue-family-init writing flags onto `pdevice->queue.families[family_count++]`). Anv also handles the `VkQueueFamilyVideoPropertiesKHR` pNext extension at `anv_physical_device.c:3012-3030`:
```c
case VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR: {
VkQueueFamilyVideoPropertiesKHR *prop = ...;
if (queue_family->queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) {
prop->videoCodecOperations = VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR | ...;
}
}
```
We need to mirror that pattern in `panvk_GetPhysicalDeviceQueueFamilyProperties2`. Right now it only walks `VkQueueFamilyGlobalPriorityPropertiesKHR` (at panvk_physical_device.c:589). Add a pNext walk for `VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR` and fill `videoCodecOperations = VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR`. Optional but recommended for Phase 1: also fill `VK_STRUCTURE_TYPE_QUEUE_FAMILY_QUERY_RESULT_STATUS_PROPERTIES_KHR` if test client asks (`anv_physical_device.c:3007-3011`).
### B.3 Queue identification at queue_create time
Driver dispatches at `panvk_vX_device.c:305-313` via `panvk_queue_create`. Extend the switch:
```
case PANVK_QUEUE_FAMILY_VIDEO_DECODE:
return panvk_per_arch(create_video_decode_queue)(
dev, create_info, queue_idx, out_queue);
```
And similarly extend `panvk_queue_destroy` (line 320-329) and `panvk_queue_check_status` (line 253-258).
For check_global_priority at panvk_vX_device.c:218-247 — the video decode family gets a new case that returns `VK_SUCCESS` for any priority (since the V4L2 device doesn't expose priority semantics) or just `VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR` like BIND.
### B.4 V4L2 submit path — clean hook into queue infrastructure
The existing `vk_queue` has a `driver_submit` callback (set in `jm/panvk_vX_gpu_queue.c:359`: `queue->vk.driver_submit = panvk_per_arch(gpu_queue_submit);`). The submit function takes a `struct vk_queue_submit` containing `command_buffers[]`, waits, signals.
For our V4L2 queue, the analog is: `queue->vk.driver_submit = panvk_per_arch(video_decode_queue_submit);` and the implementation does NOT touch Mali — it walks the cmdbuf's recorded V4L2 ops and dispatches each:
```
for each panvk_video_decode_op in cmdbuf->video_decode_ops:
media_request_reinit(op->request_fd) /* libva-v4l2-request-fourier media.c:51 */
VIDIOC_S_EXT_CTRLS(video_fd, request_fd,
{SPS, PPS, DECODE_PARAMS, SLICE_PARAMS, SCALING_MATRIX})
VIDIOC_QBUF(video_fd, OUTPUT, request_fd=op->request_fd) /* bitstream src */
VIDIOC_QBUF(video_fd, CAPTURE, dpb_buffer_index=op->dst_slot)
media_request_queue(op->request_fd) /* media.c:65 */
poll(request_fd, POLLPRI, timeout) /* media.c:79 */
VIDIOC_DQBUF(video_fd, OUTPUT)
VIDIOC_DQBUF(video_fd, CAPTURE)
```
The waits/signals from `vk_queue_submit` need to map to syncobj waits before we VIDIOC_QBUF, and a syncobj signal after the POLL completes. For Phase 1 (a single submit with no other GPU work in the queue), we can ignore semaphores and just use a syncobj that signals on DQBUF completion.
`vk_queue_init` (`panvk_vX_gpu_queue.c:348`) is the entry point; we'd reuse the same pattern for `create_video_decode_queue`. Allocate a `struct panvk_video_decode_queue { struct vk_queue vk; int video_fd; int media_fd; ... }` and stash the fds.
---
## C. Session object lifecycle (`VkVideoSessionKHR`)
### C.1 What CreateVideoSession allocates
Anv reference at `src/intel/vulkan/anv_video.c:31-55`:
```c
struct anv_video_session *vid = vk_alloc2(...);
memset(vid, 0, sizeof(*vid));
VkResult result = vk_video_session_init(&device->vk, &vid->vk, pCreateInfo);
*pVideoSession = anv_video_session_to_handle(vid);
```
That's it. The heavy lifting is in `vk_video_session_init` (`src/vulkan/runtime/vk_video.c:33-128`), which fills:
- `vid->op` (`VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR` etc.)
- `vid->max_coded`, `picture_format`, `ref_format`, `max_dpb_slots`, `max_active_ref_pics`
- `vid->h264.profile_idc` from the `VkVideoDecodeH264ProfileInfoKHR` pNext (lines 51-57)
The driver-specific anv_video_session struct (`anv_private.h:6688-6727`) adds backend-specific per-stream state: `cdf_initialized` (for AV1), `vid_mem[ANV_VID_MEM_AV1_MAX]` (private memory bindings for codec scratch).
### C.2 Memory binding via vkBindVideoSessionMemoryKHR
Anv reference at `anv_video.c:914-998` for `GetVideoSessionMemoryRequirements` and `anv_video.c:972-1000` for `BindVideoSessionMemory`. The mem_idx enums for H.264 (`anv_private.h:6588-6593`):
```c
enum anv_vid_mem_h264_types {
ANV_VID_MEM_H264_INTRA_ROW_STORE,
ANV_VID_MEM_H264_DEBLOCK_FILTER_ROW_STORE,
ANV_VID_MEM_H264_BSD_MPC_ROW_SCRATCH,
ANV_VID_MEM_H264_MPR_ROW_SCRATCH,
ANV_VID_MEM_H264_MAX,
};
```
These are scratch buffers the Intel HCP/MFX engines need. The sizes are computed in `get_h264_video_mem_size` (`anv_video.c:483-501`) as multiples of width-in-MBs.
`BindVideoSessionMemory` (anv lines 972-998) is just bookkeeping: it copies each `VkBindVideoSessionMemoryInfoKHR` into `vid->vid_mem[bind_index]` (struct `anv_vid_mem { anv_device_memory *mem; offset; size; }` at `anv_private.h:6572-6576`).
### C.3 For our V4L2 backend
**Massive simplification opportunity**: the Hantro VPU does NOT require driver-allocated scratch buffers — all scratch is internal to the VPU and managed by the kernel driver. So `GetVideoSessionMemoryRequirements` can return **zero entries** (`*pVideoSessionMemoryRequirementsCount = 0`), and `BindVideoSessionMemory` becomes a no-op (just `return VK_SUCCESS;`).
What CreateVideoSession DOES need to allocate, V4L2-side:
1. **Open `/dev/video1` and `/dev/media0`** if not already held by the device (see J.1 for ownership decision).
2. **VIDIOC_S_FMT** on the OUTPUT queue: `V4L2_PIX_FMT_H264_SLICE` (note: hantro is slice-stateless), based on `vid->h264.profile_idc` and `vid->max_coded`. See libva-v4l2-request-fourier `src/h264.c:699-738` for the control-set pattern.
3. **VIDIOC_S_FMT** on the CAPTURE queue: `V4L2_PIX_FMT_NV12`, dimensions from `vid->max_coded`.
4. **Allocate request_fd pool**: pre-allocate N request fds (one per DPB slot + outstanding submits) via `MEDIA_IOC_REQUEST_ALLOC` ioctls (media.c:41).
5. **VIDIOC_REQBUFS** on OUTPUT + CAPTURE queues to set up buffer count.
So `panvk_video_session` struct shape:
```c
struct panvk_video_session {
struct vk_video_session vk; /* shared base */
int video_fd; /* may share with physical_device */
int media_fd; /* may share with physical_device */
/* per-session V4L2 state */
uint32_t bitstream_buffer_count;
uint32_t capture_buffer_count;
struct {
int request_fd;
bool in_use;
uint32_t dpb_slot;
} request_pool[MAX_OUTSTANDING_DECODES];
};
```
### C.4 Anv session creation shape — full reference
```c
VkResult anv_CreateVideoSessionKHR(VkDevice _device,
const VkVideoSessionCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkVideoSessionKHR *pVideoSession)
/* anv_video.c:31-55 */
{
ANV_FROM_HANDLE(anv_device, device, _device);
struct anv_video_session *vid = vk_alloc2(..., sizeof(*vid), 8, OBJECT);
if (!vid) return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
memset(vid, 0, sizeof(*vid));
VkResult result = vk_video_session_init(&device->vk, &vid->vk, pCreateInfo);
if (result != VK_SUCCESS) { vk_free2(..., vid); return result; }
*pVideoSession = anv_video_session_to_handle(vid);
return VK_SUCCESS;
}
```
For us, the body grows by ~15-30 lines for V4L2 setup (open fds, S_FMT, REQBUFS, request_fd pool init) and adds error-rollback paths.
---
## D. Parameters object lifecycle (`VkVideoSessionParametersKHR`)
### D.1 The shared layer does almost everything
`src/vulkan/runtime/vk_video.c:845-885` defines:
- `vk_common_CreateVideoSessionParametersKHR` (line 846-862)
- `vk_common_UpdateVideoSessionParametersKHR` (line 865-872)
- `vk_common_DestroyVideoSessionParametersKHR` (line 875-885)
These delegate to:
- `vk_video_session_parameters_create` (helper at `vk_video.c:480` — alloc + dispatch by codec op)
- `vk_video_session_parameters_update` (line 793-844 — switches on `params->op` and calls `update_h264_dec_session_parameters` at line 692 which does the actual SPS/PPS array merge with seq_parameter_set_id collision detection per the spec)
- `vk_video_session_parameters_destroy`
**Key question**: do panvk-bifrost entrypoints get auto-wired to the `vk_common_*` versions, or does the driver need to opt in?
Mesa's entrypoint generator (`vk_entrypoints_gen.py`) wires shared-helper entrypoints **by default** unless the driver provides a stronger symbol. So if panvk does NOT define `panvk_CreateVideoSessionParametersKHR`, the linker falls through to `vk_common_CreateVideoSessionParametersKHR`. Confirmed by anv comparison: anv has no `anv_CreateVideoSessionParametersKHR`, only `anv_UpdateVideoSessionParametersKHR` is missing too — both come from `vk_common_*`.
radv DOES override (`radv_video.c:630-647`) but only to call `radv_video_patch_session_parameters` for an AMD-specific fixup. For Phase 1 we don't need that.
**Decision: rely entirely on vk_common.** Zero driver code for parameters object lifecycle.
### D.2 Parameters → V4L2 control conversion happens at CmdDecodeVideo time, not at parameter creation
The shared parameters struct (`vk_video.h:127-195`) for H.264-decode stores SPS array of `struct vk_video_h264_sps` (which embeds `StdVideoH264SequenceParameterSet base`) and PPS array of `struct vk_video_h264_pps` (which embeds `StdVideoH264PictureParameterSet base`). The lookup helpers `vk_video_find_h264_dec_std_sps(params, id)` and `vk_video_find_h264_dec_std_pps(params, id)` (`vk_video.c:1186-1198`) are what we call at decode time to get the SPS/PPS for the current frame.
The V4L2-side bridge from `StdVideoH264SequenceParameterSet``struct v4l2_ctrl_h264_sps` is the same conversion fourier does. See `libva-v4l2-request-fourier/src/h264.c:360` for `h264_va_picture_to_v4l2` which marshals to `struct v4l2_ctrl_h264_decode_params`, `v4l2_ctrl_h264_pps`, `v4l2_ctrl_h264_sps` — except the source format on our side is `StdVideoH264*` instead of `VAPictureParameterBufferH264`. The field-name mapping is essentially identical because both `VAPictureParameterBufferH264` and `StdVideoH264SequenceParameterSet` ultimately derive from the H.264 spec's syntax element names.
**We will write `panvk_h264_std_sps_to_v4l2(const StdVideoH264SequenceParameterSet *std, struct v4l2_ctrl_h264_sps *out)` etc.** as a new helper file (~150 lines per codec). This is the bridge function that has no Mesa precedent — it's our novel contribution.
### D.3 Hooking the parameters cache to ext-control structs at decode time
At `CmdDecodeVideoKHR` recording time, we retrieve the relevant `StdVideoH264SequenceParameterSet *` and `StdVideoH264PictureParameterSet *` via `vk_video_get_h264_parameters` (`vk_video.h:419-425`). The signature:
```c
void vk_video_get_h264_parameters(const struct vk_video_session *session,
const struct vk_video_session_parameters *params,
const VkVideoDecodeInfoKHR *decode_info,
const VkVideoDecodeH264PictureInfoKHR *h264_pic_info,
const StdVideoH264SequenceParameterSet **sps_p,
const StdVideoH264PictureParameterSet **pps_p);
```
Anv uses this at `genX_cmd_video.c:904` in `anv_h264_decode_video`. We do the same.
---
## E. vkCmdDecodeVideoKHR command recording
### E.1 What anv emits at record time vs submit time
**Crucial finding**: anv does ALL work at record time. By the time the cmdbuf goes to the queue, the command stream is fully baked. Look at `anv_h264_decode_video` (`genX_cmd_video.c:892-1300+`): every `anv_batch_emit(&cmd_buffer->batch, GENX(MFX_PIPE_MODE_SELECT), sel)` etc. is a register/packet write into the cmd_buffer's batch buffer. Submit time just kicks the batch.
The Begin/End wrappers are thin:
- `CmdBeginVideoCodingKHR` (`genX_cmd_video.c:31-50`): stashes `cmd_buffer->video.vid = vid; cmd_buffer->video.params = params;` into command-buffer-local state. **That's it** for H.264 (AV1 adds CDF table init).
- `CmdControlVideoCodingKHR` (`genX_cmd_video.c:52-74`): if RESET flag, emit `MI_FLUSH_DW` with `VideoPipelineCacheInvalidate = 1`.
- `CmdEndVideoCodingKHR` (`genX_cmd_video.c:76-83`): clears `cmd_buffer->video.vid = NULL; cmd_buffer->video.params = NULL;`.
The `cmd_buffer->video` shadow state (`anv_private.h:4935-4938`):
```c
struct {
struct anv_video_session *vid;
struct vk_video_session_parameters *params;
} video;
```
### E.2 For our V4L2 backend — "deferred record"
The V4L2 ioctls cannot meaningfully happen at record time, because:
1. The bitstream buffer (frame_info->srcBuffer) is a `VkBuffer` we don't necessarily know the contents of yet (might be filled by a prior submitted cmdbuf or by host writes between record and submit).
2. Request_fd allocation and S_EXT_CTRLS need to be sequential per submit (cannot pre-bind a request_fd to a recorded cmdbuf and reuse it).
**Pattern: per-cmdbuf list of "video decode ops" recorded during CmdDecodeVideoKHR.** The op captures everything we need to replay at submit time:
```c
struct panvk_video_decode_op {
/* From CmdBegin */
struct panvk_video_session *session;
struct vk_video_session_parameters *params;
/* From CmdDecode */
VkBuffer src_buffer; /* bitstream source */
VkDeviceSize src_offset;
VkDeviceSize src_size;
/* DPB target */
struct panvk_image_view *dst_iv;
uint32_t dst_dpb_slot;
/* Already-resolved SPS/PPS pointers (cheap copy by value) */
StdVideoH264SequenceParameterSet sps;
StdVideoH264PictureParameterSet pps;
/* H.264 slice info, picked apart at submit time */
StdVideoDecodeH264PictureInfo std_pic_info;
/* Reference slot info — small array, copy by value */
uint32_t reference_slot_count;
struct panvk_video_ref_slot reference_slots[16];
};
struct panvk_cmd_buffer {
...
struct util_dynarray video_decode_ops; /* of struct panvk_video_decode_op */
};
```
Then submit-time (per B.4) walks the dynarray and does the ioctl dance per op.
Comparable record-time op-list pattern exists today for sparse binds (`panvk_sparse.c`). Anv stores per-cmdbuf state in `cmd_buffer->video` but doesn't queue up ops because it emits direct register packets. We're doing what anv would do if anv ran on a separate kernel device.
### E.3 CmdBegin/Control/End for our backend
- `panvk_per_arch(CmdBeginVideoCodingKHR)`: clear `cmd_buffer->video_decode_session = vid; cmd_buffer->video_decode_params = params;`. Optionally validate the reference slot layout matches the dpb_slot count we set up at session init.
- `panvk_per_arch(CmdControlVideoCodingKHR)` for `VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR`: this needs to translate to `MEDIA_REQUEST_IOC_REINIT` on all pooled request_fds — OR just mark a session-wide flag "next decode needs fresh request setup". Phase 1 we can no-op this if we always reinit per submit anyway.
- `panvk_per_arch(CmdEndVideoCodingKHR)`: clear shadow state. No emission needed.
---
## F. DPB management
### F.1 Vulkan-side DPB model
Per-frame `VkCmdDecodeVideoKHR` receives:
- `frame_info->dstPictureResource``VkVideoPictureResourceInfoKHR { codedOffset, codedExtent, baseArrayLayer, imageViewBinding }`. The image view that will receive the decoded output.
- `frame_info->pSetupReferenceSlot``VkVideoReferenceSlotInfoKHR { slotIndex, pPictureResource }`. Says "this decoded frame becomes DPB slot N".
- `frame_info->pReferenceSlots[]` — references TO read from. Each carries `slotIndex` + `pPictureResource`.
For H.264, additionally:
- `pNext` chain `VkVideoDecodeH264PictureInfoKHR { pStdPictureInfo, sliceCount, pSliceOffsets }`
- DPB slot pNext per reference: `VkVideoDecodeH264DpbSlotInfoKHR { pStdReferenceInfo }` — contains POC/short-term/long-term flags.
Anv's reference assembly logic at `genX_cmd_video.c:992-1004`:
```c
for (unsigned i = 0; i < frame_info->referenceSlotCount; i++) {
const struct anv_image_view *ref_iv = anv_image_view_from_handle(
frame_info->pReferenceSlots[i].pPictureResource->imageViewBinding);
int idx = frame_info->pReferenceSlots[i].slotIndex;
...
dpb_slots[idx] = i;
buf.ReferencePictureAddress[i] = anv_image_dpb_address(ref_iv, baseArrayLayer);
}
```
### F.2 V4L2 DPB model
`v4l2_ctrl_h264_decode_params::dpb[16]` is an array of `struct v4l2_h264_dpb_entry { reference_ts, pic_num, frame_num, fields, flags, top_field_order_cnt, bottom_field_order_cnt }`. Each entry's `reference_ts` is the timestamp used at VIDIOC_QBUF of the OUTPUT (bitstream) plane when that reference was decoded — V4L2 uses this as the "buffer identity" key.
So the mapping rule from Vulkan-side `VkVideoReferenceSlotInfoKHR[]` to V4L2-side `dpb[16]` is:
| Vulkan field | V4L2 dpb field | How to source |
|---|---|---|
| `pReferenceSlots[i].slotIndex` | array index in `dpb[]` | direct (assert `<= 16`) |
| `pReferenceSlots[i].pNext->pStdReferenceInfo->PicOrderCnt[0]` | `top_field_order_cnt` | direct |
| `pReferenceSlots[i].pNext->pStdReferenceInfo->PicOrderCnt[1]` | `bottom_field_order_cnt` | direct |
| `pReferenceSlots[i].pNext->pStdReferenceInfo->FrameNum` | `frame_num` | direct |
| short-term/long-term flag | `flags` | direct |
| (the decoded output VkImage backing the ref slot) | `reference_ts` | **lookup**: we maintain a `slotIndex → reference_ts` map per-session, populated each time we decode into that slot. See libva-fourier `src/h264.c:140-218` for `dpb_insert`/`dpb_update`/`dpb_find_entry`. Our case is simpler: slotIndex is provided by Vulkan, we just need to track "what ts did I QBUF when I last decoded into slotIndex N". |
The fourier `src/h264.c:238-353` `h264_fill_dpb` function is the closest analog — it constructs `struct v4l2_h264_dpb_entry[]` from libva-side state. We do the analog but feed it from `pReferenceSlots[]`.
### F.3 Bookkeeping struct in panvk_video_session
```c
struct panvk_video_session {
...
struct {
uint64_t reference_ts; /* timestamp last used when decoding into this slot */
struct panvk_image *image; /* the VkImage backing this slot's DPB */
uint32_t array_layer;
bool active;
} dpb[16];
};
```
Update at decode-completion time (after VIDIOC_DQBUF) for the setup-reference-slot.
---
## G. Memory + dmabuf interop
### G.1 The challenge
App creates a `VkImage` with `VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR | VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR | VK_IMAGE_USAGE_SAMPLED_BIT`. Memory is bound via normal `vkBindImageMemory`. Then the decoded frame data needs to physically end up in that memory backing.
Hantro's CAPTURE queue allocates its own buffers via `VIDIOC_REQBUFS(memory=V4L2_MEMORY_MMAP)` or accepts dma_buf imports via `VIDIOC_REQBUFS(memory=V4L2_MEMORY_DMABUF)`. The clean path: **app's VkImage memory backing IS a dma_buf**, exported from panvk via `vkGetMemoryFdKHR`, and we VIDIOC_QBUF'd with the dma_buf fd as the CAPTURE plane.
But Vulkan apps don't usually export memory back to themselves. They expect `vkCreateImage(usage=VIDEO_DECODE_DST)` to "just work". So **we** drive the dma_buf flow internally.
### G.2 Internal dma_buf flow (proposed)
Two strategies:
**Strategy A: Driver-allocated CAPTURE buffers, app-imported into VkImage**
- VIDIOC_REQBUFS(MMAP) at session create.
- VIDIOC_EXPBUF to get a dma_buf fd per allocated buffer.
- Import the dma_buf back into pan_kmod as a VkDeviceMemory equivalent.
- VkBindImageMemory to that DeviceMemory.
**Strategy B: App-allocated VkImage, V4L2_MEMORY_DMABUF queue**
- App calls vkCreateImage with VkExternalMemoryImageCreateInfo handleTypes=DMA_BUF.
- Vk allocates the BO via pan_kmod, exports a dma_buf fd via `pan_kmod_bo_export` (`panvk_device_memory.c:387-404`).
- VIDIOC_QBUF(memory=V4L2_MEMORY_DMABUF, fd=our_dmabuf_fd) at submit time.
**Strategy B is what fourier does for surface buffers, and it's the cleaner fit** — the app gets a real VkImage with real VkDeviceMemory, we never have to fake the import direction. Phase 1 may want to start with Strategy A for simplicity since vk-video-samples likely doesn't pass `VkExternalMemoryImageCreateInfo` flags, but Strategy B is the long-term right answer.
### G.3 Anv's DPB image allocation
Anv treats DPB images as plain VkImages — no special allocation. The HW reads them directly via `anv_image_dpb_address(iv, baseArrayLayer)` at `genX_cmd_video.c:933`. Memory layout is whatever ISL gives them (tile-Y or planar-420). For our backend, that doesn't transfer — the Hantro VPU expects NV12 in a linear layout (or a vendor-specific tiled layout that we'd need to expose; for Phase 1 we mandate linear).
### G.4 panvk dmabuf entry points (already present)
- `panvk_AllocateMemory` handles `VkImportMemoryFdInfoKHR` at `panvk_device_memory.c:121-135` — calls `pan_kmod_bo_import`.
- `panvk_GetMemoryFdKHR` at `panvk_device_memory.c:387-404` exports.
- `EXT_external_memory_dma_buf` already advertised at `panvk_vX_physical_device.c:146`.
So the building blocks exist. The new code is the **session-internal V4L2 buffer pool** that converts between V4L2_MEMORY_MMAP/DMABUF and pan_kmod BOs.
---
## H. vk_video runtime helper coverage matrix
What we inherit vs what we write. Cross-referenced from sections AG:
| Question | Inherit from vk_video shared layer? | Driver writes? |
|---|---|---|
| A. KHR_video_* extension booleans | No | YES — `panvk_vX_physical_device.c` table |
| A. videoMaintenance1 feature struct | No | (Phase 1: skip; future: yes if advertised) |
| A. GetPhysicalDeviceVideoCapabilitiesKHR | **NO** — direct entrypoint | YES — new code in `panvk_physical_device.c` |
| A. GetPhysicalDeviceVideoFormatPropertiesKHR | **NO** — direct entrypoint | YES — new code in `panvk_physical_device.c` |
| B. Queue family enum + props | No | YES — `panvk_device.h` + `panvk_physical_device.c` |
| B. Queue-family-video pNext walk | No | YES — extend `panvk_GetPhysicalDeviceQueueFamilyProperties2` |
| B. Queue create/destroy dispatch | No | YES — extend `panvk_vX_device.c:305-329` |
| B. Queue submit | No | YES — new `panvk_vX_video_decode_queue.c` |
| C. CreateVideoSessionKHR — handle + base init | YES partial: `vk_video_session_init` does the codec-op parsing | YES — driver wraps, adds V4L2 fd open + S_FMT + REQBUFS |
| C. DestroyVideoSessionKHR — base finish | YES partial: `vk_video_session_finish` | YES — driver wraps, adds V4L2 teardown |
| C. GetVideoSessionMemoryRequirementsKHR | No | YES (trivial: zero entries) |
| C. BindVideoSessionMemoryKHR | No | YES (trivial: no-op) |
| D. CreateVideoSessionParametersKHR | **YES — `vk_common_CreateVideoSessionParametersKHR` (vk_video.c:846)** | NO driver code needed |
| D. UpdateVideoSessionParametersKHR | **YES — `vk_common_UpdateVideoSessionParametersKHR` (vk_video.c:865)** | NO driver code needed |
| D. DestroyVideoSessionParametersKHR | **YES — `vk_common_DestroyVideoSessionParametersKHR` (vk_video.c:875)** | NO driver code needed |
| D. H.264 SPS/PPS storage | **YES — `struct vk_video_h264_{sps,pps}` (vk_video.h:32-43)** | NO |
| D. H.264 SPS/PPS lookup | **YES — `vk_video_find_h264_dec_std_{sps,pps}` (vk_video.c:1186)** | NO |
| D. H.264 params merge with dedup | **YES — internal to `vk_video_session_parameters_update`** | NO |
| D. Std → V4L2 control marshalling | No precedent in Mesa | YES — NEW helper file (~300 lines for H.264) |
| E. CmdBeginVideoCodingKHR | No | YES — trivial state-stash |
| E. CmdControlVideoCodingKHR | No | YES — trivial RESET handling |
| E. CmdEndVideoCodingKHR | No | YES — trivial state-clear |
| E. CmdDecodeVideoKHR | No | YES — record op into cmdbuf dynarray |
| E. `vk_video_get_h264_parameters` resolver | **YES (vk_video.h:419)** | NO |
| F. DPB slot ↔ reference_ts map | No | YES — `panvk_video_session.dpb[16]` |
| F. H.264 reference list construction | Partially: `vk_fill_video_h264_*` helpers if present | YES — but mostly direct field copies |
| G. dmabuf BO import/export | YES — existing panvk path (`panvk_device_memory.c:121,387`) | NO new code |
| G. V4L2 buffer ↔ pan_kmod_bo bridging | No precedent | YES — NEW helper file |
| G. Image creation for VIDEO_DECODE_DST | YES — existing `panvk_image_init` (panvk_image.c:562) handles all usage flags through ISL | Possibly yes for tile mode restrictions |
**Net leverage**: ~3000 lines of vk_video runtime helpers we inherit for free, primarily the H.264 SPS/PPS bitstream parsing + parameters object lifecycle + std/find helpers. Our new-code estimate is roughly 800-1500 lines split across ~4 new files (see I).
---
## I. panvk-specific integration points (concrete edits)
### I.1 Existing files to modify
**`src/panfrost/vulkan/panvk_vX_physical_device.c`**:
- Lines ~123-124 (between `KHR_vertex_attribute_divisor` and `KHR_vulkan_memory_model`): add `.KHR_video_queue = true,`, `.KHR_video_decode_queue = true,`, `.KHR_video_decode_h264 = true,` (gated on hantro probe).
- Optional Phase 2+: at line 540, flip `unifiedImageLayoutsVideo` based on session config.
**`src/panfrost/vulkan/panvk_physical_device.c`**:
- Line ~565: extend the `qfamily_props[]` array — add a third entry for `PANVK_QUEUE_FAMILY_VIDEO_DECODE` with `queueFlags = VK_QUEUE_VIDEO_DECODE_BIT_KHR | VK_QUEUE_TRANSFER_BIT`.
- Around line 589 inside the `vk_outarray_append_typed` loop: add a pNext walk for `VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR` that sets `videoCodecOperations = VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR`.
- ADD new entrypoints `panvk_GetPhysicalDeviceVideoCapabilitiesKHR` and `panvk_GetPhysicalDeviceVideoFormatPropertiesKHR` at end of file (~70 lines + ~50 lines).
**`src/panfrost/vulkan/panvk_device.h`**:
- Line 46-48: add `PANVK_QUEUE_FAMILY_VIDEO_DECODE,` to the enum.
**`src/panfrost/vulkan/panvk_vX_device.c`**:
- Lines 218-247 (`check_global_priority`): add `case PANVK_QUEUE_FAMILY_VIDEO_DECODE: return VK_SUCCESS;`.
- Lines 253-258 (`panvk_queue_check_status`): add case for the new family calling `panvk_per_arch(video_decode_queue_check_status)`.
- Lines 305-313 (`panvk_queue_create`): add case calling `panvk_per_arch(create_video_decode_queue)`.
- Lines 320-329 (`panvk_queue_destroy`): symmetric.
**`src/panfrost/vulkan/meson.build`**:
- Add new files to either `libpanvk_files` (arch-agnostic) or `common_per_arch_files` (arch-templated). The session/queue/command-record code is arch-agnostic but uses `panvk_per_arch()` symbols only by convention — Phase 1 we can place all new files in `libpanvk_files` and skip the per_arch dispatch.
### I.2 New files to add
**`src/panfrost/vulkan/panvk_video_decode.c`** (~400 lines):
- `panvk_CreateVideoSessionKHR`
- `panvk_DestroyVideoSessionKHR`
- `panvk_GetVideoSessionMemoryRequirementsKHR` (returns count=0)
- `panvk_BindVideoSessionMemoryKHR` (no-op)
- `panvk_CmdBeginVideoCodingKHR`
- `panvk_CmdControlVideoCodingKHR`
- `panvk_CmdEndVideoCodingKHR`
- `panvk_CmdDecodeVideoKHR` (record op into `cmd_buffer->video_decode_ops`)
**`src/panfrost/vulkan/panvk_video_decode.h`**:
- `struct panvk_video_session`
- `struct panvk_video_decode_op`
- `struct panvk_video_decode_queue`
**`src/panfrost/vulkan/panvk_v4l2.c`** (~500 lines):
- `panvk_v4l2_probe_hantro()` — finds /dev/video1 and /dev/media0 (mirrors libva-v4l2-request-fourier `src/request.c:143-308` `find_decoder_video_node_via_topology`).
- `panvk_v4l2_session_init()` — S_FMT on OUTPUT/CAPTURE, REQBUFS, request_fd pool alloc.
- `panvk_v4l2_h264_std_to_ctrl_sps()``StdVideoH264SequenceParameterSet *``struct v4l2_ctrl_h264_sps`.
- `panvk_v4l2_h264_std_to_ctrl_pps()``StdVideoH264PictureParameterSet *``struct v4l2_ctrl_h264_pps`.
- `panvk_v4l2_h264_fill_decode_params()` — build `struct v4l2_ctrl_h264_decode_params` from VkVideoDecodeInfoKHR + slot map.
- `panvk_v4l2_submit_op()` — the request_fd / S_EXT_CTRLS / QBUF / poll / DQBUF dance for one op.
**`src/panfrost/vulkan/panvk_vX_video_decode_queue.c`** (~150 lines, per_arch):
- `panvk_per_arch(create_video_decode_queue)`
- `panvk_per_arch(destroy_video_decode_queue)`
- `panvk_per_arch(video_decode_queue_submit)` — walks cmdbuf ops, calls `panvk_v4l2_submit_op` per op.
- `panvk_per_arch(video_decode_queue_check_status)`
### I.3 Entrypoint generation
Recall from `meson.build:7-19` that entrypoints are auto-wired with `--prefix panvk` and per-arch prefixes. The names above (`panvk_CmdDecodeVideoKHR` etc.) match the auto-resolution rules — no changes needed in `vk_entrypoints_gen` invocation.
For the per-arch ones (`panvk_per_arch(...)`), we expand under each `PAN_ARCH` define just like existing per-arch code.
---
## J. Probable architecture sketch
**V4L2 fd ownership**: at `panvk_physical_device` level for probe-time discovery (`panvk_v4l2_probe_hantro` sets `phys_dev->v4l2.video_fd_present = true` and stashes paths), but actual `open()` happens at `panvk_CreateVideoSessionKHR` time per-session. Two reasons: (1) the V4L2 driver state is per-fd, so two concurrent sessions need two separate fds anyway; (2) keeping fds closed when no video session is active is good citizenship. The PhysicalDevice only holds device-node paths and capability flags.
**Per-session V4L2 state**: `struct panvk_video_session` (see C.3) owns one `video_fd` + one `media_fd` + a pool of `request_fd`s (one per max-in-flight decode, typically `max_dpb_slots + 2`). At `CreateVideoSession` we S_FMT both queues, REQBUFS to allocate the buffer count, EXPBUF the CAPTURE buffers to dma_bufs that get held in the session for later association with VkImage memory (Strategy B from G.2).
**Per-VkImage dmabuf bookkeeping**: the existing pan_kmod export path (`panvk_device_memory.c:387-404`) gives us dma_buf out. The new piece is the inverse — at `vkBindImageMemory` time for a `VkImage` whose `usage & VIDEO_DECODE_DST`, we'd register the underlying BO's dma_buf as a CAPTURE buffer with `VIDIOC_QBUF(memory=V4L2_MEMORY_DMABUF)`. The image's `panvk_image` struct gains a `int v4l2_capture_index;` field.
**Submit-time dispatch**: at `panvk_vX_device.c:305-313` we extended the switch to route `PANVK_QUEUE_FAMILY_VIDEO_DECODE` to `panvk_per_arch(create_video_decode_queue)` whose `driver_submit = panvk_per_arch(video_decode_queue_submit)`. The submit function walks each cmdbuf's `video_decode_ops` dynarray, and per op:
```
1. resolve request_fd from session pool (allocate or reuse, ioctl(media_fd, MEDIA_IOC_REQUEST_ALLOC))
2. media_request_reinit(request_fd) if reusing
3. translate op->sps to v4l2_ctrl_h264_sps via panvk_v4l2_h264_std_to_ctrl_sps()
4. translate op->pps to v4l2_ctrl_h264_pps via panvk_v4l2_h264_std_to_ctrl_pps()
5. build v4l2_ctrl_h264_decode_params from op (including dpb[] from session->dpb[] tracking)
6. VIDIOC_S_EXT_CTRLS(video_fd, request_fd=op->request_fd, {SPS, PPS, DECODE_PARAMS, SCALING_MATRIX, SLICE_PARAMS})
7. VIDIOC_QBUF(video_fd, OUTPUT, request_fd=op->request_fd, bytesused=op->src_size, m.fd=op->src_buffer's bo dma_buf)
8. VIDIOC_QBUF(video_fd, CAPTURE, index=op->dst_iv->image->v4l2_capture_index)
9. MEDIA_REQUEST_IOC_QUEUE(request_fd)
10. poll(request_fd, POLLPRI, timeout)
11. VIDIOC_DQBUF(video_fd, OUTPUT) /* releases input slot */
12. VIDIOC_DQBUF(video_fd, CAPTURE) /* output ready */
13. Update session->dpb[op->dst_dpb_slot].reference_ts to the QBUF timestamp
14. Signal vk_queue_submit's signal semaphores
```
Steps 5-12 are exactly the libva-v4l2-request-fourier `RequestEndPicture` body (`src/picture.c:497-650`). The mapping VAPicture* → V4L2 vs Std* → V4L2 is the one piece of code that has no Mesa precedent — we're inventing the bridge — but it's bounded: ~150 lines per codec (we only need H.264 in Phase 1).
---
## Mesa-version observations and risks
- Mesa 26.0.6 is the campaign baseline. The vk_video runtime helpers in `src/vulkan/runtime/vk_video.{c,h}` are stable in this version with H.264, H.265, AV1, VP9, encode-h264, encode-h265, encode-av1 all covered. No upgrade required for Phase 1.
- `KHR_video_decode_h264` spec v9 is what's in `vk_api.xml` for 26.0.6 — confirmed by extension being already known to entrypoint generator (no `--beta` flag needed; that flag at `meson.build:18` is for beta/provisional extensions only).
- Maintenance1/2 features are NOT required for the simple-test in Phase 1, so we don't need `videoMaintenance1` / `videoMaintenance2` machinery yet. Maintenance1 (inline parameters, inline queries) becomes relevant in Phase 6+ if we want to pass conformance suites.
- The `unifiedImageLayoutsVideo` feature at `panvk_vX_physical_device.c:540` is currently false. Phase 1 we can leave it false — the test client honors explicit `VkImageMemoryBarrier` transitions to/from `VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR`.
---
## Architectural maps that DO cleanly transfer from anv/radv
1. **Session as wrapper around `vk_video_session`**. Anv: `struct anv_video_session { struct vk_video_session vk; ... }`. radv: same shape. Ours: same shape. The `vk.` namespace gives us all the spec-mandated session fields for free.
2. **Parameters fully delegated to `vk_common_*`**. Anv does this, radv mostly does this (with a tiny `radv_video_patch_session_parameters` patch). Ours: full delegation.
3. **Cmdbuf-local shadow state for current session+params during the Begin..End scope**. Anv: `cmd_buffer->video.{vid,params}`. We do the same.
4. **DPB slot index ↔ image view lookup at decode time**. Both anv and our backend do this lookup per frame.
## Architectural maps that DO NOT transfer
1. **Driver-allocated session scratch memory (`anv_vid_mem` array)**. Hantro VPU keeps scratch internal; we return zero memory requirements. Hard skip — not just simplification, an inversion.
2. **`anv_batch_emit` register packets directly into cmdbuf at record time**. There is no equivalent. We MUST defer to submit-time — that's the entire point of the V4L2 backend being on a separate kernel device.
3. **`anv_image_dpb_address(iv, layer)` resolving to a GPU virtual address**. Our DPB references resolve to V4L2 buffer indices (queued at session-init) or dma_buf fds (Strategy B). The "address" abstraction doesn't apply; the VPU doesn't share the GPU's address space.
4. **MFX/HCP/VDENC register-set knowledge in `genX_cmd_video.c`** — 4000+ lines of Intel-specific HW programming. Completely irrelevant. The Hantro VPU's "programming" is a sequence of struct `v4l2_ctrl_*` fills + ioctls.
5. **MOCS / cache state in pipe-buf-addr-state** (`genX_cmd_video.c:962+`). N/A — the kernel V4L2 driver handles all cache coherency at QBUF/DQBUF boundaries.
---
## Phase 1 success criteria — final checklist
| vk-video-samples simple-test step | Where it lands in this map |
|---|---|
| `vkGetPhysicalDeviceQueueFamilyProperties2` returns family with `VK_QUEUE_VIDEO_DECODE_BIT_KHR` and `VkQueueFamilyVideoPropertiesKHR::videoCodecOperations & VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR` set | B.2 |
| `vkEnumerateDeviceExtensionProperties` returns the three KHR_video_* | A.1 |
| `vkGetPhysicalDeviceVideoCapabilitiesKHR(profile=H264)` returns sane caps | A.3 |
| `vkGetPhysicalDeviceVideoFormatPropertiesKHR` returns NV12 | A.4 |
| `vkCreateDevice` succeeds with the video queue family selected | B.3 |
| `vkCreateVideoSessionKHR` succeeds | C |
| `vkGetVideoSessionMemoryRequirementsKHR` returns 0 entries | C.3 |
| `vkCreateVideoSessionParametersKHR` with SPS+PPS succeeds | D (free from vk_common) |
| Recording a `vkCmdDecodeVideoKHR` succeeds (no execution yet — could even no-op the V4L2 ioctls in Phase 1 since correctness isn't tested) | E.2 |
| Single queue submit succeeds without VK_ERROR_DEVICE_LOST | B.4, J |
Phase 1 deliberately stops short of "decoded picture compares against reference". That's Phase 7. Phase 1 is the end-to-end plumbing.
+222
View File
@@ -0,0 +1,222 @@
# Phase 2 — design lock for panvk-bifrost-video
Phase 1 source-map (`phase1_source_map.md`) acquired the architecture. This document locks the implementation-level decisions that bind Phase 4. Where Phase 1 listed options, this picks one.
## Re-anchored constraints (re-verified 2026-05-21)
- ohm reachable, kernel `linux-fresnel-fourier` with `dma_resv` patches
- `/dev/video1` (hantro decoder) + `/dev/media0` (media controller) present
- libva-v4l2-request-fourier installed and exercising the same V4L2 path — proves the protocol works (1.56× / 1.73× realtime). **Coexistence policy: env-mutex (Phase 0 Q1 lock A).** Only one client holds `/dev/video1` at a time; user picks via `LIBVA_DRIVER_NAME=null` or service-level coordination.
- `mesa-panvk-bifrost` r4 source on ohm at `/home/mfritsche/mesa-build/mesa-26.0.6/`. Reuses the same r1r4 patch lineage in PKGBUILD; new package `mesa-panvk-bifrost-video` is a sibling — see Phase 0 [[campaign-close-via-pkgbuild]].
- Vulkan headers: 26.0.6's bundled `vk.xml` has H.264 decode v9 stable. No `--beta` flag needed.
- Test bitstream: `/home/mfritsche/fourier-test/bbb_1080p30_h264.mp4` (725 MB H.264 Main, 1080p30) — proven decoding via libva path 2026-05-21.
- vk-video-samples builds on aarch64 (Phase 0). simple-test binary at `~/panvk-bifrost-video-evidence/Vulkan-Video-Samples/build/vk_video_decoder/test/vulkan-video-dec-simple-test`.
## Locked decisions
### D1 — V4L2 device ownership: per-`VkVideoSessionKHR`, not per-`VkDevice`
Each call to `vkCreateVideoSessionKHR` opens its own `video_fd` to `/dev/video1` and `media_fd` to `/dev/media0`. The PhysicalDevice only holds discovery state (paths + caps flags). Per Phase 1 §J reasoning: kernel V4L2 state is per-fd, multiple sessions need separate fds anyway, idle-when-no-session is good citizenship.
Trade-off rejected: per-device shared fd. Would force a session-arbitration daemon inside panvk. Not worth it for Phase 1; not needed for the simple-test workload (single session).
### D2 — File layout (committed)
New files in `src/panfrost/vulkan/`:
| File | Purpose | Est. LoC |
|---|---|---|
| `panvk_video_decode.c` | VkVideoSession* + VkCmd*VideoCoding entrypoints; record video_decode_ops dynarray | ~400 |
| `panvk_video_decode.h` | structs: `panvk_video_session`, `panvk_video_decode_op`, `panvk_video_decode_queue` | ~80 |
| `panvk_v4l2.c` | V4L2 probe + per-session init + Std*→v4l2_ctrl_h264_* bridge + submit_op() | ~500 |
| `panvk_vX_video_decode_queue.c` | per-arch queue create/destroy/submit (walks ops, calls panvk_v4l2_submit_op) | ~150 |
Modified files (locations from Phase 1 §I.1):
- `panvk_vX_physical_device.c` (extension list + capability/format entrypoints)
- `panvk_physical_device.c` (queue family list + video properties pNext walk)
- `panvk_device.h` (queue family enum)
- `panvk_vX_device.c` (queue create/destroy/submit dispatch — 4 cases)
- `meson.build` (register new sources)
### D3 — Per-session state struct (locked layout)
```c
struct panvk_video_session {
struct vk_video_session vk; /* spec-mandated fields */
/* V4L2 fds — opened in CreateVideoSession, closed in Destroy */
int video_fd; /* /dev/video1 */
int media_fd; /* /dev/media0 */
/* Negotiated formats per OUTPUT / CAPTURE queue */
struct v4l2_format fmt_output;
struct v4l2_format fmt_capture;
/* Request fd pool. Max-in-flight = max_dpb_slots + 2 */
int *request_fds;
unsigned num_request_fds;
uint32_t request_fd_next; /* round-robin index */
/* DPB slotIndex → V4L2 reference_ts mapping */
struct {
bool valid;
uint64_t reference_ts; /* V4L2 timestamp at QBUF time */
/* No image-view pointer here — image references via slotIndex
* only; resolution at record time via vk.params lookup. */
} dpb[16];
/* DECODE_PARAMS/SLICE_PARAMS submit mode (locked FRAME_BASED for Phase 1) */
bool slice_based; /* Phase 1: false */
};
```
DPB mirroring is identical to `libva-v4l2-request-fourier/src/h264.c:140-218` `dpb_insert` / `dpb_update`. Reuse the algorithm; don't link the lib — copy ~80 LoC verbatim into `panvk_v4l2.c`.
### D4 — Per-cmdbuf decode-op entry (locked layout)
```c
struct panvk_video_decode_op {
/* Captured at vkCmdDecodeVideoKHR record time */
uint32_t dst_dpb_slot; /* output slot */
struct panvk_image_view *dst_iv; /* output VkImageView */
uint32_t num_ref_slots;
struct {
uint32_t slot_index;
struct panvk_image_view *iv; /* reference VkImageView */
} ref_slots[16];
/* Bitstream buffer */
struct panvk_buffer *src_buffer;
uint64_t src_offset;
uint64_t src_size;
/* Cached params at record time (so submit can run after Parameters object updates) */
const StdVideoH264SequenceParameterSet *sps; /* from vk.params */
const StdVideoH264PictureParameterSet *pps;
VkVideoDecodeH264PictureInfoKHR pic_info; /* the per-frame info */
/* Filled at submit time */
int request_fd; /* allocated from session pool */
uint64_t qbuf_ts; /* timestamp used for dpb tracking */
};
```
Recorded as a `util_dynarray` on the command buffer. `vkResetCommandBuffer` clears it.
### D5 — Bitstream input: VkBuffer dmabuf import (one-shot)
At record time, the `VkBuffer` (with `VIDEO_DECODE_SRC_BIT_KHR` usage) carries a `panvk_priv_bo` with an exportable dmabuf. At submit time, op-submit does:
```
fd = pan_kmod_bo_export_dma_buf(src_buffer->bo)
VIDIOC_QBUF(video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT,
memory=V4L2_MEMORY_DMABUF, m.fd=fd, bytesused=op->src_size,
request_fd=op->request_fd)
```
Source-side buffers are not pinned to V4L2 OUTPUT slots — each decode gets a fresh QBUF using the dmabuf fd. After DQBUF the slot is implicitly released.
### D6 — Output frames: VkImage permanent CAPTURE slot binding (Strategy B from §G.2)
At `vkBindImageMemory` time, if the VkImage's `usage & VIDEO_DECODE_DST_BIT_KHR`, the image's underlying BO is `EXPBUF`'d and registered as a permanent CAPTURE buffer slot via `VIDIOC_QBUF(memory=DMABUF)` at session init, then the slot index is stashed in:
```c
struct panvk_image {
...
int v4l2_capture_index; /* -1 if not a video output image */
};
```
Rejected alternative: per-decode-call dmabuf import. Higher per-frame ioctl overhead. Strategy B amortizes the registration cost across the session lifetime.
### D7 — Submit-time ioctl dance (the 14 steps, locked)
```
panvk_per_arch(video_decode_queue_submit)(queue, submit):
for each cmdbuf in submit:
for each op in cmdbuf->video_decode_ops:
panvk_v4l2_submit_op(session, op):
1. resolve request_fd: pool[round_robin++ % num] or MEDIA_IOC_REQUEST_ALLOC
2. ioctl(request_fd, MEDIA_REQUEST_IOC_REINIT)
3. fill v4l2_ctrl_h264_sps from op->sps via panvk_v4l2_h264_std_to_ctrl_sps()
4. fill v4l2_ctrl_h264_pps from op->pps via panvk_v4l2_h264_std_to_ctrl_pps()
5. fill v4l2_ctrl_h264_decode_params from op->pic_info + session->dpb[]
6. ext_controls = { SPS, PPS, DECODE_PARAMS, SCALING_MATRIX }
(Phase 1: SLICE_PARAMS optional, FRAME_BASED → omit)
7. VIDIOC_S_EXT_CTRLS(video_fd, which=REQUEST_VAL, request_fd, ext_controls)
8. VIDIOC_QBUF(video_fd, OUTPUT, memory=DMABUF, request_fd, m.fd=src_dmabuf,
bytesused=op->src_size, timestamp=op->qbuf_ts)
9. VIDIOC_QBUF(video_fd, CAPTURE, memory=DMABUF, index=dst_iv->image->v4l2_capture_index)
10. MEDIA_REQUEST_IOC_QUEUE(request_fd)
11. poll(request_fd, POLLPRI, timeout_ms=200)
12. VIDIOC_DQBUF(video_fd, OUTPUT) /* release input slot */
13. VIDIOC_DQBUF(video_fd, CAPTURE) /* output ready */
14. session->dpb[op->dst_dpb_slot] = { valid:true, reference_ts:op->qbuf_ts }
vk_queue_signal_semaphores(submit->signal_semaphores)
```
Per Phase 1 §J. Step 11's 200ms timeout is empirically derived from libva-v4l2-request-fourier behavior (it polls indefinitely; we cap to avoid driver-side hangs surfacing as Vulkan device-lost on bad bitstreams).
### D8 — Synchronization: standard vk_queue infrastructure
`panvk_per_arch(create_video_decode_queue)` initializes a `struct vk_queue` with `driver_submit = panvk_per_arch(video_decode_queue_submit)`. Wait/signal semaphores are handled by the standard `vk_queue_submit` infrastructure. Inside `submit`, the `poll(request_fd)` in step 11 is the synchronous gate — when it returns, the decode is done in V4L2 land, and the signal semaphores are signaled before returning.
For Phase 1, **all video decodes are synchronous to submit**. Async / pipelined decode is Phase >>1.
### D9 — Hantro probe: by DT compatible name + topology
`panvk_v4l2_probe_hantro()` enumerates `/dev/video*` via `udev`, queries each with `VIDIOC_QUERYCAP`, accepts cards whose `card` field starts with `"hantro-vpu"` OR matches the RK3568/RK3566/RK3588 hantro DT compatibles. Falls back to a hard-coded `/dev/video1` if udev unavailable. Mirrors `libva-v4l2-request-fourier/src/request.c:143-308` `find_decoder_video_node_via_topology`.
Negative probe outcome (no hantro device) → physical_device's video extension advertisement returns false, queue family entry is suppressed, vkEnumerateDeviceExtensionProperties does not list the three KHR_video_*. Driver gracefully degrades to graphics-only.
### D10 — Errors: broad first, refine Phase 6
- V4L2 EINVAL / EAGAIN / EBUSY at submit → `VK_ERROR_DEVICE_LOST` (broad)
- Probe failure during CreateVideoSession → `VK_ERROR_INITIALIZATION_FAILED`
- DPB slot conflict → `VK_ERROR_OUT_OF_DEVICE_MEMORY` (closest spec match)
- Refine per-error-class mapping in Phase 6 (conformance hardening).
## Out of scope for this iteration (explicit non-goals)
1. **H.265 / HEVC**: Phase 0 lock — H.264 only.
2. **Encode**: out of scope, ever (until a separate campaign).
3. **Async decode** / pipelined submit: synchronous-to-submit only in Phase 1.
4. **Multi-session concurrent decode**: single session only in Phase 1 (per Phase 0 Q5).
5. **`VkVideoMaintenance1`** (inline parameters, inline queries): not in the simple-test requirements.
6. **Multiplane 444 formats** (`VK_EXT_ycbcr_2plane_444_formats`): optional, not in Phase 1.
7. **`VK_EXT_descriptor_buffer`** integration: optional, not in Phase 1.
8. **Decode correctness verification** (frame-PSNR vs reference): Phase 7 territory.
9. **Brave consumer**: structurally unfixable, see brave-vaapi-fourier close + DokuWiki.
## Failure modes to watch for during Phase 4 (instrumentation plan)
| Failure | Detection |
|---|---|
| hantro device not present on a build target | `panvk_v4l2_probe_hantro` returns false → extension list silently shrinks. Test: `vulkaninfo \| grep VK_KHR_video` empty on a non-hantro box |
| `/dev/video1` held by libva → CreateVideoSession EBUSY | `mesa_loge()` at probe + return VK_ERROR_INITIALIZATION_FAILED. Test: run mpv-fourier in parallel, verify clean error message |
| S_EXT_CTRLS EINVAL on a per-control basis | per-control `failing_ctrl_id` is in libva-v4l2-request-fourier `src/v4l2.c:497-502` (the format we don't have on the iter14 path). Reproduce that diagnostic in our `panvk_v4l2_submit_op` |
| H.264 spec field mismatch between Std* and v4l2_ctrl_* | Add a per-field assertion in the std→v4l2 bridge for the fields where the bitwidth differs (e.g., `bit_depth_luma_minus8` is u8 in std, u8 in v4l2 — but some flags pack differently). Test: assert at translation time |
| DPB slot reuse with stale reference_ts | `session->dpb[].valid` cleared at DestroyVideoSession + at ResetVideoCodingControl. Test: send a `RESET` flag mid-stream and check dpb[] is cleared |
| Driver-side decode hang (bad bitstream) | poll(timeout=200ms) is the gate. Test: feed a truncated bitstream, verify clean VK_ERROR_DEVICE_LOST rather than session hang |
## Phase 4 implementation slice — first three commits
Bite-sized, validated incrementally:
1. **Commit 1** — extension advertisement + queue family registration (no functionality, just enumeration). Validation: `vulkan-video-dec-simple-test` gets past `HasAllDeviceExtensions` check and into device creation. Failure mode: extension list still missing.
2. **Commit 2**`CreateVideoSessionKHR` + `DestroyVideoSessionKHR` + capability/format entrypoints (returns sane caps, no V4L2 yet — fds opened as `/dev/null` placeholders if necessary). Validation: simple-test creates a session, gets memory requirements (0 entries), destroys it cleanly. Failure mode: session create returns ERROR.
3. **Commit 3**`panvk_v4l2_probe_hantro` + real video_fd open + per-session V4L2 init (S_FMT, REQBUFS, request fd pool). Validation: simple-test creates a session against real `/dev/video1`. Failure mode: probe fails or EBUSY.
After commit 3, all the plumbing is wired. Commits 4-6 add the per-frame decode plumbing (vkCmdDecodeVideoKHR record + submit dispatch + the ioctl dance). Commit 7 is the Std→v4l2 control bridge.
## Phase 2 close criteria
- [x] All D1D10 decisions locked
- [x] Non-goals explicit
- [x] Failure-modes table with detection methods
- [x] Phase 4 first-three-commits slice defined
- [x] Constraints re-verified on ohm (substrate side)
Phase 3 next: build a probe test client (smaller than vk-video-samples) that exercises just the extension-advertisement + queue-family-enumeration path. This is the regression test Phase 4 commits 1-2 are validated against, before bringing in the heavier vk-video-samples machinery.
— claude-noether, 2026-05-21
@@ -0,0 +1,50 @@
# Phase 4 progress — panvk-bifrost-video Commits 1-6 landed; 7b residual
State at 2026-05-21 20:40 UTC. All evidence in `phase0_evidence/`.
## What's working end-to-end
1. **Three required Vulkan video extensions advertised**: `VK_KHR_video_queue`, `VK_KHR_video_decode_queue`, `VK_KHR_video_decode_h264` (probe_vkvideo PASS 5/5).
2. **Video decode queue family** advertised at Vulkan idx 1 (PAN_ARCH<9), with `VK_QUEUE_VIDEO_DECODE_BIT_KHR | VK_QUEUE_TRANSFER_BIT` and `videoCodecOperations = VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR`.
3. **Video session create/destroy**: opens real V4L2 fds to `/dev/video1` + `/dev/media0`, negotiates multi-planar `H264_SLICE` OUTPUT + `NV12` CAPTURE formats, REQBUFS both queues with `V4L2_MEMORY_DMABUF`, allocates 18 request_fds via `MEDIA_IOC_REQUEST_ALLOC`, sets device-level `DECODE_MODE_FRAME_BASED + START_CODE_ANNEX_B` controls, STREAMON.
4. **Per-physical-device capability + format entrypoints**: `panvk_GetPhysicalDeviceVideoCapabilitiesKHR` (max 1920×1088, 16 DPB slots, level 4.2), `panvk_GetPhysicalDeviceVideoFormatPropertiesKHR` (NV12).
5. **`Cmd*Video*` entrypoints dispatch reaches our code**: Begin/End/Control/Decode are called per the spec for vk-video-samples simple-test. The first frame's params parse correctly: sps_id=0, pps_id=0, IdrPicFlag=0, 0 refs, src bitstream 6273 bytes.
6. **Std → V4L2 H.264 bridge compiled in**: `panvk_v4l2_h264_std_to_ctrl_sps`, `_pps`, `_scaling_matrix`, `_default_flat_scaling_matrix`, `_build_decode_params` (460 LoC, agent-authored, field-by-field map cited to V4L2 kernel docs).
7. **14-step V4L2 ioctl dance compiled in**: `panvk_v4l2_submit_h264_decode` does `S_EXT_CTRLS` (request_fd-bound) → `QBUF OUTPUT``QBUF CAPTURE``MEDIA_REQUEST_IOC_QUEUE``poll(POLLPRI, 200ms)``DQBUF OUTPUT/CAPTURE`. Per Phase 2 D7.
## What's deferred — Commit 7b
The Cmd*Video* entrypoints currently log entry and discard their inputs. To actually decode, they need to:
1. **Access `cmdbuf->video.{vs,params}` fields**. These fields exist on JM `panvk_cmd_buffer` (added in this iter). Access requires the per-arch header, which an arch-agnostic source file can't reach.
**Fix**: relocate the four Cmd*Video* entrypoints to `jm/panvk_vX_video_decode_cmd.c` so they compile only for PAN_ARCH<9 and have native access to the JM cmdbuf struct.
2. **Translate parameters per frame**. The Std→V4L2 bridge is ready; call site needs:
- `vk_video_find_h264_dec_std_sps(params, pStdPictureInfo->seq_parameter_set_id)` — lookup active SPS from session params
- `vk_video_find_h264_dec_std_pps(params, sps_id, pic_parameter_set_id)`
- `panvk_v4l2_h264_std_to_ctrl_sps/pps()`
- `panvk_v4l2_h264_default_flat_scaling_matrix()` (Phase 1; real scaling matrix is later)
- `panvk_v4l2_h264_build_decode_params(vs, h264_pi, pps, dst_slot, refs, ts, &c_dec)`
3. **Resolve VkBuffer→dmabuf and VkImage→dmabuf**. Open work — panvk's buffer/image management doesn't expose a direct BO accessor for arbitrary VkBuffer handles. Two candidate paths:
- **DMABUF path**: walk VkBuffer→bound VkDeviceMemory→`panvk_device_memory.bo``pan_kmod_bo_export()` (pattern at `panvk_device_memory.c:400`). Requires extending `panvk_buffer` to track its bound memory, OR using `vk_buffer`'s implicit binding.
- **MMAP path**: REQBUFS with `V4L2_MEMORY_MMAP` instead of DMABUF, `mmap()` the kernel-allocated buffers, copy bitstream in / decoded frame out at QBUF/DQBUF time. Slower (CPU copies) but completely sidesteps panvk's BO integration. **Probably the right Phase 1 minimum.**
4. **Call `panvk_v4l2_submit_h264_decode()`**. The function exists, takes the four control structs + src/dst dma_buf fds + timestamp, runs the 14-step dance synchronously.
5. **Update `vs->dpb[dst_slot]`** with the output timestamp so the next frame's `build_decode_params` finds the reference correctly.
## Snapshot for resume
- Source tarball: `phase0_evidence/commits_1-6_source_snapshot_2026-05-21.tgz` (47KB, 10 files)
- Test output: `phase0_evidence/vk_video_samples_commit4-6_2026-05-21.txt` (entrypoint dispatch confirmed)
- Probe baseline: `phase0_evidence/probe_vkvideo_commit1_PASS_2026-05-21.txt` (5/5 PASS, regression check)
- Build host: ohm at `/home/mfritsche/mesa-build/mesa-26.0.6/`
- Live patched lib: `/home/mfritsche/panvk-patched-libs/libvulkan_panfrost.so`
- ICD JSON: `/tmp/iter17_icd.json` (points at patched lib)
## Per dev_process
Phase 4 stays open (Commit 7b residual). Phase 5 (janet review), Phase 6 (real decode validation), Phase 7 (mpv-fourier consumer proof), Phase 8 (package r1 of `mesa-panvk-bifrost-video`) are all gated on 7b.
— claude-noether, 2026-05-21
+128
View File
@@ -0,0 +1,128 @@
/*
* panvk-bifrost-video — Phase 3 regression probe.
*
* Enumerates Vulkan device extensions + queue families on every physical
* device. Emits structured PASS/FAIL lines for the four conditions Phase 1
* of the campaign must flip from FAIL to PASS:
*
* 1. extension VK_KHR_video_queue present
* 2. extension VK_KHR_video_decode_queue present
* 3. extension VK_KHR_video_decode_h264 present
* 4. queue family with VK_QUEUE_VIDEO_DECODE_BIT_KHR (advertising
* videoCodecOperations & VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR)
*
* Build: gcc -O2 -Wall probe_vkvideo.c -lvulkan -o probe_vkvideo
* Run: VK_ICD_FILENAMES=/usr/lib/panvk-bifrost/icd.json \
* PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1 \
* ./probe_vkvideo
*
* Phase 3 baseline (panvk-bifrost r4): all 4 → FAIL.
* Phase 4 commit 1 target: all 4 → PASS (no functionality, just enumeration).
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <vulkan/vulkan.h>
#define FAIL(fmt, ...) do { fprintf(stderr, "[fail] " fmt "\n", ##__VA_ARGS__); return 1; } while (0)
#define INFO(fmt, ...) printf("[info] " fmt "\n", ##__VA_ARGS__)
static void report(bool ok, const char *name) {
printf("[%s] %s\n", ok ? "PASS" : "FAIL", name);
}
static bool has_ext(const VkExtensionProperties *exts, uint32_t n, const char *name) {
for (uint32_t i = 0; i < n; i++)
if (strcmp(exts[i].extensionName, name) == 0) return true;
return false;
}
int main(void) {
VkResult r;
VkInstance inst;
const VkApplicationInfo app = {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pApplicationName = "panvk-bifrost-video-probe",
.apiVersion = VK_API_VERSION_1_3,
};
const VkInstanceCreateInfo ici = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pApplicationInfo = &app,
};
r = vkCreateInstance(&ici, NULL, &inst);
if (r != VK_SUCCESS) FAIL("vkCreateInstance => %d", r);
uint32_t n_phys = 0;
r = vkEnumeratePhysicalDevices(inst, &n_phys, NULL);
if (r != VK_SUCCESS) FAIL("vkEnumeratePhysicalDevices count => %d", r);
if (n_phys == 0) FAIL("no physical devices");
VkPhysicalDevice *phys = calloc(n_phys, sizeof(*phys));
r = vkEnumeratePhysicalDevices(inst, &n_phys, phys);
if (r != VK_SUCCESS) FAIL("vkEnumeratePhysicalDevices fill => %d", r);
int overall_pass = 0;
for (uint32_t pi = 0; pi < n_phys; pi++) {
VkPhysicalDeviceProperties p;
vkGetPhysicalDeviceProperties(phys[pi], &p);
INFO("device[%u]: %s (vendor=%04x device=%08x)", pi, p.deviceName, p.vendorID, p.deviceID);
uint32_t n_ext = 0;
vkEnumerateDeviceExtensionProperties(phys[pi], NULL, &n_ext, NULL);
VkExtensionProperties *exts = calloc(n_ext, sizeof(*exts));
vkEnumerateDeviceExtensionProperties(phys[pi], NULL, &n_ext, exts);
bool e_queue = has_ext(exts, n_ext, "VK_KHR_video_queue");
bool e_decode = has_ext(exts, n_ext, "VK_KHR_video_decode_queue");
bool e_h264 = has_ext(exts, n_ext, "VK_KHR_video_decode_h264");
report(e_queue, "VK_KHR_video_queue");
report(e_decode, "VK_KHR_video_decode_queue");
report(e_h264, "VK_KHR_video_decode_h264");
/* Queue family enumeration with video-properties pNext walk.
* If VK_KHR_video_queue isn't advertised, this still works but
* VkQueueFamilyVideoPropertiesKHR fields stay zero. */
uint32_t n_qf = 0;
vkGetPhysicalDeviceQueueFamilyProperties2(phys[pi], &n_qf, NULL);
VkQueueFamilyProperties2 *qfp = calloc(n_qf, sizeof(*qfp));
VkQueueFamilyVideoPropertiesKHR *vp = calloc(n_qf, sizeof(*vp));
for (uint32_t i = 0; i < n_qf; i++) {
qfp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2;
qfp[i].pNext = e_queue ? &vp[i] : NULL;
vp[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR;
}
vkGetPhysicalDeviceQueueFamilyProperties2(phys[pi], &n_qf, qfp);
bool qf_has_video = false;
bool qf_has_h264 = false;
for (uint32_t i = 0; i < n_qf; i++) {
INFO(" qf[%u]: flags=0x%08x count=%u",
i, qfp[i].queueFamilyProperties.queueFlags,
qfp[i].queueFamilyProperties.queueCount);
if (qfp[i].queueFamilyProperties.queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) {
qf_has_video = true;
if (vp[i].videoCodecOperations & VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR)
qf_has_h264 = true;
}
}
report(qf_has_video, "queue family with VK_QUEUE_VIDEO_DECODE_BIT_KHR");
report(qf_has_h264, "queue family advertising DECODE_H264 codec op");
if (e_queue && e_decode && e_h264 && qf_has_video && qf_has_h264)
overall_pass = 1;
free(qfp); free(vp); free(exts);
}
free(phys);
vkDestroyInstance(inst, NULL);
printf("\n=== OVERALL: %s ===\n", overall_pass ? "PASS" : "FAIL (Phase 3 baseline expected)");
return overall_pass ? 0 : 2; /* exit 2 distinguishes "ran cleanly, baseline-fail" from build/run errors */
}