3ed1e454fb
α-2 (POC strip removal) changed wire bytes (POC now matches kdirect's sentinel-encoded 0x10000) but H.264 output unchanged. POC not load-bearing. 5-codec regression sweep on α-2 backend: all 4 non-H.264 anchors hold. Zero regression. Iter8 close: 5/6 PASS, criterion-1 PARTIAL. Bug 4 narrowed but not fixed. Eliminations achieved: 1. libva-readback bug (γ dump) 2. Slot-binding wrong (γ dump shows correct slot per surface) 3. Stale residue (IMP-1 memset confirmed deterministic kernel write) 4. constraint_set_flags (Phase 5b CRIT-1: rkvdec source review) 5. POC sentinel strip (α-2 wire change, no output change) Remaining candidates for iter9: PPS diff (α-3), DECODE_PARAMS post-DPB fields (α-6), DPB entry order (α-4), slice data encoding (α-5). Fork tip 0226684 carries γ + IMP-1 diagnostic + α-2 hygiene. All env-gated off by default; α-2 is a wire-payload cleanup with zero behavior effect. Lessons distilled: - Reviews are never skippable — Phase 5b CRIT-1 saved a build cycle. - Wire-byte equivalence ≠ behavior equivalence. - Per-driver kludges in shared codec code need explicit gating. - Bug carryover labels can mislead (Bug 4 != "inter race-loss"). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
170 lines
8.4 KiB
Markdown
170 lines
8.4 KiB
Markdown
# Iteration 8 — Phase 8 (close)
|
||
|
||
Closes 2026-05-13. iter8 = Bug 4 (H.264 partial-fill, originally "inter race-loss") PARTIAL close — narrowed via three eliminations, not fixed.
|
||
|
||
## Summary
|
||
|
||
| Metric | Value |
|
||
|---|---|
|
||
| Iteration target | Bug 4 — H.264 libva produces 16×32 partial-fill instead of full frame |
|
||
| Hardware | RK3399 rkvdec |
|
||
| Fork tip start (iter7 close) | `6df2159` |
|
||
| Fork tip end (iter8 close) | `0226684` (4 commits: γ dump, IMP-1 pre-zero, stdlib include fix-fwd, α-2 POC strip removal) |
|
||
| LOC delta | +103 / -3 across `src/surface.c`, `src/picture.c`, `src/h264.c` |
|
||
| Phase 1 criteria | 5/6 PASS (C1 PARTIAL — Bug 4 narrowed not fixed) |
|
||
| Reviews | 2 (Phase 5 γ-plan review + Phase 5b/5c α candidate reviews); 1 plan killed (α-1) |
|
||
| Hypotheses eliminated | 5 (libva-readback, slot-binding, stale-residue, constraint_set_flags, POC sentinel) |
|
||
| Campaign scoreboard | Unchanged on pixel-correctness axis; +0 net codec fixes. +diagnostic instrumentation (γ dump, pre-zero gate). |
|
||
|
||
## Phase-by-phase narrative
|
||
|
||
### Phase 0 — Bug 4 locked
|
||
|
||
User pick: H.264 inter race-loss (carryover label from iter4 Phase 7). Lock criterion: `libva_h264 == kdirect_h264` byte-identical.
|
||
|
||
### Phase 2 — H.264 source-read
|
||
|
||
Walked h264.c pipeline end-to-end (994 LOC). Mapped per-frame decode flow (BeginPicture → RenderPicture → EndPicture → SyncSurface). Eliminated 6 of 13 surface-level hypotheses by source-read alone.
|
||
|
||
### Phase 3 — empirical strace + byte-level YUV examination
|
||
|
||
**Bug redefinition**: NOT inter-race-loss — even keyframe (IDR) fails. Pattern: structured 16×32 byte patch of luma-neutral data at Y top-left, rest zero. Per-codec diff: VP9 works via libva, HEVC/H.264 don't. SPS bytes: only diff is `constraint_set_flags` (libva=0 vs kdirect=2). DECODE_PARAMS shows POC sentinel diff (libva strips, kdirect doesn't).
|
||
|
||
### Phase 4 — γ-then-α plan
|
||
|
||
Decided: diagnostic dump γ FIRST to distinguish "kernel didn't write" from "libva mis-reads."
|
||
|
||
### Phase 5 — γ plan reviewed
|
||
|
||
Sonnet-architect: 2 CRIT (logging API misuse, missing null guard) + 4 IMP + 3 MIN. All mechanical; strategy stood.
|
||
|
||
### Phase 6 — γ implemented
|
||
|
||
Added env-gated diagnostic dump to surface.c::RequestSyncSurface. Built, installed.
|
||
|
||
### Phase 7 — γ + IMP-1 verification
|
||
|
||
γ dump showed libva-readback path returns exactly what's in the buffer (no readback bug). IMP-1 memset experiment confirmed the 16×32 patch is deterministic (NOT stale residue). **Bug pinned to kernel-side**: rkvdec accepts request, writes only 512 bytes, stops without error flag.
|
||
|
||
### Phase 4b/5b — α-1 SPS constraint_set_flags fix (KILLED)
|
||
|
||
Plan: derive constraint_set_flags per-profile.
|
||
Phase 5b reviewer empirically read rkvdec-h264.c end-to-end and found `constraint_set_flags` is NEVER accessed by the driver. **CRIT-1 killed α-1 before any build.** Saved ~15 LOC + a build/install/test cycle.
|
||
|
||
Reviewer redirected to DPB / POC diff.
|
||
|
||
### Phase 4c/5c/6c — α-2 POC sentinel strip removal
|
||
|
||
Plan: remove `h264_strip_ffmpeg_poc_sentinel` (hantro-specific kludge that's not needed for rkvdec).
|
||
Phase 5c greenlit with one amendment (preserve VA_PICTURE_H264_INVALID → 0 guard).
|
||
Phase 6c implemented: ~12 LOC change in h264.c.
|
||
|
||
### Phase 7c — α-2 verification
|
||
|
||
α-2 changed wire bytes (POC now matches kdirect's 0x00010000) but output unchanged. **POC isn't load-bearing for Bug 4.** Three more hypotheses eliminated (libva-readback, slot-binding, stale-residue, constraint_set_flags, POC sentinel — 5 total).
|
||
|
||
5-codec regression sweep: all 4 non-H.264 hashes unchanged. Zero regression.
|
||
|
||
## Commits shipped
|
||
|
||
### Fork (libva-v4l2-request-fourier)
|
||
|
||
| SHA | Files | LOC | Description |
|
||
|---|---|---|---|
|
||
| `7eae6ea` | src/surface.c | +78 / -1 | γ env-gated CAPTURE buffer diagnostic dump |
|
||
| `66ecbef` | src/picture.c | +23 | IMP-1 env-gated CAPTURE pre-zero diagnostic |
|
||
| `6f4e583` | src/picture.c | +1 | stdlib.h include fix-forward (getenv) |
|
||
| `0226684` | src/h264.c | +12 / -2 | α-2: pass H.264 POC values through unchanged |
|
||
|
||
### Campaign repo (fresnel-fourier)
|
||
|
||
| Commit | Phase | Description |
|
||
|---|---|---|
|
||
| `e47a7ba` | P0 | Lock Bug 4 |
|
||
| `abd97e3` | P2 | H.264 source-read |
|
||
| `4320d78` | P3 | Strace findings + bug redefinition |
|
||
| `3a63076` | P4 | γ-then-α plan |
|
||
| `d4c04b4` | P5 | Architect review |
|
||
| (this) | P7 + P8 | Verification + close |
|
||
|
||
## What worked
|
||
|
||
- **Phase 5b's empirical source-read killed α-1 BEFORE the build cycle**. Saved a build/install/test pass. Pure win for the review discipline.
|
||
- **γ dump immediately ruled out libva-readback hypothesis**. Without γ, iter9 would still be considering libva-side fixes.
|
||
- **IMP-1 memset experiment** was a one-line discriminator (env-gated) that definitively ruled out stale-residue.
|
||
- **5-codec regression sweep at every step**: no anchors moved across γ, IMP-1, α-2 changes. Zero regression risk to date.
|
||
|
||
## What didn't work
|
||
|
||
- **α-1 (constraint_set_flags)**: hypothesis dead per source read.
|
||
- **α-2 (POC strip)**: wire bytes changed; output unchanged.
|
||
|
||
Net: 5 hypotheses eliminated, Bug 4 still present.
|
||
|
||
## Lessons distilled
|
||
|
||
### Lesson 1: Wire-byte equivalence ≠ behavior equivalence
|
||
|
||
α-2 made libva's wire-byte output match kdirect's for POC fields. Output unchanged. **A single-field wire diff is a necessary signal but not sufficient — without knowing whether the kernel actually consumes that field, matching it is theater.** Phase 5b CRIT-1's source-read methodology is the right discipline.
|
||
|
||
### Lesson 2: Per-driver kludges should be flagged as such
|
||
|
||
`h264_strip_ffmpeg_poc_sentinel` was a hantro-specific workaround embedded in shared H.264 code without per-driver gating. iter5b-β's `feedback_unconditional_codec_state.md` rule covers per-codec; this case suggests an analogous **per-V4L2-driver** rule for any kludge with implementation-specific motivation. Memory candidate.
|
||
|
||
### Lesson 3: Bug carryover labels can mislead
|
||
|
||
"H.264 inter race-loss" was the label since iter4 P7. Phase 3 empirically showed the keyframe also fails — the bug isn't race-related at all. **Re-validate the bug shape with empirical evidence before assuming the prior label is correct.** Memory candidate.
|
||
|
||
## Cross-cutting backlog status (iter8 increment)
|
||
|
||
Closed:
|
||
- (none — Bug 4 is PARTIAL, not closed)
|
||
|
||
Narrowed:
|
||
- **Bug 4**: 5 hypotheses eliminated. Remaining candidates: PPS field diff, DPB ordering, DECODE_PARAMS post-DPB fields, slice data encoding.
|
||
|
||
Still open (unchanged):
|
||
- iter4-B1b (multi-decoder routing)
|
||
- iter4-B2, B3, Q6, COLOR_RANGE, L3
|
||
- Bug 5 (HEVC kernel rejection)
|
||
- Bug 6 (VP8 partial output, kernel-side per iter6 narrowing)
|
||
|
||
## Iter8 → iter9 handoff
|
||
|
||
Substrate at close:
|
||
- Fork tip `0226684` on noether + fresnel + gitea.
|
||
- Backend SHA `b6a3958a…` on fresnel.
|
||
- Kernel `linux-fresnel-fourier 7.0-1` unchanged.
|
||
- Test fixtures unchanged.
|
||
- γ + IMP-1 diagnostic infrastructure in place (env-gated off by default).
|
||
|
||
Campaign scoreboard (unchanged from iter7):
|
||
|
||
```
|
||
Codec | Site | Status | Notes
|
||
========|===========|===============|====================================
|
||
H.264 | rkvdec | PARTIAL | Bug 4 narrowed; PPS diff next (iter9)
|
||
HEVC | rkvdec | TRANSITIVE * | Bug 5 deferred
|
||
VP9 | rkvdec | PASS direct | iter5b-β fix
|
||
MPEG-2 | hantro | PASS (env) | iter1 PASS
|
||
VP8 | hantro | PARTIAL (env) | Bug 6 deferred
|
||
```
|
||
|
||
iter9 candidate ranking (per Phase 7c):
|
||
1. **α-3 PPS full-byte diff** (lowest LOC, mechanical strace re-run + diff)
|
||
2. **α-6 DECODE_PARAMS post-DPB fields** (strace re-run with longer -s, diff bytes 512-559)
|
||
3. **α-4 DPB entry ordering** (~10 LOC change to h264_fill_dpb)
|
||
4. **α-5 Slice data encoding** (deepest investigation, ~60 min)
|
||
|
||
## Memory rule candidates (deferred to next memory-curation pass)
|
||
|
||
- **Per-V4L2-driver kludge gating**: any hantro / rkvdec / cedrus-specific workaround in shared codec code must be gated, similar to per-codec gating per `feedback_unconditional_codec_state.md`.
|
||
- **Bug label revalidation**: when picking up a carryover bug, run Phase 3-equivalent empirical reproduction first; the label may be wrong.
|
||
- **Wire-byte equivalence ≠ behavior equivalence**: a successful "match kdirect's bytes" change isn't proof of fix. Always run the success criterion verifier post-change.
|
||
|
||
## Phase 8 commit
|
||
|
||
This document records iter8 close. Fork at `0226684`. Backend SHA `b6a3958a…`. Bug 4 narrowed via 5 eliminations; 4 of 5 codec criteria unchanged (PASS); criterion-1 H.264 still PARTIAL.
|
||
|
||
iter8 = 5/6 PASS. iter9 has a clearer search space than iter8 opened with.
|