MEM4: decode into the planes of evicted frames

With MEM1-MEM3 twelve clips on a timeline still took 5.1 GB, only 2.5 GB of
it live: each decoded picture allocated three planes, each eviction freed
them, and the system allocator kept the freed pages.

filmcraft_frame::pool keeps the planes of frames the GOP caches evict (up to
192 MiB per sample type; a frame something else still holds is left alone).
The H.264 decoder, through a plane allocator hook that keeps the crate free
of dependencies, and the VideoToolbox path take their output planes from it.

perf.stats reports decode.planePoolMB and decode.planesReused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
justjohn12345
2026-10-05 16:57:16 -04:00
co-authored by Claude Opus 5.5
parent b999b69f07
commit 4f3e119ac2
10 changed files with 296 additions and 9 deletions
+12
View File
@@ -43,6 +43,18 @@ to a 12 GB footprint, 10.8 GB of it live heap in three piles.
memory appeared in no counter (`frames.cache` covers the frame server's rendered images and
GPU plans only).
4. **Freed planes the allocator keeps (2.5 GB), MEM4.** With MEM1–MEM3 the same twelve clips took
5.1 GB, only 2.5 GB of it live: every decoded picture allocated three planes and every
eviction freed them, and the system allocator kept the freed pages (`footprint`: 1.7 GB
reclaimable). `filmcraft_frame::pool` now keeps the planes of evicted frames (up to 192 MiB per
sample type; a frame something else still holds is left alone) and the H.264 decoder and the
VideoToolbox path decode into them, so steady-state decoding allocates no planes.
`perf.stats` reports `decode.planePoolMB` and `decode.planesReused`.
The same session showed that the desktop app never used hardware decoding: `register()` was an
argument of a `log::info!` that no logger evaluated (fixed under HW1; `decode.hardware.sessions`
was 0 with every frame decoded in software).
What remains per live decoder is unchanged: the H.264 decoder publishes each macroblock row of a
picture as its own allocations (`Frame::make_row`, five per row), which is where the 290 MB per
decoder comes from.