mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-14 14:41:15 +00:00
dfbd4a8e82bb653cdd101ed4e1a17f8cf3bfc46c
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
db21c733b4 |
Auto: a frame's ticket ends it on every exit
AutoPick::ticket chooses a side and reports the frame's time once; dropped without one it ends the frame unmeasured. The viewer's frames, the renderer's top-level frames and frames rendered in passes use it, so an Auto CPU frame turned away by GPU admission (#3028), a cancelled export frame or any later exit no longer leaves its frame counted as running. The frame server keeps its choice across calls and still ends a replaced frame itself. |
||
|
|
08362b9c04 |
GPU: free effect working textures after each call instead of at frame end (#1523)
* GPU: free effect working textures after each call instead of at frame end A GPU frame keeps its encoder open while the CPU renderer runs layers with GPU effects (Gpu::effects -> run_chain). Each call's Enc handed its textures back to the shared pool, where they waited for every open encoder, so all effect intermediates of a frame stayed allocated until the frame ended (17.7 GB by layer 17 of a heavy 4K comp, then OOM). Effect calls now borrow a pool owner (Enc::lent) that is given back once the call's work is submitted or discarded; its kept textures are trimmed to the pool budget, so the rest are freed after each call. * GPU: one pool budget for idle effect calls, trimmed at the end of a render Review of #1523: each idle lent owner kept up to POOL_BUDGET of textures of its own, outside the shared accounting, and there were as many idle owners as effect calls ever ran at once (16 frame threads: ~12 GB after a 4K render). Giving a lent owner back now moves its kept textures to the shared free list, so one POOL_BUDGET bounds what the free list and every finished effect call keep. They skip Pool::release's wait for open encoders: only the lent Enc recorded work on them, and that work is submitted or discarded. Each lend is a fresh owner id, so a lease that outlives its call (an image handed to another encoder) is released through Pool::release; this does not rely on the result being read back. Accelerator::render_end (called when an export ends) drops the kept textures. * GPU: evict the pool's oldest free textures, guard escaped leases Review of #1523 (follow-up to 0a884fb6): - Pool::make_free rejected a texture when the free list was full and never evicted, so once sizes that no longer occur (per-frame blur bounds, padded layer sizes) filled the budget, every later free was a drop and every take an allocation. It now evicts the least recently freed textures until the new one fits. - A lease read by another Enc (dispatch, copy, readback, display) or handed to a cache is marked escaped and always released through the guarded Pool::release, so a lent call can no longer reuse a texture that a still open encoder reads. - Docs: POOL_BUDGET caps the free list only; textures waiting for open encoders and those of live Encs are outside it. - export_async calls render_end from a drop guard, so the pool is also trimmed when an export panics or its future is dropped. - Tests use a private context with its own pool budget instead of a global override; new tests for stale sizes and an image read by an open encoder. * GPU: evict only stale pool sizes, count evicted textures until the GPU frees them Evicting the least recently freed texture for every newcomer thrashed when a frame frees more than the budget in a repeating order (blur/glow intermediates): each free evicted the size the next call takes first, so misses came back to the old level and evict + reallocate raised the peak. The free list now evicts only sizes nobody asked for in the last 2 output frames (Accelerator::frame_end, called by the export per frame); otherwise the incoming texture is dropped and the kept set keeps hitting. Evicted bytes count against the budget until the work submitted so far is done, so evictions run at most one budget ahead of the GPU. * GPU: lower the shared pool budget to 256 MB On 4K RTX 3090 runs 256 MB matches the old code's peak reserved on d_blurglow (9204 MB) and is 256-512 MB above it on c_effects (6592 vs 6080 MB), while staying faster. * GPU: end frames on the multi-frame render paths, route recording through Enc::record Only the export pipeline called frame_end, so off export (preview, remote frames) the pool's clock stood still, no size went stale and a full free list dropped every newcomer. passes::comp_frame (exports), remote frames and the preview workers now end each frame; test without pool_frame_end. Docs: the frame clock is coarse with many frames in flight; dying only throttles eviction, approximately; no cache path escapes images. Enc::record is the single way to get the encoder outside context.rs and marks the images it names (Enc::uses). * GPU: wait for the empty submission while evicted pool textures still count stale_sizes_do_not_starve_a_steady_size failed with 0 hits and 20 misses on hardware adapters: pool_frame_end submitted an empty batch and then only did a non-blocking Poll, and the queue's work-done callback did not run before the next frame, so Pool::dying never drained and make_free stopped evicting stale sizes. While dying is non-zero, pool_frame_end now waits on that empty submission for up to the readback timeout (the pool lock is already released). A wait timeout just moves on and does not retire the context or its readbacks; other poll errors still retire them. Without dying textures it keeps the cheap Poll. Enc::crop records through Enc::record(&[src, &dst]) so both pooled images are registered like on every other recording path (review). * GPU: do not repeat the pool frame-end wait until evicted textures drain A wait that frees none of the evicted bytes (timeout, or a WebGPU poll that does not block) marks the pool stalled; later frames only poll until dying drops. Test covers the no-repeat and partial-progress cases; dying decrement saturates. * Remote frames: end a pending frame that a new render replaces A render arriving while a multi-pass frame waits for readbacks dropped that frame without `frame_end`, so the GPU pool's clock skipped it. Errors return before `frame_begin`. * Render: end the frame even when a comp frame panics `passes::comp_frame` called `frame_end` only after a normal return, so a frame that panicked (or whose future was dropped between passes) never aged the GPU pool. * GPU pool: log the reuse rate at render end; test reuse across effect calls and frames Log cumulative hits/misses (and reuse %) once per render before trimming. Tests cover reuse within an open frame across effect calls, and across repeated frames. --------- Co-authored-by: Matej Kozlovský <MatejKozlovsky@users.noreply.github.com> Co-authored-by: bflatastic <bombayapirat@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com> |
||
|
|
f3715aac32 |
M13.30: web depth and polish
- GPU in browser job workers: each job worker opens its own WebGPU device (deferred readbacks); the Render Queue export and the analyses' frame loops are futures (render::passes, offload::run_request_async) whose frames render in passes, awaiting the device between them. GPU particles and Advanced 3D read back under keys too. workers.jobs reports passes and readbacks; the smoke test measures them. - Layer buffers in the browser's OPFS disk cache: frame workers back their layer caches with a PrefetchStore; the page plans what to fetch before a request from recent misses (LayerPrefetch over the shared DiskIndex). - Templates embed footage (default on, size-capped with a warning) and creating from a template extracts it next to the new project / into browser storage. - ICC LUT profiles (lut8/lut16/lutAtoB/lutBtoA, from the public ICC spec) in Simulate Output > My Custom RGB, baked into a 3D LUT for the viewer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |