Files
punktfunk/crates/pf-client-core
enricobuehler f4dda9074b feat(dxvadec): the AV1 picparams harness AV1 forgot, and the D3D11VA AV1 rung is promoted
Two halves.

**The harness.** `libav_picparams_parity` covered H.264 and HEVC only, which is
exactly the gap that let a wrong AV1 submission ship. It now plans, converts and
packs all 274 frames of the vendored AV1 vector and checks what needs no capture:
the three-buffer descriptor set with no quantization matrix (AV1's matrices are
selected by index, so `dxva2_av1_end_frame` passes NULL/0 and there is no buffer
to submit), no macroblock count anywhere, the 912-byte picture-parameter buffer,
and the tile records — which unlike H.264/HEVC slice records do NOT abut, because
a `DXVA_Tile_AV1` addresses a tile PAYLOAD and consecutive payloads are separated
by their `tile_size_minus_1` fields.

The one that matters most is `no_av1_submission_names_its_decode_surface_in_the_
reference_store`: the invariant the previous commit fixed, over the submitted
BYTES rather than over the plan. libavcodec cannot produce that shape — it fills
`RefFrameMapTextureIndex` from the pre-refresh store and takes
`CurrPicTextureIndex` from a frame the reference update has not run on — which is
the argument for calling it a defect rather than a convention.

`AV1_FIELDS` reaches into the eight nested blocks (`tiles.widths`,
`segmentation.feature_data`, …) so a future capture reports a field and not "260
bytes of tiles differ"; `field_table!` grew nested-path support for it. The
`#[ignore]`d `our_av1_picture_parameters_match_libavcodecs` and the capture recipe
are in place, and `the_dump_and_the_parser_agree…` now self-compares AV1 too.

⚠ NO libavcodec AV1 capture was taken and the module docs say so rather than
leaving an absent result to be read as a pass: `.221` has no MSYS2, no gcc and no
make, so a patched FFmpeg there is a toolchain bring-up, not a build. Everything
this file claims about libavcodec's AV1 side is READ out of `dxva2_av1.c` (n8.1).
That reading did turn up one live divergence, recorded at `pic_av1.rs`'s
`pp.width` and deliberately NOT changed: libavcodec sends `avctx->width`, which is
FrameWidth (pre-superres), where this crate sends UpscaledWidth. The two are equal
whenever superres is off, which is every stream that exists here, so the 250/250
result says nothing either way and a blind change would be unmeasured.

**The promotion.** `(D3d11va, CODEC_AV1)` is `verified` — 250/250 delivered frames
bit-identical to libavcodec on an RTX 3500 Ada AND an Intel Arc. All three places
move together: the evidence arm, the module table and
`every_rung_runs_and_the_unproven_ones_are_named`, whose `unproven` array loses the
pair and whose proven list gains it.

⚠ This changes rung SELECTION, not just a label. `verified` is what lets `auto`
pick D3D11VA ahead of Vulkan Video, so Windows Intel and unknown-vendor boxes —
where the ladder is `native-d3d11va → native-vk → sw` — now decode AV1 on D3D11VA
where they previously fell to Vulkan. Taken deliberately: ~10x the Vulkan leg's
speed, and the parity that promoted it was measured on an Intel Arc, which is the
vendor family the change moves. Still no soak on the goldens, and the notes say so.

Also: `frame_av1` holds the decode's `Result` instead of `?`-ing it, so both slot
releases run on the failure path. `decode_av1` notes an error and keeps the
session rather than rebuilding the slot map, so an early return leaked a surface
per failed frame and hit `SlotError::Full` after nine.
2026-08-07 21:07:23 +02:00
..