diff --git a/STREAMING_TO_DISK_PLAN.md b/STREAMING_TO_DISK_PLAN.md index 6f8a410..2d425ed 100644 --- a/STREAMING_TO_DISK_PLAN.md +++ b/STREAMING_TO_DISK_PLAN.md @@ -461,6 +461,19 @@ it resident. The heavy, evictable thing is the **image assets** referenced by fi from blob row or external `path`); Tier 2 = decoded pixels (`ImageCache` + GPU textures — the heavy one). +**Progress (2026-06-21):** +- **[DONE] Tier 2 — bound the decoded `ImageCache`.** 256 MB **usage-LRU**: every + `get_or_decode`/`_cpu` bumps the asset's recency; inserts past budget evict the least-recently-used + (a miss re-decodes from `asset.data`). Achieves usage-based eviction via render-access recency + (simpler than the frame→asset enumeration below; that enumeration is only needed for *prefetch*). +- **[TODO] Tier 1 — lazy/droppable compressed bytes.** Currently `asset.data` is **eager-read** from + the container on load (Phase 3.5b). Make it lazy: give `ImageCache` the container path, load bytes + on a decode miss via `read_packed_media_readonly(path, asset_id)` (don't eager-read on open → instant + load; don't accumulate compressed bytes). Wiring wrinkle: the `ImageCache` lives in the stage, not the + App that holds the container path → thread the path through `SharedPaneState`. +- **[TODO, optional] Prefetch via frame→asset enumeration** (4a below) — only if Tier-2 misses during + scrub/playback prove visible; the access-recency LRU already keeps rendered images resident. + ### 4a. Frame→asset enumeration (incl. nested clips — see note below) A function `assets_needed_at(time) -> HashSet`: walk each visible vector layer's active `ShapeKeyframe`, collect `fill.image_fill` across its `VectorGraph.fills`, **recursing into