fa2bcd9dbb82dcf602cf7479f837310cf1c2fb87
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
96fc3eca10 |
test(vkdecode): the AV1 rung finally has pixels to answer to
A parity and smoke harness for AV1, mirroring the H.264 and H.265 legs that proved those rungs bit-identical to libavcodec on four drivers before either ran on glass. This was the milestone's largest test gap: the adversarial review found four blocking defects in the AV1 conversion — flags unset on 274 frames of 274, a units error in LoopRestorationSize, per-reference info describing the wrong picture, film-grain fields left zero — and every one of them would have shown on frame 1 of a parity run, while clippy and 164 green unit tests said nothing at all. The golden is 250 per-frame SHA-256s in DISPLAY order, not 274. The vector carries 274 coded frames in 250 temporal units; the 24 extras are hidden ALTREFs, decoded and referenced but never shown, and the rung delivers what dpb.outputs names. The count is re-derived from the planner rather than assumed. Cross-checked between ffmpeg 8.1.1 on macOS arm64 and 8.0.1 on Linux x86_64, whose raw outputs are byte-identical — and then against a third party neither build knows about: the vendored vector ships upstream's own per-frame MD5s, and re-running those reproduces all 250. The golden agrees with a decode nobody in this program performed. I reproduced both independently before committing. 8-bit NV12, traced from the sequence header rather than presumed (seq_profile 0, high_bitdepth 0, mono_chrome 0), so the P010 scar does not apply here — and the header says which check to make if a Main 10 golden is ever added. film_grain_params_present is 0, which is load-bearing: grain synthesis is part of the Vulkan decode profile, so this golden is only comparable against a grain-less profile key. Anti-vacuity is the point of the exercise, so it is structural. The golden guard asserts the exact count, that every line is a bare digest, and that all entries are DISTINCT — 250 copies of one digest would let a decoder frozen on a single frame pass parity. The parity body asserts the golden set and the access-unit count before it touches hardware, so an IVF reader returning nothing cannot become "0 frames compared, pass". The agent verified the guards fire by mutating the golden three ways. assert_bit_identical now names the FIRST divergent frame, which is what localises a defect; that improves all six legs, not just AV1. AV1 has no four-byte-start-code twin, deliberately: OBUs are length-delimited, so there is no prefix for a driver to mis-skip. Documented where a reader would otherwise see an omission. Nothing here has run on a GPU. The harness exists precisely so the four review defects can be answered by measurement instead of argument. |
||
|
|
5d0b269e58 |
test(vkdecode): parity over the start-code form the host actually emits
Both vendored vectors carry three-byte Annex-B start codes throughout. The real host emits four-byte ones on 100% of access units in both codecs — 1514/1514 H.264 and 1133/1133 HEVC, measured off the M0 NVENC corpus through the capture hook's own .idx offsets. So every parity verdict this program has recorded was taken on a prefix form that never ships, and the one form that does ship was exercised by nothing. That gap is not hypothetical. Submitting four-byte start codes to vkCmdDecodeVideoKHR unchanged is exactly what made HEVC unplayable on every driver tested: drivers are validated on the three-byte form, and a fixed +3 + 2 skip into a four-byte-prefixed slice reads a nonsense pps_id — the 115 and 119 both NVIDIAs printed. H.264 was never safe here by structure, only by its vendored encoder's convention, which is why the cure lives in the shared ring layer and why this coverage is generic over both codecs. Each codec's parity body now takes its access units as a parameter and runs twice: once over the vector as it sits, once over the same vector rewritten to four-byte prefixes. Prefix width carries no information, so both runs must reproduce the same goldens — sharing one body is what makes that an equality rather than two assertions that can drift. The rewrite copies nalu.data[nalu.offset..], the same nal_size bytes the parser hands the planner, so trailing_zero_8bits are dropped exactly where the production parser drops them: the only difference between the two streams is the width of every prefix. Two CPU guards keep the new legs from passing vacuously, which is the failure mode they are most exposed to — a rewrite that quietly returned its input would make them trivially green and nothing on the fleet would notice. They assert the original really does carry three-byte prefixes, that the rewritten stream carries none, that the NAL count is preserved exactly, and that the planner still yields 250 pictures. Hardware: all four legs 250/250 bit-identical to libavcodec on two independent driver stacks — AMD VanGogh on RADV/Mesa 26.0-devel (the Steam Deck) and NVIDIA 610.43.03 on Linux. NVIDIA is the family that rejected the four-byte form outright, so it is the meaningful witness for this regression. |
||
|
|
5c6b09a5c5 |
test(vkdecode): the HEVC GPU legs, which find M3 broken on every driver
M3 was recorded as code complete. Its exit criteria named the HEVC gpu_smoke and gpu_parity legs, and the goldens for them were committed — 250 per-frame NV12 hashes, cross-checked between two independent FFmpeg builds, with a header saying they are "consumed the same way by the HEVC parity test". No such test existed. Both GPU files were H.264 only, with zero references to h265, so nothing had ever decoded a single HEVC frame through this crate on hardware. They exist now, and the first run answered. On AMD Adrenalin 25.10.30.02 (distinct mode, queryResultStatusSupport=false) 247 of 250 frames diverge from libavcodec, and that device's smoke leg PASSES — because smoke only reads the driver's verdict and that driver reports none. That is the Ally X class, reproduced in-house on demand: output that is wrong everywhere the picture is looked at and clean everywhere the decoder is asked. Both NVIDIA drivers reject the stream outright and name the cause themselves, "Invalid PPS/SPS id in slice header (pps_id=119 / 115)" — the identical two values, and the smoke leg dies at the identical AU 9, on a 4090 under 610.88 on Windows and on an RTX 5070 Ti under 610.43.03 on Linux. Same wrong values, same access unit, two GPU generations, two operating systems: deterministic, and therefore ours rather than any driver's. It is not an ordering fault. Five of the divergent hashes appear nowhere in the 250 goldens, so the pixels are wrong rather than correct-but-reordered. Parity dies at frame 1 while smoke dies at AU 9 only because smoke holds four frames before it looks; the first inter-predicted picture is already corrupt. The legs are committed ahead of the fix deliberately. They are the regression test for the defect, they are #[ignore]d so no CI leg changes colour, and the evidence above is worth recording in the order it was obtained. Adding a third and fourth copy of ~150 lines of unsafe Vulkan bring-up was not acceptable, so it moved to tests/common. The two behavioural differences between the callers are now named parameters rather than accidents: the parity legs read back on a graphics queue and require one, while the smoke legs accept a decode-only device and fall back to the decode family — which also decides whether pool images are EXCLUSIVE or CONCURRENT, so it is load-bearing rather than cosmetic. H.264 came through the refactor unchanged, verified two ways: argument-by-argument against the previous file, and on hardware, still 250/250 bit-identical on NVIDIA Windows, AMD Windows and now NVIDIA Linux. The loader is deliberately leaked at teardown. ash::Entry owns the Arc<Library>, so dropping it unloads the Vulkan loader with every ICD and implicit layer; harmless while each binary held one GPU leg, but each now holds two, and the second would re-open a loader the first had torn down. Three guards run without a GPU, because everything above is #[ignore]d: the golden file's count and digest shape, the HEVC access-unit split agreeing with what the CPU planner emits (with iraps == 1 pinning "no CRA anywhere", so a re-synced vector that opens with one fails here rather than as a frame-count mismatch on the fleet), the vector staying Main 4:2:0 8-bit since both legs hard-code that probe, and a refusal to run the smoke legs with PF_VKD_TEST_READBACK set, which would quietly grow the pool a usage flag production never carries. |