Files
punktfunk/crates/pf-vkdecode/tests/data/lowdelay-640x480.nv12.sha256
enricobuehler 834b244301 fix(client): the H.264 twin was real — every low-delay picture decoded into a surface it predicted from
The AV1 review round flagged the H.264 leg as "plausibly the same defect, traced in
source, not reproduced" and deliberately did not touch it. It is reproduced now, and
it is worse than the AV1 one: it fires on 297 of 300 access units of every stream a
punktfunk host emits, at 720p, 1080p and 2160p alike, on BOTH the DXVA rung and the
Vulkan one.

**Decided on the CPU, no GPU needed.** `H264Planner` snapshots `dpb_refs` in
`begin_picture`, BEFORE `finish_picture` runs 8.2.5's marking and C.4.5.3's bump, so a
picture the sliding window unmarks and the bump then evicts lands in both `dpb_refs`
(which `RefFrameList` is built from) and `dpb.removed`. The conversion released the
whole `removed` list and then assigned the decode target a slot; `SlotMap::assign`
takes the lowest free slot, which is the one just vacated. `CurrPic = N` and
`RefFrameList[k] = N`, in one submission.

The two conditions have to coincide in ONE access unit, and low-delay H.264 is exactly
what makes them: `max_num_reorder_frames = 0` means the evicted picture has already
been output, which is what makes it evictable at all. NVENC seals it by writing
`max_num_ref_frames = 3` ALONGSIDE `max_dec_frame_buffering = 3` — a DPB exactly as
deep as its reference count — so the window unmarks the oldest reference in the very
unit whose bump drops it. The aliased picture is `ref_idx 2` of a three-entry
`num_ref_idx_l0_active` list: addressable by any macroblock, not a spare.

**Why two hardware-proven codecs and four GPUs never saw it.** `test-25fps.h264` is
level 1.3 with no VUI `bitstream_restriction`, so `dpb_limit` falls back to A.3.1's
level ceiling and gives a 7-frame DPB against 2 reference frames — the window unmarks
two units before the bump can evict — and it REORDERS, which keeps an unmarked picture
alive past the unit that unmarked it. Two independent reasons, both properties of that
vector rather than of H.264. It measured zero and passed 250/250 throughout.
`data/lowdelay-640x480.h264` is vendored to close exactly that: our own host's output,
120 pictures, goldens from libavcodec cross-checked bit-identical across two ffmpeg
builds on two architectures.

**The fix is the AV1 fix.** `DecodePlanDxva` and `DecodePlanVk` grow
`release_after_decode`, the conversions hand the removals back instead of applying
them, and the callers release them once the decode op is issued. It costs no slot the
map does not have: `SlotMap::new` allocates `max_dpb_frames + 1` and the DPB never
exceeds `max_dpb_frames`, so a free slot always exists with the whole `removed` list
still held — measured, peak 4 of 4 on the stream that defers on 117 of 120 units.

The Vulkan rung breaks on it in both DPB modes and neither loudly: DISTINCT hands the
aliased reference the same array layer the setup writes; COINCIDE clears
`slot_image[setup]` in the binding sync and the reference then resolves to no bound
image, dropping out of `pReferenceSlots` with a `trace!`. Its deferred release runs on
the FAILURE paths too — the fallible region's Result is held rather than `?`-ed,
because seven exits sat between the conversion and the release and each would have
leaked a slot.

`a_full_dpb_bump_reuses_the_slot_but_the_pool_model_binds_a_fresh_image` asserted the
aliasing as "the planner's normal behaviour": an authored depth-1 stream whose AU1
references the picture it evicts. It now asserts the opposite, which is the defect in
two lines.

New evidence, all of it runnable: the CPU proof pins BOTH numbers (0 on the vector,
117 of 120 on the low-delay stream) so neither can drift silently; the ledger-pressure
test measures the peak; and a low-delay parity leg is added to `pf-vkdecode`'s
`gpu_parity` and `pf-client-core`'s `video_d3d11_native::parity` so both rungs are held
to what they stream rather than only to what they conform to.
2026-08-07 22:09:44 +02:00

150 lines
9.3 KiB
Plaintext

# SHA-256 per decoded frame of lowdelay-640x480.h264, DISPLAY order — 120 frames.
# Each frame is the full 640x480 picture as tightly packed NV12:
# Y plane 640*480 bytes, then interleaved UV 640*240 bytes = 460800 bytes/frame.
#
# THE STREAM IS OURS, not a conformance vector, and that is the point of it.
# `punktfunk-host spike` on .21 (NVENC, RTX 5070 Ti, driver 610.57.04), 2026-08-07:
#
# punktfunk-host spike --source synthetic --codec h264 --width 640 --height 480 \
# --fps 60 --seconds 2 --bitrate 1 --no-loopback --out lowdelay-640x480.h264
#
# It is LOW-DELAY IPPP: one IDR, no B pictures, `max_num_reorder_frames = 0`, so a
# picture is output the moment it decodes. Its SPS says `max_num_ref_frames = 3` AND
# `max_dec_frame_buffering = 3` — the DPB is exactly as deep as the reference count,
# which is what makes 8.2.5's sliding window unmark a picture in the same access unit
# that the C.4.5.3 bump evicts it. `test-25fps.h264` cannot reach that shape (level
# 1.3, no VUI bitstream_restriction, so a level-derived DPB of 7 against 2 reference
# frames) and REORDERS besides, which is why it measured zero aliasing while every
# stream this program actually ships aliased on 99% of its frames.
#
# Goldens from libavcodec's SOFTWARE decoder, the same ground truth the vendored
# vectors' goldens use (H.264 decoding is exactly specified, so every conformant
# decoder is bit-identical):
#
# ffmpeg -i lowdelay-640x480.h264 -f rawvideo -pix_fmt nv12 \
# -fps_mode passthrough ref.yuv
# # then split ref.yuv into 460800-byte frames and sha256 each
#
# ffmpeg version n8.1.2 (Arch/CachyOS, gcc 16, x86_64) — cross-checked BIT-IDENTICAL
# against ffmpeg 8.1.1 on macOS arm64, all 120 frames. 120 of 120 digests distinct.
be912b67b89d720b4e9403bde4c52f0e4414571e3323e4b5312ff5dc26309dd3
87115b7a352e95baec35ad8bbbe45af5ac6c691264291c9c904e4d01c2e6f911
03ad701f6c1c4421ad6f8396ed24b893c275d245cf93d24a4f7cf59f9c74675a
faee80c2c494b009b6bab7d9e6d6cb5ccf0921cfa1bdba0d83479b19d2a6f012
a01b6234ff0bf5c222a0de7b574075f7dec5fc4ea3ccb6657941c791251c6242
d0befc0eb1e018b671dea55d74009ef1d09cdcba392ecd8509ec000aae91fe1d
f15c273a6077f73296edf4e245069299c034e4a3f4dea10006d9bbf29f8f4220
5e08336bba0a20ffd3efb8659424af9b76da0252c0cd5f1ccfcdbe92612bafc9
a8bff0f9921ae301c17e83885760e3e085845732f8d48c4a0fd70f591e3043af
dd90da5b869d1026fba4e41cfba059b8e75fca383bd1ab76c493a82271e1141b
e9237c44040f78e453129daf71afe5e24a640a67524b1c8460c9efaac8eb4795
fed123e00f51dab09a4b9964bd289c9db95b6a83564d35a5a5e3d5ac2ab8f371
d7f2db0a52f5a0d835ca9d7d74ec30da29b36bba94b30c10058715c505e26cd9
25ac9facc9d25c85d0d30864985a0fcad635bd7e65e4773a03e620cbd510ea97
6d6558eb98c4fc4c8a3dfe9e9eefd744b3cf66f66c6f09c40afbaad272f3f16d
678cadfadfd980eac5aa8ca83eeff2112249262cc4747fac49ecba49a8fbbd42
031d73796c6f2b9589bc1443937f77156d52aeb602fc7fbc7ec34f02e1ba33ba
59f26c57bade55876dc4ef17070a703cb5585f059f8db7a477a752e731830615
783d10022eb2f8749f7130954b899c74ad950fb98305a8b0f83ef5a78f38207b
e8d8ce42e46c4121be8a270d2bb30c98a3d11bee7808dcacbdb19e9318e66989
0b2fb3507e886953ab801e03a63715e6a6a26088de9fc809a56f454e1e2da069
8bc350ca94eb356c1bd2f221d482eb6e6cdc6e132366236c8ec4b1a41289a01f
dd0f472b9c78ce5b2b4fa2a2354c46090f208fefb12af0440e9a18a2d61b3167
08bceb5c011632733cc14edf01c301fa4ffe2ba5ee30424f518a23c908db7168
142b77142fa169ebd231308b0f3162eedeac66bfecb60eb9493abe16bcccaffa
c1dec8e1876afb17d0881c6df6e32e5ee1d8d931f3bbccb079f3ba44380721a0
e26bc6604826dd69d778ec77d0d3823a797faf32f838f3e13aceca3af15ddecb
bc7b93e2a39d2102539587d3aa96c4aaa58a13050a881bd4f9ced1411bca3a48
f41bfc62cce822129d65952cbcee15345e5a5fbc529acffdb223851a6f24fdce
3d3b23a6f161580f2f82382c01901ebe0345194d33e07981c50d4cfe0f39bf02
6e86c11618e37e770667245a679d359fe4a2f42c2a31ccbdc8eac2ee1a299fcd
9083b8c5455f513ed558954892e43b2b18c90928aa7a098ff49f4eff153ede34
9037d398f4e7cf295ad3bb43069c6a2fa96769c9b20617c9bebd1f34ccb1be3d
a333ed7ba7c7403b9b3a548e1a5f1669218ad85e47f90d69308eb037b4729330
aabbb4aa194537e260d5a11603fd1a9ef704d784b4d0ea592f7bea6d2a23af17
a46f730e965d4e39a3120ea43cb02ac94342073b1cf1e473e8d43c49b0cffae4
259d098d3f53248e889beff1517e4ca88aed4e3803b4ea4923d348c8109f5ac9
3fc9bc21d3420726606a5534c6516b1ea0cc2140392e0bec2855a45f6f090b82
2f3cebf32859649c29b1665c766fec4dbdbff2003e64be9e4720971d9b6ae2f1
f756e4459576a5aeb4c260c9a6c8e115e43ec97a64bfe74fe128f03c3c61b9a1
d6e101889565951515168958141a23950eb25637dd5202d55d24885eae4e1b42
1402b95affc25769e00d8ef30eeb0a831bacc41649246e48a46bac1c362ef3a2
7c838e5d2f191908e2d488185d209fe51c29a50e822ceb1a1f22b6eb6f28fcbf
ba39e5f0936af9706d9718390d03713a235b57102904e2a3972e67ff11b30800
cfe7b79981886bf74c50957f30b1a98bc4a064e2b41f8fb3996b0a3e15d132ba
47a02c20be1d34caa0a0d406a12d4970dbf642085442663070a8ae942323eb1e
495c75b4d163828750d0e828243bcbff08354418dfd2d43c5d1fd93c3bf691a7
5ed8d82a1aad0f27066028b4b1058d29f0b9ed5f424f378315ef18c883fe9fc2
85a9bcb2df1feb0053fc707028df68e9fcf3aed326ec2438ad111dc264aa69bd
b8247ee3d57539fe80bee41669a8a4c6955fd1e374b33cdfe6a6ad9fbb7d9fcb
bcc0a47694f3074d1c7b812f9d00c3eb57f98ee981d8acd7cb504bbaa04275f2
c5ca305e54f839a7e6f46d3280c17d81f5b3507310bec9a7fa2dae6a151fafd9
f5807f97f81927b2226395fc27a5d91eef56732916d9e78f65eb485fc4b846ee
3b9d1302b30c11e91eab92eedfcc9dad71a0382488808acc851589740f01498f
619f4862e224fe000acb4edb645fbdaf9e2784e4917e4e3c994052df123c701c
dcabed23f10e192e6103c032f6049adc2e30379f5f71e62489008cfc905f4953
85dac7f9dfe772670adb9087edc3825c201bd1dcfef412243e26317f5115c6d1
3518fc0bd4ee33d08976a51f23215960a16bee54e4abd09612c2012c6c716431
9e0761070df35ed19fc09b8795d66db6021142b99f69f549561390b61ac0a134
52f92a9c0c2cd9803077ca9a5ee88fe455cd8dd17c8fdba99638200c0a63014f
afe7313b2073231a6c2db4ee749b49f5f0af3105631a77f2b8b27fac0d430430
c09fde16b28b07291c8e35392a755e05875a4d2f83fbfc91c03ab4cfe7d2e39f
0bf84907d5bf24b62c17fb6f5747c410caecdeb39b5fb2449e1b2cd61b9ddddc
dcf0d031d689f362e04e29bfc2ebdd079fce9fab6624285b2da6e2acff61d1e0
25bee66822c1dfbac341f6a8b4e91f6463cd44ef24403823040810d4cb9d35c9
ec06e17bc3d2377b92c9c738964797a4fa6dc13645a1b0b563957a373f62e997
81e49365823b69f1dadd84a0fcb07e0e21e573664f5dc3f4e3cb3ef5b70b1bb3
cf7a344c4bbd78d334131dc0e9c4cadb7e4ba1540a16fae268652cc81cda3ef0
03b9528d2ab09525e80257938bbed9fc4c8f50308e1aefc368c1702557882134
05a20b533ab2a7345f2f7ca4c51974b5594779fc173dd405e5361f70bc28aff4
f77cceadf8138be43e272695706573b3476215d788365b2e0f9deb881cade818
35d39e923d98550ed36dec9836896c784bd7c8eb38bf78c4f1490579cab16d0f
95e721bd96198c40d37ef9c9c1ffb4473800367c81dab7170cf70e92ff8e0d70
448d2db0f09244f85d7f851218d16e80b06bcba0ec2fc7e53e4bd1ab6a55b565
9e1d141ad0231a0c67767758cbce6dbc9fb40aa4b68af9b533cff1adf5b205e9
2af66d2f3158c7da06854f881a9212bf6d4ed09dcc4d32c9e12ef3d8a1f9d28e
20760574c8c569d998e606d72eae71f8f705be80c383ef91deb71f4b0a45024e
9e0df9a3771307e7ce09b9efe4a4ea4a648d744f32816d614909b82c0c150e3b
47e3350d8dbb2012a9f92870c100e8e97cb16f519746c4f7e6afc3e0731cb05c
54ff346f3517b007cea9cebcdfc11b77e488b6ee86b1593a6b275f018ed7024e
8f7fe4882777cc53ca1c3af01b4321a584119eb431114c441a9f275c16e0adf6
ea08117dc667e86f3d99bec9fe7a76f5d6f675cb9d95bfa9d5e0e5ccaa498655
73dfddf6c6722d6a6d7db0220bbc823aa121fc75ed6be74b05549bfa527748af
e9fadef92b639b39dea8303926a63ac6aceb8ca83daf49c7a7018d0fb9e195a8
26eaeb1b0e2b5e9f2e88422c74bfaf162b2e3345cc6283096f96bbb23c88a59b
73dad6fffd397e25e122c01760b9b18f7cfb4d8bc53bd5f49168f6a91b9ac25f
3b28a8cbd94de49716240e43c3354c508222c888c7e86b645302924b630b7b82
c860ad68336e11d9f41cea92bc62f8016e1edb36240fce059743800bd31140fb
2843fef676d2600c81228dc2c4578f9de17004f22d0bb17ba4afc78f9adb22f2
9b01be7e851cbe311b14a5f904d94451cc467fe903aac8d4ed5b127967f02e47
1e583c1c8018d869e73d88dadb65bd6b69b294e7b32b12158a77e43005d59717
31f6da73506a565ec7bfb116086a4499992e357c96b2449c53e0b21624c579b9
d2dce5507ffef26cefcfb4efb3c4abbba4f4d7b02288a75b7243e12889ca08f6
b89bddfc2b94a40086a8169c4790352668e0365640cdd9cfc8f8256a8cd67a76
5d1f8f7562f1c0e7bcef9ba025b79c68bb0651b5d2039802f3489ca194e5b1f0
b7928b410e299e00bd69691f656b64de1598ac680effa3a6cc1456fc625544d0
02334e28175693b207b50e7ced14110afa8a8335fd22d00b2c4dc4f6d8a3480b
a290bf65e6d5fc843ccdb4e33f4b53ffa7d17363c324ce0fe91fc5c59bbf7fc3
191b54c810f0d694f457e4575d8c306f113fd6443dbbb0a403abb36e04381355
a1be53163c757fefe4bacf3b4c295cacf6d54e467a3a41bd1718bb5552efb0d9
cd151dbb675f5f25e34d08db74c9d6f203e9c7fc0fbe662bc8054c2d9c11a4d6
3c3f77e544b8d21eed0f4f39c68ce5804e3affaaa7188f53c193b040a44afc68
dba6ef4a4eb5cc89ee9dfe2161a0f727da6fc65aa646837a20601af9b57dfc70
639c0d1145a5cad6f18a21205d83b2ba1c48fd027efce0fed5477e5d89b3e4b8
353223c07d88e11081a886257460c8ff1b7ad8c957a567e43994cc9f2f08dc2b
0f0871d1f2c12f7b76a486da9d194b53756fddce56321aba2c2c16c8740bb377
343ffd487e7c1da166d6fe1acebaa1d2ef89fe0fc16d6ad108a3813a0f8c3206
625a4e45280b2028a0ca85e806ef4d716664a377fd6e4e0bfaf8cfe2fce2e6b3
4c4617317e3cfc2369faccc1b6bc5826a7dd92f8b06552fd6fcd2aebedcfb9dd
738c656ffd4e8e0a902c4da9cd7cb19316f0d4aa9f0aaa68c1353f7965abaa6b
ede77993572a017e4dee8a8abc14c6446eed4369385265e18a810afd32e8b3d8
3029c3cec839a7edfefd05a692cb25b50f029a10710aeef7791307fed8ca4203
325b6248633ee801e4c0d695f54fd0dbd6dddb61848daf92f74d9895d15923fa
3688c307fe659d4a178ac08afd7cdaa787abe55498aa537e8bd670a63088b3d0
c4372ea5bfb4003d1b2208a7eaa48259ed48ed41ba5cc930639b5ecd89d45fd8
4f335634ca6bbfe265197ae86b6ac3fb66dc2aefe8451f135fc8dc211dfe4baa
f1126e7188550c0e5d1da828d942ec48f1e0fc5963303ee3f28fa1e3b3c64ab7
27b8cb0963d22c67584ac2acfe0afa74328958617d6ca0287b772101cb7091ba
52c6865d58ec4b891ff3e6489475463f9807f2b4f25e60af439e52a04c0f2601
193dd2b43319b131d821dc554da172b1d36858838c6a88f1f8b747026a7e814e