Commit Graph

11 Commits

Author SHA1 Message Date
claude-noether ec9133a5e4 iter1 Phase 7: verification — all 5 criteria GREEN, second codec PASS
Phase 7 verification of iter1 MPEG-2 fix executed against fork tip
229d6d1 (libva-v4l2-request-fourier master = post-Commit-D).
Verbatim raw output captured to phase0_evidence/2026-05-08/
iter1_phase7/. All five Phase 1 criteria green; bonus byte-compare
confirms structural match against Baseline C with one numerical
divergence (vbv_buffer_size, kernel-ignored, non-blocking).

Phase 1 → Phase 7 scoreboard:

  Criterion 1 (vainfo MPEG-2 Simple+Main enum):           PASS
  Criterion 2 (vaCreateConfig SUCCESS for MPEG2Main):     PASS
    Pre-iter1: VA_STATUS_ERROR_UNSUPPORTED_PROFILE (12)
    Post-iter1: VA_STATUS_SUCCESS (verified verbatim libva trace)
  Criterion 3 (ffmpeg-hwaccel-vaapi engages backend):     PASS
    5 frames decoded, exit 0, no Failed-to-create lines,
    no S_EXT_CTRLS EINVAL on the MPEG-2 path
  Criterion 4 (DMA-BUF GL HW=SW byte-identical at +02s):  PASS
    HW frame 1: 6e7873030dbf0403c67f35dd106ebef3c7909a0fd12433b82ad758e7fee9f092
    SW frame 1: 6e7873030dbf0403c67f35dd106ebef3c7909a0fd12433b82ad758e7fee9f092
    HW frame 2: ccc7ce08810d4a96e9ba7a19f4f95bbf6cc861bda9337604b5c668ad52bef7de
    SW frame 2: ccc7ce08810d4a96e9ba7a19f4f95bbf6cc861bda9337604b5c668ad52bef7de
    Frames 1 vs 2 differ in size (real motion).
  Criterion 5 (T4 H.264 reference hashes match):          PASS
    HW + SW frames at +30s into bbb_1080p30_h264.mp4 match
    f623d5f7... and 7d7bc6f2... exactly. No H.264 regression.

Bonus byte-compare against Phase 3 Baseline C verbatim:

  count=3, ctrl_class=V4L2_CTRL_CLASS_CODEC_STATELESS=0xf010000:
    SEQUENCE     id=0xa409dc size=12   (matches)
    PICTURE      id=0xa409dd size=32   (matches structurally)
    QUANTISATION id=0xa409de size=256  (intra matrix bytes
                                        IDENTICAL to Baseline C
                                        verbatim 64 bytes;
                                        non_intra all 16's)
    All return = 0 (kernel accepts every batched call).

  One numerical divergence: sequence.vbv_buffer_size
    post-fix:    0x100000 = 1 048 576 (= SOURCE_SIZE_MAX)
    Baseline C:  0x151800 = 1 376 256 (= negotiated sizeimage)
    Kernel ignores per v4l2-controls.h:2003 (informational).
    Decode is bit-exact correct regardless. Phase 5 reviewer S2
    was numerically prescient; my Phase 5 response (rejected with
    "slot->size = sizeimage") was wrong empirically; operational
    impact nil. Tracked as low-priority post-iter1 polish.

Phase 7 → Phase 8: clean transition, no loopback to Phase 4.

Notable observations for Phase 8 memory update:

  1. V4L2 /dev/videoN numbering shuffles across reboots on RK3399.
     Phase 0/3 had rkvdec=video3+media1, hantro=video5+media2; this
     boot has rkvdec=video1+media0, hantro=video3+media1. Phase 1
     binding cells using fixed paths fragile across reboots. Phase
     4 cross-cutting fix candidate: backend probes /dev/media* for
     driver=hantro-vpu/rkvdec rather than env-var stability.

  2. iter1 patch-0011 cache-stale bug class also affects MPEG-2
     (verified empirically; same as H.264 in T4). vaDeriveImage
     readback returns all-zero NV12 via ffmpeg-vaapi+hwdownload.
     Workaround: DMA-BUF GL import (mpv --vo=image) is cache-
     coherency-safe. Phase 4 cross-cutting fix candidate: add
     VIDIOC_EXPBUF + DMA_BUF_IOCTL_SYNC support to libva backend
     image-export path.

  3. src/context.c:142-155 H.264 device-init logs noisy EINVAL on
     hantro every CreateContext (return value cast to (void) but
     v4l2.c:484 still calls request_log). Cosmetic suppression
     candidate; low priority.

  4. Phase 6 commit D (fix-forward for missed mpeg2-ctrls.h
     include in context.c) — Phase 2 grep audit was incomplete.
     Phase 8 lesson: when deleting a header, completeness check
     is git rm + clean rebuild, not grep alone.

Campaign scoreboard: 1/5 → 2/5 codecs passing
(H.264 in T4, MPEG-2 in iter1). Iter1 advances to Phase 8.

Refs:
  ../libva-v4l2-request-fourier@229d6d1 (the fork tip verified)
  phase4_iter1_plan.md (criteria as locked, including Phase 5
                        amendments to criterion 3 + criterion 4)
  phase5_iter1_review.md (S2 partial-correct; S3, Q4, Q5
                          confirmed empirically)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 09:00:14 +00:00
claude-noether 0e2e1c2293 iter1 Phase 5: sonnet-architect review — 6 findings, 4 amendments
Phase 5 review run via Plan subagent with model: sonnet per
feedback_dev_process.md Phase 5 discipline. Review verbatim
preserved in phase5_iter1_review.md alongside per-finding response.

Findings: 1 Critical (latent), 2 Should-fix (1 valid, 1 misreading),
2 Question/clarification, 1 Nit. Reviewer's bottom-line: medium-high
confidence in the plan as written.

Resolutions:

C1 (union-aliasing reasoning was wrong; iter1 unaffected; latent bug):
  Verified offsets on fresnel via gcc + libva headers:
    h264.matrix_set       at union byte 240
    mpeg2.iqmatrix_set    at union byte 376
    mpeg2.iqmatrix range  [88..376) — sizeof=288
  Setting h264.matrix_set=false writes byte 240, which lands inside
  mpeg2.iqmatrix.chroma_intra_quantiser_matrix at offset 20.
  Phase 2 said the byte gets overwritten by RenderPicture before
  mpeg2_set_controls reads it. That was true only because ffmpeg-
  vaapi sends VAIQMatrixBufferType every frame; codec_store_buffer
  then copies the full 260-byte payload over the corrupted byte.
  ACCEPTED: update Phase 2 + Phase 4 wording to cite the correct
  safety chain. Latent bug for clients that reuse a surface without
  re-sending IQMatrix logged for iter2+ backlog.

S2 (vbv_buffer_size source — reviewer misread):
  Reviewer assumed slot->size = SOURCE_SIZE_MAX (1MB). Verified
  source: src/request_pool.c:71 sets pool->slots[i].size = length,
  where length is the V4L2-reported buffer length from
  VIDIOC_QUERYBUF (= negotiated sizeimage from S_FMT). Phase 3
  Baseline C strace shows S_FMT(OUTPUT_MPLANE) returns
  sizeimage=1382400=0x151800 — exactly matches Baseline C's
  vbv_buffer_size payload. Plan is correct as-is.
  REJECTED (reviewer's claim wrong); 1-line note added to Phase 6
  Commit B message clarifying the dynamic source.

S3 (default-matrix transcription byte-verify protocol):
  ACCEPTED. Phase 6 protocol amendment: when transcribing the
  64-entry default_intra[] in src/mpeg2.c, derive values from
  Baseline C QUANTISATION verbatim payload, then run a diff-based
  assertion before commit lands. Same for non_intra (all 16's),
  chroma_intra (= intra), chroma_non_intra (all 16's) — verified
  against Baseline C bytes 0..63 / 64..127 / 128..191 / 192..255.

Q4 (criterion 4 — ffmpeg+hwdownload primary, not fallback):
  ACCEPTED. Phase 7 harness criterion 4 changes from
    mpv --hwdec=vaapi --vo=image first, ffmpeg fallback
  to
    ffmpeg -hwaccel vaapi -vf hwdownload,format=nv12 primary,
    mpv-vaapi-vo=image backup
  Critical addition: Phase 7 must check both hashes match AND
  content non-zero/non-sentinel. T4 found ffmpeg-vaapi
  -hwaccel_output_format nv12 returns mostly zeros via cached-mmap
  on RK3399 (iter1 patch-0011 cache-stale bug class). For MPEG-2,
  hwdownload may use a different readback path; if it also exposes
  the cache-stale bug, swap to mpv-vaapi-vo=image. Empirical
  determination during Phase 7.

Q5 (timestamp behavior is a correction, not "no semantic change"):
  ACCEPTED. Phase 4 Clause 3 amendment: explicitly note that
  forward_ref_ts/backward_ref_ts = 0 when reference surface is
  VA_INVALID_ID is a CORRECTION vs current code's self-referencing
  behavior. Old code at src/mpeg2.c:106-107, 113-115 set
  forward_reference_surface = surface_object (self-ref) when ref
  was VA_INVALID_ID. New code sets ts to 0. Baseline C frame 1
  confirms 0-as-sentinel; FFmpeg v4l2_request_mpeg2.c:98-108
  matches. Iter1 fixes a latent bug.

Nit 6 (hevc-ctrls.h left alongside removed mpeg2-ctrls.h):
  ACCEPTED (lower-risk path). Phase 6 Commit B removes mpeg2-ctrls.h
  include only; Commit C deletes include/mpeg2-ctrls.h only.
  Hevc-ctrls.h header + include left untouched, deferred to HEVC
  iteration. Optional cleanup if Phase 6 chooses to bundle, but
  default is the smaller diff.

Phase 4 → Phase 6 amendments consolidated:
  1. Clause 3 timestamp behavior explicit (Q5)
  2. Clause 4 default-matrix Baseline-C-derived transcription (S3)
  3. Phase 7 criterion 4 ffmpeg+hwdownload primary + non-zero check (Q4)
  4. Hevc-ctrls.h cleanup deferred (Nit 6)
  5. Phase 2 + Phase 4 wording fix on union safety chain (C1 partial)
  6. Latent surface-reuse bug logged for iter2+ backlog (C1 follow-up)

Plan re-locks with these amendments. Phase 6 proceeds.

Per global ~/.claude/CLAUDE.md rule: Phase 5 reviews are never
skippable. This review was the right path forward; surfaced 2 plan
amendments + 1 latent bug worth documenting + 1 reviewer-misreading
worth pinning so the trail is clear. Material outside-look value.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 05:36:12 +00:00
claude-noether 3e996d09e2 iter1 Phase 4: plan — contract clauses, diff scope, Phase 7 harness
Phase 4 plan for the iter1 MPEG-2 fix, structured per the
feedback_dev_process.md Phase 6 contract-before-code worked example
(0012-h264-omit-scaling-matrix-frame-based.patch shape):
contract clauses with citations first, then code changes mapping
1:1 to clauses.

Phase 1 criterion #3 re-locked per Phase 3 → Phase 1 loopback:

  Original: "mpv --hwdec=vaapi-copy ... engages backend"
  Adjusted: "ffmpeg -hwaccel vaapi ... engages backend"

  Phase 3 Baseline A established mpv silently filters MPEG-2 out
  before libva is loaded; the original wording was unfalsifiable.
  ffmpeg-direct exercises the path. mpv-driven testing → separate
  follow-up task.

Other 4 criteria unchanged (vainfo regression, vaCreateConfig
SUCCESS, DMA-BUF GL pixel verify HW=SW at +02s, T4 H.264
regression).

Six contract clauses cited from authoritative sources:

  Clause 1 — Three split controls in one batched VIDIOC_S_EXT_CTRLS
    Authority: linux/v4l2-controls.h:1988-2105
    Reference impl: FFmpeg libavcodec/v4l2_request_mpeg2.c:130-155
    Empirical anchor: Phase 3 Baseline C verbatim payload

  Clause 2 — v4l2_ctrl_mpeg2_sequence layout (12 bytes)
    Authority: linux/v4l2-controls.h:2009-2017
    Field-by-field VAAPI source mapping table
    Note: progressive_frame is used as proxy for progressive_sequence
          (VAAPI doesn't expose the latter; same bit for BBB).

  Clause 3 — v4l2_ctrl_mpeg2_picture layout (32 bytes)
    Authority: linux/v4l2-controls.h:2056-2065
    reserved[5] MUST be zeroed (kernel doc 2052)
    8 picture flags decoded; field-by-field VAAPI mapping

  Clause 4 — v4l2_ctrl_mpeg2_quantisation layout (256 bytes)
    Authority: linux/v4l2-controls.h:2089-2096
    Matrices in zigzag scanning order; no permutation in libva backend
    (kernel hantro_mpeg2_dec_copy_qtable handles zigzag-to-raster)
    Decision: when iqmatrix_set is false, populate from MPEG-2 spec
    defaults (ISO/IEC 13818-2 Table 7-3) to avoid kernel rejecting
    a batch missing the QUANTISATION control.

  Clause 5 — Per-frame submission via v4l2_set_controls
    Authority: existing src/h264.c:986 pattern
    surface_object->request_fd binds controls to per-surface request

  Clause 6 — config.c MPEG-2 case must break;
    Authority: C semantics; H.264 case shape at config.c:62-63
    Empirical anchor: Phase 3 Baseline B confirmed scratch-fix shape.

Diff scope:

  src/config.c    — 3 lines added (break for MPEG-2 cases) + drop
                    stale #include <mpeg2-ctrls.h>
  src/mpeg2.c     — full rewrite of mpeg2_set_controls against new
                    split API; ~120 lines replaced; switches from
                    2× v4l2_set_control(single) to 1× batched
                    v4l2_set_controls(3-control array)
  include/mpeg2-ctrls.h — DELETE (staging-era, masks kernel UAPI)
  src/picture.c, src/context.c, meson.build — no changes
                    (verified Phase 2 + Phase 3)

Phase 6 implementation order (3 logical commits):

  Commit A: config.c break — substrate fix in isolation
  Commit B: mpeg2.c rewrite + drop mpeg2-ctrls.h includes
  Commit C: delete include/mpeg2-ctrls.h

Phase 7 verification harness (full Bash incantations included in
plan body):

  Criterion 1: vainfo MPEG-2 enumeration regression check
  Criterion 2: vaCreateConfig SUCCESS via libva trace
  Criterion 3: ffmpeg -hwaccel vaapi exit 0, no Failed-to-create
  Criterion 4: mpv --hwdec=vaapi --vo=image at +02s seek; HW=SW
               byte-identical hashes for 2 distinct frames
               (fallback to ffmpeg hwdownload if mpv-vaapi also
               filters MPEG-2; criterion holds, harness adapts)
  Criterion 5: T4 H.264 hashes still f623d5f7... and 7d7bc6f2...
  Bonus: byte-compare post-fix S_EXT_CTRLS payload vs Baseline C

Pre-identified Phase 7 → Phase 4 loopback triggers:

  1. S_EXT_CTRLS EINVAL post-fix → check pic.reserved[5] memset,
     struct sizes, flag value collisions
  2. Pixel hash mismatch → check f_code packing, field/frame
     interpretation, ref timestamps, IQ matrix order
  3. mpv-vaapi filters MPEG-2 out (same as -copy) → fall-forward
     to ffmpeg hwdownload pixel verify (criterion holds, harness
     adapts; do not redefine criterion)
  4. H.264 regression → re-locate the offending change in Bug 1
  5. Header deletion breaks unaudited consumer → git grep audit

Out of scope (LOCKED): HEVC/VP9/VP8 (later iterations); vaDerive
Image cache-stale fix; chromium-fourier 149 install; perf metrics;
long-duration stress; other MPEG-2 containers; mpv-hwdec follow-up;
context.c H.264 device-init EINVAL (auxiliary, intentional);
profile/chroma/progressive_sequence refinement; upstream engagement.

Phase 5 entry: artifacts handover (no summary, raw bundle) per
feedback_dev_process.md — phase0_findings_iter1.md,
phase2_iter1_situation.md, phase3_iter1_baseline.md,
phase4_iter1_plan.md, plus phase0_evidence/2026-05-07/iter1_phase3/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 04:38:53 +00:00
claude-noether b9625af278 iter1 Phase 3: baseline measurements — Phase 2 confirmed empirically
Four Phase 3 baselines captured on fresnel post-reboot 2026-05-08
00:39 CEST. SDDM watchpoint condition stayed green (greeter passed
cleanly on the new boot). All four baselines confirm Phase 2's
situation analysis empirically; one Phase 1 criterion needs minor
adjustment (Phase 3 → Phase 1 loopback per feedback_dev_process.md).

Baseline A — pre-patch failure mode (master tip 65969da):

  ffmpeg -hwaccel vaapi -i bbb_720p10s_mpeg2.ts ... under strace +
  LIBVA_TRACE captures the chain:

  vaInitialize ret = SUCCESS
  vaQueryConfigProfiles ret = SUCCESS
  vaCreateConfig(profile=VAProfileMPEG2Main, entrypoint=VLD)
    ret = VA_STATUS_ERROR_UNSUPPORTED_PROFILE

  No V4L2 ioctls beyond ENUM_FMT probes from RequestQueryConfigProfiles.
  Confirms Phase 2 Bug 1 (config.c:55-69 fall-through to default).

Baseline B — post Bug 1 scratch patch (the missing break added):

  vaCreateConfig now returns SUCCESS. V4L2 setup proceeds:
  CREATE_BUFS, QUERYBUF (40), REQBUFS, STREAMON, S_FMT, etc.
  Then VIDIOC_S_EXT_CTRLS fails:

    ioctl(/dev/video5, VIDIOC_S_EXT_CTRLS,
          {ctrl_class=0xf010000,
           count=1,
           controls=[
             {id=V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
              size=56, ...}
           ]})
        = -1 EINVAL

  CID 0x9909fa (V4L2_CID_MPEG_BASE+250) doesn't exist on this kernel —
  mainline removed it in favor of the split V4L2_CID_STATELESS_MPEG2_*
  CIDs. Size 56 = sizeof(combined v4l2_ctrl_mpeg2_slice_params) from
  the fork's local include/mpeg2-ctrls.h. Confirms Phase 2 Bug 2.

  Auxiliary EINVAL: src/context.c:142-155 unconditionally sets H.264
  device-wide controls (H264_DECODE_MODE, H264_START_CODE) on every
  CreateContext, regardless of profile. EINVALs on hantro-vpu-dec
  (no H.264 controls there). Intentional best-effort behavior —
  return value is cast to (void) and discarded. Auxiliary, not iter1
  scope.

Baseline C — cross-validator verbatim contract anchor:

  ffmpeg -hwaccel v4l2request strace shows ONE batched call per frame:

    ioctl(/dev/video5, VIDIOC_S_EXT_CTRLS,
          {ctrl_class=0xf010000,    // V4L2_CTRL_CLASS_CODEC_STATELESS
           count=3,
           controls=[
             {id=0xa409dc, size=12,  ...},   // SEQUENCE
             {id=0xa409dd, size=32,  ...},   // PICTURE
             {id=0xa409de, size=256, ...}    // QUANTISATION
           ]}) = 0

  Field-by-field decode of frame 1 (I-picture):
    SEQUENCE: 1280×720, vbv=0x151800, profile_level=0,
              chroma_format=1, flags=PROGRESSIVE
    PICTURE: back/fwd_ref_ts=0/0, flags=0x82
             (FRAME_PRED_DCT|PROGRESSIVE), f_code=0xF×4 (I-frame
             default), P_C_T=1 (I), structure=3 (FRAME),
             intra_dc_precision=0
    QUANTISATION: starts [8, 16, 16, 19, 16, 19, 22, 22, ...] —
                  canonical MPEG-2 default intra matrix in zigzag
                  scanning order.

  Frame 2 (P-picture) shows real f_code values {{1,1},{15,15}}
  and forward_ref_ts pointing to frame 1's timestamp. Confirms
  Phase 2's claim that matrices arrive in zigzag order;
  no permutation needed in the libva backend (kernel's
  hantro_mpeg2_dec_copy_qtable handles zigzag-to-raster).

  This is the iter1 contract anchor: every Phase 4 implementation
  diff must produce a structurally indistinguishable
  VIDIOC_S_EXT_CTRLS call.

Baseline D — H.264 regression check (Phase 1 criterion #5):

  T4 reference hashes match exactly with scratch Bug 1 fix installed:
    HW frame 1: f623d5f7a41697f67dd227275c6f1b21ffc257f65626d32fde8229357f8764c9
    SW frame 1: f623d5f7a41697f67dd227275c6f1b21ffc257f65626d32fde8229357f8764c9
    HW frame 2: 7d7bc6f2146dda8b2d223bba622c4b9fbe9674181ff1e02afe286b620342e0a8
    SW frame 2: 7d7bc6f2146dda8b2d223bba622c4b9fbe9674181ff1e02afe286b620342e0a8

  Bug 1 fix in isolation does not regress H.264.

Phase 1 criterion #3 needs adjustment (Phase 3 → Phase 1 loopback):

  Original wording: "mpv --hwdec=vaapi-copy ... engages the backend"
  Reality: mpv-vaapi-copy never loads libva for MPEG-2. mpv's hwdec
  policy filters MPEG-2 out before libva is touched. Zero V4L2
  ioctls, zero libva trace, silent SW fallback. Independent of
  Bug 1 fix state.

  Adjusted criterion #3 (proposed; locks alongside Phase 4 plan):
    "ffmpeg -hwaccel vaapi -i bbb_720p10s_mpeg2.ts -frames:v 2
     -f null - shows vaCreateConfig SUCCESS, no Failed to create
     decode configuration lines, no EINVAL from VIDIOC_S_EXT_CTRLS,
     exits 0 cleanly."

  mpv-driven testing moves to a follow-up task (mpv hwdec-codecs
  filter override), separate from iter1.

Other 4 Phase 1 criteria (vainfo regression, vaCreateConfig SUCCESS,
DMA-BUF GL pixel verify HW=SW, T4 H.264 regression) hold as locked.

Scratch state cleanup: scratch patch reverted, master backend
reinstalled, MPEG-2 fails again with vaCreateConfig=12 — back to
Baseline A state, no leak.

Phase 4 plan inputs:

  - Diff scope: src/config.c (1 break), src/mpeg2.c (rewrite to
    new API), include/mpeg2-ctrls.h (delete or empty). picture.c
    + context.c unchanged.
  - Contract anchor: cite verbatim from
    linux/v4l2-controls.h:1985-2105, FFmpeg
    libavcodec/v4l2_request_mpeg2.c:130-155, kernel
    drivers/media/platform/verisilicon/hantro_mpeg2.c, AND this
    document's Baseline C verbatim payload.
  - Phase 7 verification: re-run all 5 Phase 1 criteria
    (with #3 adjusted), byte-by-byte compare post-fix
    VIDIOC_S_EXT_CTRLS payload against Baseline C.

Evidence files:

  Tracked (text):
    phase3_iter1_baseline.md (writeup with verbatim raw output)
    phase0_evidence/2026-05-07/iter1_phase3/baseline_A_ffmpeg/ffmpeg.stdout
    phase0_evidence/2026-05-07/iter1_phase3/baseline_B_postbug1/ffmpeg.stdout
    phase0_evidence/2026-05-07/iter1_phase3/baseline_C_xvalidator/ffmpeg.stdout

  Gitignored (regenerable from re-run incantations in the writeup):
    *.strace.*  *.txt (ftrace) libva.trace.* (added the latter pattern)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 04:04:25 +00:00
claude-noether cc55a6e60a iter1 Phase 2: situation analysis — three bugs in MPEG-2 path
Phase 2 source-read of the libva-v4l2-request-fourier MPEG-2 path
on master tip 65969da identifies three independent bugs, all in
the libva backend (kernel + driver path proven solid by Phase 0
cross-validator sweep).

Bug 1 — fall-through to default in RequestCreateConfig
(src/config.c:55-69):

  case VAProfileH264*:
      // FIXME
      break;
  case VAProfileMPEG2Simple:
  case VAProfileMPEG2Main:
  case VAProfileHEVCMain:
  default:
      return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;

H.264 cases have a break, MPEG-2 + HEVC fall through to default.
This explains the vaCreateConfig: 12 (UNSUPPORTED_PROFILE) error
observed in Phase 0 cross-validator sweep for both codecs.

Likely history: H.264 was libva-multiplanar focus iter1-iter5;
the FIXME comment suggests profile-specific validation logic was
expected but never landed. MPEG-2 stayed in fall-through bucket.

Fix shape: add break for MPEG-2 cases. HEVC stays in fall-through
(h265.c excluded from build per Phase 0 finding F-C; honest
UNSUPPORTED_PROFILE is correct until h265.c is reinstated in a
later iteration).

Bug 2 — staging-era UAPI in mpeg2.c; mainline kernel removed it:

src/mpeg2.c uses:
  V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS  (V4L2_CID_MPEG_BASE+250 = 0x9909fa)
  V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION  (V4L2_CID_MPEG_BASE+251 = 0x9909fb)

Mainline kernel UAPI (include/uapi/linux/v4l2-controls.h:1985-2105):
  V4L2_CID_STATELESS_MPEG2_SEQUENCE      (CODEC_STATELESS_BASE+220 = 0xa409dc)
  V4L2_CID_STATELESS_MPEG2_PICTURE       (CODEC_STATELESS_BASE+221 = 0xa409dd)
  V4L2_CID_STATELESS_MPEG2_QUANTISATION  (CODEC_STATELESS_BASE+222 = 0xa409de)

Fresnel V4L2 inventory confirms kernel exposes the new IDs only.
The fork's local include/mpeg2-ctrls.h is the staging-era header
that masks the kernel's modern definitions.

Six structural changes from old to new API:

1. Slice header parsing moved to kernel — bit_size, data_bit_offset,
   quantiser_scale_code GONE from new structs.
2. Reference timestamps moved from slice to picture
   (forward_ref_ts, backward_ref_ts now in v4l2_ctrl_mpeg2_picture).
3. Boolean fields collapsed into v4l2_ctrl_mpeg2_picture.flags
   bitmask (TOP_FIELD_FIRST, FRAME_PRED_DCT, CONCEALMENT_MV,
   Q_SCALE_TYPE, INTRA_VLC, ALT_SCAN, REPEAT_FIRST, PROGRESSIVE).
4. progressive_sequence collapsed into
   v4l2_ctrl_mpeg2_sequence.flags & V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE.
5. PICTURE_CODING_TYPE renamed to PIC_CODING_TYPE
   (V4L2_MPEG2_PICTURE_CODING_TYPE_X → V4L2_MPEG2_PIC_CODING_TYPE_X).
6. Quantisation load_* flags removed; matrices always present;
   British spelling — quantiSation not quantiZation.

Quantisation matrix order: kernel doc says zigzag scanning order;
VAAPI VAIQMatrixBufferMPEG2 also stores in zigzag scanning order;
direct memcpy works. Kernel hantro_mpeg2.c does the
zigzag-to-raster permutation kernel-side
(hantro_mpeg2_dec_copy_qtable lines 12-26). No userspace
permutation needed in the libva backend (unlike FFmpeg, which
unwinds its internal idsp.idct_permutation order).

Per-frame submission: FFmpeg reference (libavcodec/
v4l2_request_mpeg2.c:130-155) batches 3 controls in single
VIDIOC_S_EXT_CTRLS. Backend's v4l2_set_controls (src/v4l2.c:475)
already supports batching — used by iter6/7/8 H.264
(src/h264.c:986). MPEG-2 rewrite follows H.264's batched pattern.

Bug 3 — include/mpeg2-ctrls.h is the staging-era local header:

The fork's local include/mpeg2-ctrls.h is the staging-era header
that defines the old (removed) API. config.c:37 + mpeg2.c:38
include it via meson's include_directories('../include'). Should
be deleted (or emptied); rely on kernel <linux/v4l2-controls.h>
pulled transitively via <linux/videodev2.h>.

Things verified NOT to be bugs:

- src/picture.c MPEG-2 dispatch is fully wired:
  - codec_store_buffer handles VAPictureParameterBuffer + VAIQMatrix
  - codec_set_controls dispatches MPEG-2 to mpeg2_set_controls
  - HEVC explicitly UNSUPPORTED_PROFILE (correct for build state)
- src/picture.c:287 unconditional h264.matrix_set=false reset is
  benign for MPEG-2 (union aliasing puts it in mpeg2.picture or
  .slice region; RenderPicture overwrites that byte before
  mpeg2_set_controls reads anything).
- src/mpeg2.c field extraction from VAAPI structs is sound; only
  the destination control IDs and struct shape need rewiring.
- src/v4l2.c batching API (v4l2_set_controls) is in place.

Open questions tabled for Phase 3 baseline:

1. Live ftrace of failing libva MPEG-2 attempt post Bug-1-fix
   (verify expected EINVAL on VIDIOC_S_EXT_CTRLS for old CID).
2. VAAPI VAIQMatrixBufferMPEG2 matrix order from real mpv decode
   (verify zigzag, no pre-permutation).
3. Cross-reference verbatim VIDIOC_S_EXT_CTRLS payload from
   ffmpeg-v4l2request cross-validator anchor strace dump.
4. SDDM watchpoint resolution — fresnel SSH No route to host at
   Phase 2 start (network event, SDDM regression, or operator
   power-state). Resolve before Phase 3.

Predicted iter1 outcome: small mechanical diff (config.c break
+ mpeg2.c rewrite + drop local mpeg2-ctrls.h). Phase 7 verification
should land all 5 Phase 1 boolean checks green on first or second
try. Likely Phase 7 → Phase 4 loopback triggers if any: forgotten
struct padding zero, garbage timestamps on first I-frame, or
device-state precondition we missed in hantro_mpeg2.c.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 22:24:50 +00:00
claude-noether f720c7784b iter1 Phase 0 + Phase 1 lock: MPEG-2 boolean correctness on hantro
Iteration 1 of the campaign 8(+1)-phase loop opens following the
campaign Phase 0 close (b74551b). Per the suggested order in
phase0_evidence/2026-05-07/cross_validator_traces.md, iter1 attacks
MPEG-2 — the cheapest fix in the codec status sweep (mpeg2.c is
already compiled, src/config.c has the case statements, but
vaCreateConfig returns 12 / UNSUPPORTED_PROFILE).

Locked research question:

  Make MPEG-2 the second codec to pass boolean-correctness on
  fresnel via the libva-v4l2-request-fourier path —
  mpv --hwdec=vaapi-copy bbb_720p10s_mpeg2.ts engages the backend
  cleanly and DMA-BUF GL import yields HW pixels byte-identical
  to a software-decoded reference for the same frames.

Phase 1 success criterion (5 boolean checks, all must be green):

  1. vainfo: VAProfileMPEG2Simple + VAProfileMPEG2Main still
     enumerated on the hantro env binding (regression check).
  2. vaCreateConfig(VAProfileMPEG2Main, VLD): VA_STATUS_SUCCESS.
  3. mpv --hwdec=vaapi-copy --frames=2 --vo=null on
     bbb_720p10s_mpeg2.ts: engages backend, exit 0, no
     "Failed to create decode configuration" lines.
  4. mpv --hwdec=vaapi --vo=image (DMA-BUF GL import) at +02s
     seek: 2 distinct frames hash-equal to SW reference frames
     and hash-differ from each other.
  5. T4 H.264 regression: re-run T4 incantation, hashes match
     f623d5f7... and 7d7bc6f2... reference values.

Mechanism the question targets:

The kernel + driver path is solid (cross_validator_traces.md —
ffmpeg-v4l2request decodes the same fixture exit 0). vaCreateConfig
rejection must be downstream of src/config.c:64-65's case match
(both VAProfileMPEG2Simple and VAProfileMPEG2Main are present in
the validation switch) but upstream of return-success. Plausible
suspects for Phase 2 source-read:

  - V4L2 capability probe (e.g., VIDIOC_TRY_FMT against MG2S) that
    fails because the libva backend was bound to /dev/video5 but
    is checking format against the wrong codec list.
  - Device-discovery routing reaches a default-reject because
    bound device didn't match an expected codec-to-device map.
  - media_request allocation step fails on /dev/media2 for some
    MPEG-2-specific reason.
  - iter6/iter7 regression in the dispatch-by-profile path that
    broke MPEG-2 silently because nobody on libva-multiplanar
    tested it (iter5 close: "MPEG-2 was iter1 backlog, dropped
    at iter6 close because A55 CPU handles it fine" — fresnel
    runs A53 so the disposition doesn't transfer).

Phase 4 plan must cite the contract before patching, per
feedback_dev_process.md Phase 6 contract-before-code: read kernel
drivers/media/platform/verisilicon/hantro_mpeg2.c, read FFmpeg
downstream libavcodec/v4l2_request_mpeg2.c, state the MPEG-2
control-submission contract explicitly before any code lands.

Predecessor carry-over (state vs data) explicit per
feedback_dev_process.md Phase 0 + feedback_replicate_baseline_first.md:

  Carries forward (re-verified in campaign Phase 0):
    - iter8 master fork (65969da) installed on fresnel,
      vainfo enumeration confirmed
    - bbb_720p10s_mpeg2.ts fixture (5.3 MB, MPEG-2 Main, 720p,
      10s, MPEG-TS) on fresnel ~/fourier-test/, provenance
      documented in test_fixtures.md
    - hantro-vpu-dec /dev/video5 + /dev/media2 binding
    - Cross-validator anchor: ffmpeg-v4l2request mpeg2 trace
      captured (5 S_EXT_CTRLS, 4 REQUEST_ALLOC, 4 DMA_BUF_SYNC)
    - T4 reference hashes for H.264 regression check

  Does NOT carry forward (re-acquire if needed):
    - ohm/RK3568 hantro MPEG-2 behaviour — different kernel
      driver variant inside drivers/media/platform/verisilicon/
    - Pre-iter6 libva-multiplanar MPEG-2 trace data (untested
      at iter6 close)

  Open questions inherited:
    - Cache-stale vaDeriveImage bug class on RK3399 (T4) —
      iter1 uses DMA-BUF GL import for verify; Phase 4 cross-
      cutting fix is not iter1-scoped
    - Architectural divergence ffmpeg vs our backend (EXPBUF +
      DMA_BUF_SYNC vs cap_pool + vaDeriveImage) — Phase 4
      design decision, not iter1-blocking

Out-of-scope (LOCKED): HEVC/VP9/VP8 (later iterations); vaDerive
Image cache-stale fix (Phase 4 cross-cutting); chromium-fourier
149 install (Phase 0 follow-up to iter1 substrate, non-gating);
performance metrics (Phase 1+ separate iteration); long-duration
stress (>10s); other MPEG-2 containers beyond MPEG-TS;
upstream engagement.

Iter1 Phase 2 source-read targets:
  - src/config.c::RequestCreateConfig (rejection site)
  - src/picture.c MPEG-2 dispatch path
  - src/mpeg2.c set-controls path
  - kernel drivers/media/platform/verisilicon/hantro_mpeg2.c
  - FFmpeg downstream libavcodec/v4l2_request_mpeg2.c

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 22:04:52 +00:00
claude-noether b74551bc56 phase 0 close: deliverables 5 + 6 — fixtures + cross-validator anchor
Closes Phase 0 for fresnel-fourier. Per-codec test fixtures and
cross-validator contract traces complete the campaign-locked
boolean-correctness baseline.

Deliverable #5 — per-codec test fixtures (test_fixtures.md):

Generated 4 new fixtures on fresnel from the bbb_1080p30_h264.mp4
master via stock ffmpeg (libx265 ultrafast, libvpx-vp9 speed 5,
mpeg2video, libvpx vp8). All 720p 10s 8-bit yuv420p — matching the
silicon-supported profile/pixfmt for each codec on RK3399:

  bbb_720p10s_hevc.mp4   620 KB  (HEVC Main, rkvdec target)
  bbb_720p10s_vp9.webm   3.4 MB  (VP9 Profile 0, rkvdec target)
  bbb_720p10s_mpeg2.ts   5.3 MB  (MPEG-2 Main, hantro-vpu-dec target)
  bbb_720p10s_vp8.webm   2.4 MB  (VP8, hantro-vpu-dec target)

Encode wall times on fresnel: HEVC 13s, VP9 93s, MPEG-2 6s, VP8 26s.
H.264 master is 725 MB carryover from libva-multiplanar / fourier_attribution.

Deliverable #6 — cross-validator anchor (cross_validator_traces.md):

phase0_findings.md named chromium-fourier 149 as the cross-validator;
that package isn't installed on fresnel and marfrit-packages isn't
configured (no auto-install path tonight). Substituted ffmpeg
-hwaccel v4l2request as a better-fit cross-validator: it's an
independent V4L2 client (uses no libva at all, lives in
libavcodec/v4l2_request*.c), already on the box (stock
ffmpeg n8.1-13-gb57fbbe50c, the Kwiboo v4l2-request-n8.1 branch),
and implements all 5 codecs the campaign locked.

Headline finding: ALL 5 CODECS WORK end-to-end via the kernel
direct path on RK3399.

  ffmpeg -hwaccel v4l2request -i bbb_<codec>.<ext> -frames:v 2 -f null -
  H.264:  exit 0
  HEVC:   exit 0
  VP9:    exit 0
  MPEG-2: exit 0
  VP8:    exit 0

The Linux kernel + rkvdec + hantro-vpu drivers are solid for the
entire campaign codec scope. Phase 6 work scope is purely libva-
backend code — no kernel patches, no upstream Linux engagement.

Per-codec libva (iter8) vs ffmpeg-v4l2request status sweep:

  H.264   libva: PASS (T4 PASS + bit-exact pixel verify) | ffmpeg-v4l2req: PASS
  HEVC    libva: vaCreateConfig=12 (UNSUPPORTED_PROFILE) | ffmpeg-v4l2req: PASS
          → src/h265.c is excluded in src/meson.build but src/config.c:151
            enumerates HEVCMain via V4L2_PIX_FMT_HEVC_SLICE probe;
            vaCreateConfig fails downstream of the case match.
  VP9     libva: profile not enumerated                  | ffmpeg-v4l2req: PASS
          → no vp9.c in fork
  MPEG-2  libva: vaCreateConfig=12 (UNSUPPORTED_PROFILE) | ffmpeg-v4l2req: PASS
          → mpeg2.c IS compiled, config.c:64-65 has the case statements,
            yet vaCreateConfig rejects. Phase 2 source-read needed.
  VP8     libva: profile not enumerated                  | ffmpeg-v4l2req: PASS
          → no vp8.c in fork

Suggested Phase 6 iteration order (subject to Phase 1 lock):
  iter1: MPEG-2 — likely cheapest (config.c-level path; mpeg2.c
                  already compiled)
  iter2: HEVC   — re-enable h265.c in build, audit against rkvdec
  iter3: VP8    — implement vp8.c on hantro
  iter4: VP9    — implement vp9.c on rkvdec (largest control surface)

Per-codec ioctl frequency anchor (2-frame ffmpeg -hwaccel v4l2request):

  ioctl                  H.264 HEVC  VP9  MPEG-2 VP8
  VIDIOC_DQBUF              45   49   40    26   49
  VIDIOC_QBUF               22   24   20    10   20
  VIDIOC_CREATE_BUFS        17   17   17    12   17
  VIDIOC_QUERYBUF           15   15   15    10   15
  VIDIOC_S_EXT_CTRLS        13   14   11     5   10
  VIDIOC_EXPBUF             11   11   11     6   11
  VIDIOC_QUERY_EXT_CTRL      0    5    0     0    0
  MEDIA_IOC_REQUEST_ALLOC    4    4    4     4    4
  DMA_BUF_IOCTL_SYNC         0    0    0     4    0
  MEDIA_REQUEST_IOC_REINIT   0    0    0     0    3

Architectural divergence ffmpeg-v4l2request vs libva-v4l2-request-fourier:

  - ffmpeg uses VIDIOC_EXPBUF + DMA-BUF for downstream readback.
    Our libva backend uses cached mmap via vaDeriveImage — the
    iter1 patch-0011 cache-stale bug class. Phase 4 work item
    consistent with T4's finding: adding VIDIOC_EXPBUF + DMA-BUF-
    backed image export to the libva backend would fix the
    cache-coherency issue identified in T4's H.264 readback.
  - ffmpeg uses 4 request_fds pooled. Our backend uses 16 (iter6
    per-OUTPUT-slot binding). Both valid; different pool depth.
  - HEVC alone needs VIDIOC_QUERY_EXT_CTRL for hevc_slice_params
    dynamic-array introspection — unique among the 5 codecs.

Substrate change deferred (not a Phase 0 blocker): chromium-fourier
149 install on fresnel is Phase 1+ work. When done, a follow-up
trace pass per codec will cross-check ffmpeg-v4l2request and
chromium contracts. For Phase 0 baseline, ffmpeg-v4l2request is
the anchor.

Phase 0 fully closed. Six deliverables landed. Phase 1 lock can proceed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 21:52:21 +00:00
claude-noether d8a9903ef4 phase 0 deliverable 4: H.264 baseline trace — PASS boolean correctness
H.264 hardware decode on RK3399 / rkvdec / libva-v4l2-request-fourier
@ master tip 65969da (iter8 Phase 4) verified bit-exact correct against
software reference, when read via the cache-safe DMA-BUF GL import path.

Test method:

  - mpv --hwdec=vaapi --vo=image (DMA-BUF + EGL_EXT_image_dma_buf_import
    + glReadPixels + JPEG encode — cache-coherency-safe per the iter1
    patch-0011 lesson).
  - Decoded 2 frames at +30s seek (mid-content bunny motion, not BBB
    intro fade-in) so size + content variation is genuine.
  - Compared HW JPEGs vs SW reference JPEGs (same mpv invocation with
    --hwdec=no).

Result:

  HW frame 1 sha256 = f623d5f7...  (651,726 bytes)  byte-identical
  SW frame 1 sha256 = f623d5f7...  (651,726 bytes)  to SW reference
  HW frame 2 sha256 = 7d7bc6f2...  (630,433 bytes)  byte-identical
  SW frame 2 sha256 = 7d7bc6f2...  (630,433 bytes)  to SW reference

  Frames 1 vs 2 differ in size — real content change captured.

Phase 0 boolean-correctness criterion for H.264: PASS.

Contract trace:

The V4L2 + media-request ioctl sequence per H.264 frame is the
canonical iter6/iter7 pattern:

  S_EXT_CTRLS (CODEC_STATELESS class, request_fd=N)
  QBUF CAPTURE_MPLANE  index=K
  QBUF OUTPUT_MPLANE   index=K  (compressed slice)
  MEDIA_REQUEST_IOC_QUEUE   (request_fd=N)
  MEDIA_REQUEST_IOC_REINIT  (request_fd=N)  ← per-OUTPUT-slot reuse
  DQBUF OUTPUT_MPLANE  index=K
  DQBUF CAPTURE_MPLANE index=K

REINIT-before-DQBUF works because the kernel completes decode in
~0.6 ms (request → COMPLETE state), and mainline media_request_
ioctl_reinit accepts both IDLE and COMPLETE. iter7 cap_pool
instantiates 24 slots cleanly: "v4l2-request: cap_pool_init: 24
slots ready" in mpv stdout.

No EINVAL, no EBUSY, no errors observed across 5 frames. iter4's
frame-11 EINVAL bug from libva-multiplanar does not reproduce on
RK3399 in this short window (longer-run repro is Phase 1+ work).

Side finding — cache-stale readback bug present in libva-backend's
vaDeriveImage path on RK3399:

When pixels are read via the cached-mmap path (libva's vaDeriveImage
+ vaMapBuffer, used by ffmpeg -hwaccel vaapi -hwaccel_output_format
nv12), readback is corrupted in exactly the iter1 patch-0011 pattern:

  size=6,220,800 bytes (correct: 2 × 1920×1080×1.5 NV12)
  non-zero=544 (0.009%)
  pattern: 16 consecutive non-zero bytes at every 1920-byte row stride,
           rest of buffer reads as zero
  diff vs SW reference: 100% of bytes differ, MAE=53.3 per byte

This is the canonical stale-cached-mmap pattern. Kernel writes real
pixels (proven by DMA-BUF GL import readback succeeding), but the
libva backend's image-export path returns a cached pointer without
the correct cache-invalidation incantation. Userspace reads stale
all-zero memory punctuated by whichever cache lines happened to fetch
post-write.

Phase 4 work item: audit whether the iter1 patch-0011 cache-flush
fix is present, effective, or RK3399-routing-bypassed. Three
possibilities: (a) fix landed for RK3568 but cache topology differs
on RK3399, (b) fix is gated on something that's not true on RK3399,
or (c) RK3399 V4L2_MEMORY_MMAP page protection bypasses the flush.
Not gating Phase 0 — kernel-side decode is correct.

Phase 1+ binding cells must use the DMA-BUF GL import path for pixel
verification, not vaDeriveImage / cached-mmap. The iter1 lesson
restated: cached-mmap readback is unreliable on this hardware family.

Evidence files (under phase0_evidence/2026-05-07/h264_baseline_trace.md
and h264_baseline/):

  - mpv.stdout — libva log, vaapi-copy engaged, cap_pool_init
  - h264_baseline_trace.md — full writeup with re-run incantations
  - mpv.strace.* (gitignored) — 19 per-thread ioctl/openat traces
  - ftrace_v4l2.txt (gitignored) — kernel qbuf/dqbuf events
  - merged_ioctls.tsv (gitignored) — time-sorted V4L2/MEDIA/DRM
    ioctls across all threads
  - *.jpg (gitignored) — HW vs SW JPEG comparison artefacts
  - frames_hw_cached_readback.nv12 (gitignored) — broken nv12
    readback for forensic reference

gitignore: extended extension list (jpg, png, nv12, yuv, tsv, strace*).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 21:32:36 +00:00
claude-noether 60e62da666 phase 0 corrections: hantro RK3399 has no H.264; substrate is iter8 master
Two empirical corrections to the morning-of-2026-05-07 phase 0 lock,
based on V4L2 inventory + iter8 fork build smoke captured this evening
on fresnel (kernel 6.19.9-99-eos-arm).

Correction 1 — hantro-vpu-dec on RK3399 does not advertise H.264.

phase0_findings.md morning lock claimed both rkvdec (/dev/video3)
and hantro-vpu-dec (/dev/video5) advertise H.264. Empirical
v4l2-ctl --list-formats-out shows hantro-vpu-dec exposes only
MG2S (MPEG-2) and VP8F (VP8) — no S264. Likely carryover from
RK3568 (ohm) hantro, which does support H.264; the RK3399 hantro
kernel variant in drivers/media/platform/verisilicon/ registers
a different codec list. Fix:

  - README.md hardware-target table: drop "+ H.264" from Decoder
    block 2.
  - README.md decode-side surface-area paragraph: note hantro is
    MPEG-2 + VP8 only and that there is exactly one bind for H.264
    (rkvdec).
  - phase0_findings.md mechanism table: drop H.264 from /dev/video5
    row; correct DT compatible to rockchip,rk3399-vpu (the actual
    parent device compatible — sysfs reports rockchip,rk3399-vpu,
    not rockchip,rk3399-vpu-dec which is just the v4l2 card type
    string).
  - phase0_findings.md "H.264 lands on both blocks" sentence:
    inverted to "H.264 lands only on rkvdec".
  - phase0_findings.md Open Question #2 (two-block H.264 routing):
    marked RESOLVED 2026-05-07 evening (null). Single bind, no
    routing decision, one test cell per codec.

Empirical evidence: phase0_evidence/2026-05-07/v4l2_inventory_findings.md
(distilled from v4l2_inventory.txt — the latter is gitignored as
raw data, regenerable via the v4l2-ctl invocation documented in
the findings file).

Correction 2 — substrate is iter8 master (65969da), not iter5-end.

phase0_findings.md morning lock framed the substrate as "iter5-end
fork." That was true on 2026-05-05 (iter5 close); between then and
the 2026-05-07 fresnel-fourier scaffold libva-multiplanar continued
through iter6 (per-OUTPUT-slot REINIT request_fd binding), iter7
(slot-leak fix, cap_pool harness, msync verify harness, OUTPUT-pool
teardown), and iter8 (perf binding cell harness, RK3566/3568 doc
fix). Building from master tip 65969da inherits all the iter6-iter8
hardening at zero cost. Fix:

  - phase0_findings.md substrate paragraph: strikethrough the
    "iter5-end" framing, add corrected paragraph naming master
    tip 65969da and listing what iter6/7/8 added.
  - phase0_findings.md top-of-doc: add an "Empirical corrections
    2026-05-07 evening" callout linking to the evidence files,
    so a reader spotting the locked-vs-corrected mismatch knows
    where the empirical update came from.

Empirical evidence: phase0_evidence/2026-05-07/iter8_build_smoke.md
(clean build, vainfo profile enumeration, HEVC anomaly write-up).

What's preserved on purpose:

The strikethrough rendering in phase0_findings.md keeps the original
locked text visible alongside the correction — campaign convention
treats locks as historical record, not editable state. A reader
landing on the file from a deep link sees both the morning's
intent and the evening's empirical update. Git history has the
clean diff if anyone wants the original without strikethrough.

What's not changed:

The codec scope in the locked research question stays correct in
count — five codecs (H.264 + HEVC + VP9 + MPEG-2 + VP8). The
routing table changes (H.264 → rkvdec only; MPEG-2 → hantro only;
no shared block) but the boolean-correctness pass/fail criterion
per codec is unaffected. Phase 1 lock can proceed on the corrected
map without re-opening scope.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:57:40 +00:00
claude-noether e83298f0da phase 0 deliverables 1-3: SDDM watchpoint, V4L2 inventory, iter8 fork smoke
Three Phase 0 deliverables, three findings worth flagging.

Deliverable #1 — SDDM recovery (phase0_recovery_2026-05-07.md):

Closed as watchpoint, not as root-caused fix. Greeter is green on
this boot — mfritsche has been in Plasma Wayland on tty1 since 20:32.
The "Process crashed (exit code 1)" in journalctl -u sddm is the
post-login greeter teardown, not the pre-login crash described in
~/.claude/plans/dynamic-forging-piglet.md. No coredumps, no qFatal
strings. No package changed since the 2026-04-28 Syyuu; the only
difference between the failing boot and this one is a reboot —
likely a flaky panfrost/GBM cold-init that happened to succeed.
Plan procedures + /var/cache/pacman/pkg rollback candidates remain
ready if regression fires.

Deliverable #2 — V4L2 inventory (phase0_evidence/2026-05-07/
v4l2_inventory_findings.md, raw capture in v4l2_inventory.txt
which is gitignored as raw data):

Full v4l2-ctl --all + --list-ctrls-menus + --list-formats-out per
node, plus media-ctl topology, plus DT compatibles. Authoritative
codec map on running kernel 6.19.9-99-eos-arm:

  /dev/video3 (rkvdec, rockchip,rk3399-vdec):
    OUTPUT_MPLANE: S265 (HEVC), S264 (H.264), VP9F (VP9)
    CAPTURE_MPLANE: NV12

  /dev/video5 (hantro-vpu-dec, rockchip,rk3399-vpu):
    OUTPUT_MPLANE: MG2S (MPEG-2), VP8F (VP8)
    CAPTURE_MPLANE: NV12

This contradicts phase0_findings.md (and README.md), which both
claim hantro-vpu-dec on RK3399 also does H.264. It does not on
this kernel. Open Question #2 from phase0_findings.md ("two-block
H.264 routing") is null on RK3399. Correction commit follows.

Deliverable #3 — iter8 fork build + vainfo (phase0_evidence/
2026-05-07/iter8_build_smoke.md):

Built libva-v4l2-request-fourier master tip 65969da on fresnel
directly (no distcc per locked precedent), gcc 15.2.1, meson 1.11.1,
ninja 1.13.2, libva 1.23.0, libdrm 2.4.131. Clean build, 302 KB
.so, two harmless v4l2.h forward-decl warnings. Installed to
/usr/lib/dri/v4l2_request_drv_video.so. vainfo enumerates:

  rkvdec bind: H.264 {Main, High, ConstrainedBaseline, MultiviewHigh,
                      StereoHigh}, HEVCMain
  hantro-vpu-dec bind: MPEG-2 {Simple, Main}

Substrate is iter8 master, not iter5 as the campaign docs frame —
libva-multiplanar continued past iter5 into iter6-iter8 between the
2026-05-05 iter5 close and the 2026-05-07 fresnel-fourier scaffold.
Building from master inherits per-OUTPUT-slot REINIT, slot-leak
fix, cap_pool harness, msync verify harness, OUTPUT-pool teardown.
Correction commit follows.

HEVC anomaly worth flagging: src/config.c:146-151 probes
V4L2_PIX_FMT_HEVC_SLICE before adding VAProfileHEVCMain. rkvdec
advertises S265 so the probe succeeds; HEVCMain gets enumerated.
But src/meson.build excludes h265.c from the build. A consumer
that calls vaCreateConfig(VAProfileHEVCMain) will succeed (config.c
validation list includes HEVCMain) but actual decode will fault
at dispatch since no h265 symbols are linked. Phase 4 decision:
re-enable h265.c, gate enumeration on a compile-time #ifdef, or
strip enumeration honestly.

Per-codec routing confirmed one-env-var-per-process: request.c:149
reads LIBVA_V4L2_REQUEST_VIDEO_PATH once at init. A single backend
instance binds to either rkvdec or hantro-vpu-dec, not both. Phase 4
will need either a wrapper-script-per-consumer hack or a backend
probe-loop change to route by VAProfile across both decode nodes.

Build infrastructure (gitignore):

Switched from blanket phase*_evidence/ exclude to extension-based
allow-list — track narrative .md, ignore raw .txt/.log/.trace/.pcap/
.bin/.gz/.zst/.json/.dat/.ftrace/.strace. Keeps the V4L2 inventory
text untracked (reproducible from the v4l2-ctl invocation) while
preserving the findings narrative in-repo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:54:38 +00:00
marfrit c9a96cbb38 fresnel-fourier campaign scaffold: peer to libva-multiplanar, RK3399 target
Roll out libva-v4l2-request-fourier on fresnel (Pinebook Pro / RK3399)
with broader codec scope than ohm-side libva-multiplanar:

- H.264 + HEVC + VP9 via the rkvdec block (/dev/video3)
- MPEG-2 + VP8 via the hantro-vpu-dec block (/dev/video5)

Topology: peer campaign, independent 8(+1) loop. fresnel-fourier
results do not gate libva-multiplanar Phase 8 closes. Code-side work
in the shared fork (../libva-multiplanar/libva-v4l2-request-fourier/)
lands per Phase 2 source-read of each iteration.

Phase 0 task 1: recover fresnel from the SDDM greeter crash-loop
(per ~/.claude/plans/dynamic-forging-piglet.md). Recovery is bookkept
inside this campaign's Phase 0, not as an out-of-band prereq.

Verified 2026-05-07 via SSH:
- linux-eos-arm 6.19.9-99 has CONFIG_FTRACE=y + CONFIG_FUNCTION_TRACER=y
  + CONFIG_DYNAMIC_FTRACE=y + CONFIG_TRACING=y. /sys/kernel/tracing/
  populated. No kernel rebuild needed for trace work.
- /dev/video3 = rkvdec (NV12 capture, MPLANE).
- /dev/video5 = hantro-vpu, card type rockchip,rk3399-vpu-dec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:11:04 +00:00