iter31 α-29 close: HEVC Bug 5 remainder FIXED — 3/3 PASS

Fix: slice_params.short_term_ref_pic_set_size = picture->st_rps_bits
(was 0, mis-routed via α-26 into decode_params with same field name).

Final 5-codec state:
- H.264 10F: PASS (byte-equal SW)
- HEVC 10F: PASS (byte-equal SW)  ← THIS ITER
- VP9 10F: PASS (byte-equal SW)
- MPEG-2 / VP8: untestable through libva single-device probe
  (pre-existing limitation, orthogonal to Bug 4/5)

Backend fork tip: 23eb1bd. Kernel: 7.0-10 (diagnostic printks still in,
production cleanup outstanding).
This commit is contained in:
2026-05-14 15:30:48 +00:00
parent 422ecafca9
commit c1f9738368
+61
View File
@@ -0,0 +1,61 @@
## Iteration 29/30/31 — Phase 8 (close): HEVC frame 2+ FIXED
Closes 2026-05-14, second campaign-day session after iter27/28 partial close. Three sub-iterations: iter29 probe (refuted 40-byte inflation theory), iter30 timestamp-magnitude sweep (refuted timestamp hypothesis), **iter31 α-29 (FIX)**.
### Final result: 3/3 PASS (anchors that go through libva single-device probe)
| Codec | 10F result | Status |
|---|---|---|
| H.264 | byte-equal to SW (10 frames) | **PASS** (Bug 4 already fixed iter25 α-25) |
| HEVC | byte-equal to SW (10 frames) | **PASS** (Bug 5 NOW FIXED iter31 α-29) |
| VP9 | byte-equal to SW (10 frames) | **PASS** (unchanged) |
| MPEG-2| untestable through libva | pre-existing single-device probe limitation |
| VP8 | untestable through libva | same |
### Root cause: wrong V4L2 field
α-26 had set `decode_params->short_term_ref_pic_set_size = picture->st_rps_bits` based on the FIELD NAME. But `picture->st_rps_bits` from VAAPI is documented as the bit-count of `short_term_ref_pic_set()` in the **slice segment header** (per `/usr/include/va/va_dec_hevc.h:177-185`). The V4L2 SLICE-PARAMS field of the same name is what rkvdec reads. The V4L2 DECODE-PARAMS field with this name (where α-26 wrote it) refers to the SPS-side bit count, which rkvdec does not use.
`rkvdec_hevc.c::assemble_sw_rps` (lines 386-389) reads `sl_params->short_term_ref_pic_set_size`:
```c
if (!(decode_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC)) {
if (sl_params->short_term_ref_pic_set_size)
st_bit_offset = sl_params->short_term_ref_pic_set_size;
else if (sps->num_short_term_ref_pic_sets > 1)
st_bit_offset = fls(sps->num_short_term_ref_pic_sets - 1);
}
```
For BBB's `num_short_term_ref_pic_sets == 1`, the fallback (`fls(0) = 0`) is wrong — the HW reads slice-header bits from offset 0, treats the st_ref_pic_set() bytes as long-term-RPS / slice-header continuation, and the entropy decoder spins onto garbage state for every non-IDR slice. IDR is gated out by `V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC` → frame 1 unaffected → consistent with prior iter25 "frame 1 PASS, frame 2+ FAIL" observation.
### Fix: α-29
```c
// src/h265.c::h265_fill_slice_params, line 476:
- slice_params->short_term_ref_pic_set_size = 0; /* VAAPI doesn't expose */
+ slice_params->short_term_ref_pic_set_size = picture->st_rps_bits;
```
Backend commit `23eb1bd`. Build, deploy, re-test → 10/10 PASS for HEVC.
### Investigation path
- **iter29** added env-gated dump of last 80 bytes of HEVC slice_data. Trailing 80 bytes look like real entropy — refuted the "40-byte ffmpeg-vaapi inflation" hypothesis from iter27/28 close.
- **iter30** added `LIBVA_TS_SCALE` env-gated timestamp multiplier. Tested scales 1/1000/1000000. All produced identical (wrong) frame-2 output. Refuted timestamp-magnitude hypothesis.
- **iter31** extended kernel iter27 printk to dump `dpb[2..3]` (offsets 96..128) and `sl[32..64]`. Direct libva-vs-kdirect comparison for POC=1 (display frame 2, decode #4) revealed all slice_params[0..64] bytes match EXCEPT `num_entry_point_offsets` (known unused by rkvdec). Re-reading rkvdec's assemble_sw_rps located the `sl_params->short_term_ref_pic_set_size` read site, then traced backward to ffmpeg-v4l2request's `sh->short_term_ref_pic_set_size` source. VAAPI's `picture->st_rps_bits` is the semantic equivalent.
### Substrate state at iter31 close
- Backend fork tip `23eb1bd` (α-25 through α-29 + iter29 dump + iter30 ts-scale env probes; α-29 is the load-bearing fix; others are env-gated and inactive by default).
- Kernel `7.0-10` with iter17 + iter20 + iter21 + iter22 + iter23 + iter27 + iter31 printks (production kernel would revert all these — outstanding cleanup item).
- 5-codec status: 3 PASS, 2 untestable. MPEG-2/VP8 reachability requires libva multi-device-probe rework (separate iter — orthogonal to Bug 4/5).
### Campaign milestone
Bug 4 fix landed iter25 α-25. Bug 5 frame 1 fix landed same iter25 α-25. Bug 5 remainder (frames 2+) localized over iter26-28 (correctly: rkvdec reads field X, libva sends 0), mis-fixed in α-26 (right value, wrong field), refuted in iter29-30 (rule-outs), correctly fixed in α-29 (right value to right field). Total: 1 day for full pixel correctness across the three rkvdec-routed codecs.
### Memory entries to update
- `feedback_rkvdec_image_fmt_pre_seed.md` — note the remainder-fix landed (no longer "deferred").
- `feedback_libva_byte_correct_kernel_bug.md` — fully overturned now (Bug 5 is fully a libva-side fix, not kernel-side).
- New: `feedback_va_st_rps_bits_is_slice_field.md` — VAAPI's picture->st_rps_bits goes into slice_params not decode_params (the field NAME is identical, semantics differ).