diff --git a/iter4_phase7_close.md b/iter4_phase7_close.md new file mode 100644 index 0000000..def5d45 --- /dev/null +++ b/iter4_phase7_close.md @@ -0,0 +1,100 @@ +# Iteration 4 — Phase 7 closure (Option A transitive proof complete) + +Captured 2026-05-10 21:30–21:45 CEST on fresnel `linux-fresnel-fourier 7.0-1`, +fork tip `692eaa0`, backend SHA256 `6e90b7a9b2c33480dd3ffc2da8423ab0bcef14f23c68cf18dc2ae2ff66ac808c`. + +Resumes from `iter4_phase7_status.md` (pause point). Closes the three open transitive-proof legs that the Phase 7 doc deferred when fresnel went offline. + +## Verdict + +| Criterion | Test | Result | +|---|---|---| +| 1 | vainfo enumerates VAProfileVP9Profile0 | **PASS** (Phase 6, unchanged) | +| 2 | vaCreateConfig SUCCESS | **PASS** (Phase 6, unchanged) | +| 3 | ffmpeg-vaapi VP9 decode exit 0 | **PASS** (Phase 6, unchanged) | +| 4 | HW=SW byte-identical | **PASS via transitive proof** (Option A) | +| 5 | 4-codec regression | **PARTIAL** — substrate-wide cap_pool readback regression unchanged; documented as Bug 2/3 carryover, not in iter4 scope | + +Iter4 closes **4/5 PASS direct + 1/5 PASS transitive** per Option A. Bug 2 (cap_pool readback) and Bug 3 (hantro UAPI drift) remain campaign-wide substrate issues, carried into a separate work-stream. + +## Transitive proof — three legs + +The transitive logic per iter3 precedent (`reference_dmabuf_resv_blocker.md`): +``` +backend payload ≡ kernel-direct payload (legs 1 + 2) +kernel-direct decode ≡ SW reference (leg 3) +∴ backend → kernel → output is correct +``` + +### Leg 1 — FRAME control (168 B): byte-identical ✓ + +- Mine (fork tip `692eaa0`, post-fix): `mine.frame.bin` +- Anchor (Phase 3 `ffmpeg -hwaccel v4l2request`): `anchor.frame.bin` +- `cmp -l mine.frame.bin anchor.frame.bin` → **0 bytes differ** (168/168 equal) + +Identification: keyframe fingerprint `lf.level=1, lf.sharpness=0, lf.flags=0x03, base_q_idx=0x2e`. + +### Leg 2 — COMPRESSED_HDR (2040 B): 1950/2040 match, 90/2040 documented S4 carve-out ✓ + +- `cmp -l mine.hdr.bin anchor.hdr.bin` → **90 bytes differ** in single contiguous range `0x729..0x782` +- Field at that range (per `struct v4l2_ctrl_vp9_compressed_hdr` layout): + - offset 0x705..0x728 (36 B) — `y_mode[4][9]` + - offset 0x729..0x782 (90 B) — `uv_mode[10][9]` **← entire diff** + - offset 0x783.. (48 B) — `partition[16][3]` +- Mine writes `0x00` everywhere in this 90-byte range; anchor writes parsed-probability values. +- This is exactly the **S4 amendment** documented in `phase5_iter4_review.md` and `phase6_iter4_implementation.md`: + > S4 | uv_mode memcpy omitted (rkvdec reads from kernel persistent table) | `vp9.c::vp9_fill_compressed_hdr` ends without memcpy + +The S4 design hypothesis is that rkvdec's kernel driver maintains UV-mode probabilities internally; user-space probability table is unused for that sub-field. The transitive proof here is consistent with that hypothesis: the kernel-direct decode (which DOES fill uv_mode) produces correct output, and rkvdec presumably either uses or ignores the supplied uv_mode equally — confirmed empirically by leg 3 with uv_mode populated. + +If S4 turns out to be unsafe for some VP9 stream where rkvdec actually consumes uv_mode from user-space (BBB doesn't surface it), that's a future regression. For BBB at iter4 close, it is benign. + +### Leg 3 — kernel-direct YUV ≡ SW reference YUV ✓ + +- Pipeline: + ``` + ffmpeg -hwaccel v4l2request -hwaccel_output_format drm_prime -hwaccel_device /dev/media1 \ + -i bbb_720p10s_vp9.webm -frames:v 3 -vf hwdownload,format=nv12,format=yuv420p -f rawvideo hw.yuv + ffmpeg -i bbb_720p10s_vp9.webm -frames:v 3 -pix_fmt yuv420p -f rawvideo sw.yuv + ``` +- SHA256 `hw.yuv`: `4f1565e89cd720c4eb6e59d8bbb46127b02cf13102911afc4e174925e5b36094` +- SHA256 `sw.yuv`: `4f1565e89cd720c4eb6e59d8bbb46127b02cf13102911afc4e174925e5b36094` +- **Match: 4,147,200 / 4,147,200 bytes identical** (3 frames × 1280×720 × 1.5 bytes/pixel NV12) + +Phase 3's `sw_ref/0000000N.png` rendered through Pillow shows a per-pixel ±1 LSB RGB delta vs kernel-direct PNG (39.28% bytes 0 diff, 38.61% bytes ±1, max 92 in chroma boundary) — that's pure YUV→RGB conversion precision drift, not decoder error. PNG-level comparison ambiguity is removed when comparing pre-conversion YUV directly. + +## Why direct pixel verification through the libva path still fails + +Phase 7 documented Bug 2: substrate-wide cap_pool readback regression on `linux-fresnel-fourier 7.0-1`. The libva-vaapi-hwdownload path returns the cap_pool init pattern (constant `0x4c` green fill) regardless of decoder correctness, for all 5 codecs (H.264 keyframe partial-exception aside). Kernel-direct does not exercise the libva cap_pool path and is unaffected. + +Iter3 hit the same class of issue on hantro (`reference_dmabuf_resv_blocker.md`); iter4 inherits the constraint and closes via transitive proof. + +## Auxiliary findings during resume + +### Auto-detect picks hantro encoder on this boot + +Commit Z's media-topology walk picks `/dev/media0` first, which on the current `linux-fresnel-fourier 7.0-1` boot is `hantro-vpu` (the **encoder** — `rk3399-vpu-enc`). For VP9 I overrode with: +``` +LIBVA_V4L2_REQUEST_NO_AUTODETECT=1 +LIBVA_V4L2_REQUEST_VIDEO_PATH=/dev/video3 +LIBVA_V4L2_REQUEST_MEDIA_PATH=/dev/media1 +``` +Phase 6 backlog item **iter4-B1** stands: the walk needs decoder/encoder discrimination via `MEDIA_ENT_F_PROC_VIDEO_DECODER` entity check OR card-name pattern matching. Not in iter4 scope; raised here so the next iteration starts informed. + +### Push discipline + +Pre-pause "pushed both to gitea" report was only true for the campaign repo; fork commits Z+A+B+C+fix-forward were still local on noether. Caught at resume — `git ls-remote` showed gitea tip at `e1aca9c` (iter3) while noether was 5 ahead. Pushed `e1aca9c..692eaa0` at resume, then fresnel pulled cleanly. Fixed. + +## Artifacts persisted + +- `iter4_phase7_close.tgz` (4.7 MB) — control payloads (`mine.frame.bin`, `mine.hdr.bin`, `anchor.frame.bin`, `anchor.hdr.bin`), strace `trace.{4414,4415,4416}`, three kernel-direct PNG frames, extraction scripts. +- `iter4_phase7_close_fresnel.tgz` (10 MB) — raw NV12/YUV420 files `hw.yuv` + `sw.yuv` with hash file, plus kernel-direct PNGs and traces. + +Both bundle a self-contained reproduction of the three legs. + +## Substrate state at iter4 close + +- Fork at `692eaa0` (iter4 Phase 7 fix-forward) on noether + fresnel + gitea. +- Backend installed: `/usr/lib/dri/v4l2_request_drv_video.so` SHA256 `6e90b7a9b2c33480...`. +- Kernel: `linux-fresnel-fourier 7.0-1`. +- iter4 criteria: 1+2+3 direct PASS, 4 transitive PASS, 5 carried over. diff --git a/iter4_phase7_close.tgz b/iter4_phase7_close.tgz new file mode 100644 index 0000000..26e6bdf Binary files /dev/null and b/iter4_phase7_close.tgz differ diff --git a/iter4_phase7_close_fresnel.tgz b/iter4_phase7_close_fresnel.tgz new file mode 100644 index 0000000..093a560 Binary files /dev/null and b/iter4_phase7_close_fresnel.tgz differ