mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-14 19:27:05 -04:00
Web: the layer and footage caches stay small enough for eight stacked clips
Cause: the browser build kept the desktop's cache budgets (1 GB layer
cache, 1 GB footage frame cache) inside the page's memory, which wasm32
caps at 4 GiB. FilmCraft's decoders keep up to 384 MB of decoded frames
per open movie beside them, so a comp of eight stacked 1080p H.264 clips
grew the page by about 55 MB/s while playing and ran it out of memory
after about 50 s ("unreachable": a failed allocation).
Fix: in the browser Prefs::cache_budgets keeps the Layer Cache within
512 MB and the Footage Frame Cache within 256 MB (WEB_LAYER_CACHE,
WEB_MEDIA_CACHE); smaller settings and the desktop are unchanged, and
the RAM preview keeps its budget. Docs (web, preferences) say so.
Tests: tests_m145::web_cache_budgets_leave_room_for_the_decoders: with
4 GB settings the web budgets are the caps, the desktop's are the
settings, and smaller settings stay as they are.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
30aaddf7c2
commit
2ccc66e73b
4 files changed
+39
-2
No files matched your search
@@ -586,8 +586,18 @@ impl Prefs {
|
||||
/// budgets, scaled down so together they leave **RAM Reserved for Other Applications** free,
|
||||
/// and halved while the system is low on memory when **Reduce Cache Size When System Is Low
|
||||
/// on Memory** is on. `mem` = the system's memory (`None` = unknown: configured budgets).
|
||||
/// In the browser the layer and footage caches also stay within [`WEB_LAYER_CACHE`] and
|
||||
/// [`WEB_MEDIA_CACHE`].
|
||||
pub fn cache_budgets(&self, mem: Option<crate::sysinfo::SysMemory>) -> CacheBudgets {
|
||||
self.cache_budgets_in(mem, cfg!(target_arch = "wasm32"))
|
||||
}
|
||||
|
||||
/// [`Prefs::cache_budgets`], in the browser's memory (`web`) or not.
|
||||
pub(crate) fn cache_budgets_in(&self, mem: Option<crate::sysinfo::SysMemory>, web: bool) -> CacheBudgets {
|
||||
let (mut l, mut m, mut p) = (self.layer_cache_bytes() as u64, self.media_cache_bytes() as u64, self.preview_cache_bytes() as u64);
|
||||
if web {
|
||||
(l, m) = (l.min(WEB_LAYER_CACHE), m.min(WEB_MEDIA_CACHE));
|
||||
}
|
||||
let floor = 64u64 << 20;
|
||||
let mut capped = false;
|
||||
let mut reduced = false;
|
||||
@@ -732,6 +742,15 @@ fn push_mru(list: &mut Vec<String>, v: &str, max: usize) {
|
||||
list.truncate(max.max(1));
|
||||
}
|
||||
|
||||
/// The most the layer cache holds in the browser. A wasm32 page addresses at most 4 GiB, which
|
||||
/// these caches share with the app and with the decoders' own decoded frames (FilmCraft keeps
|
||||
/// up to 384 MB per open movie): with the desktop's 1 GB defaults, eight stacked 1080p clips ran
|
||||
/// the page out of memory a few seconds into playback.
|
||||
pub const WEB_LAYER_CACHE: u64 = 512 << 20;
|
||||
|
||||
/// The most the footage frame cache holds in the browser (see [`WEB_LAYER_CACHE`]).
|
||||
pub const WEB_MEDIA_CACHE: u64 = 256 << 20;
|
||||
|
||||
/// Effective cache budgets in bytes (see [`Prefs::cache_budgets`]).
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
|
||||
pub struct CacheBudgets {
|
||||
|
||||
@@ -202,6 +202,23 @@ fn cache_budgets_leave_reserved_ram_and_shrink_when_low() {
|
||||
assert!(!p.cache_budgets(Some(low)).reduced);
|
||||
}
|
||||
|
||||
/// Eight stacked 1080p clips ran the browser build out of its 4 GiB of memory: the footage and
|
||||
/// layer caches kept their desktop sizes there, beside the decoders' own frames.
|
||||
#[test]
|
||||
fn web_cache_budgets_leave_room_for_the_decoders() {
|
||||
use crate::prefs::{WEB_LAYER_CACHE, WEB_MEDIA_CACHE};
|
||||
let mut p = crate::prefs::Prefs::default();
|
||||
p.memory.layer_cache_mb = 4096;
|
||||
p.memory.media_cache_mb = 4096;
|
||||
let web = p.cache_budgets_in(None, true);
|
||||
assert_eq!((web.layer as u64, web.media as u64), (WEB_LAYER_CACHE, WEB_MEDIA_CACHE));
|
||||
assert_eq!(web.preview, p.cache_budgets_in(None, false).preview, "the RAM preview keeps its budget");
|
||||
// Smaller settings stay as they are; the desktop is unchanged.
|
||||
p.memory.media_cache_mb = 128;
|
||||
assert_eq!(p.cache_budgets_in(None, true).media, 128 << 20);
|
||||
assert_eq!(p.cache_budgets_in(None, false).layer, 4096 << 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn motion_path_span_follows_the_composition_setting() {
|
||||
let mut p = crate::prefs::Prefs::default();
|
||||
|
||||
+2
-2
@@ -71,8 +71,8 @@ Commands (CLI, MCP, control channel):
|
||||
- `audio.outputDevice`: Default Output (device list from the desktop host)
|
||||
- `audio.outputLeft`: Left (Audio Output Mapping)
|
||||
- `audio.outputRight`: Right (Audio Output Mapping)
|
||||
- `memory.layerCacheMb`: Layer Cache
|
||||
- `memory.mediaCacheMb`: Footage Frame Cache
|
||||
- `memory.layerCacheMb`: Layer Cache (in the browser at most 512 MB, see [web.md](web.md))
|
||||
- `memory.mediaCacheMb`: Footage Frame Cache (in the browser at most 256 MB)
|
||||
- `memory.previewCacheMb`: Preview (RAM) Cache
|
||||
- `threeD.defaultRenderer`: Default 3D Renderer
|
||||
- `labels.N.name` / `labels.N.color`: the 16 label names and colours, used by the Label menu,
|
||||
|
||||
@@ -61,6 +61,7 @@ device of their own), `?nosw` (don't register the service worker).
|
||||
| config directory: settings, shortcut presets, recent projects, the recovery sentinel | `store::WebConfig` in browser storage |
|
||||
| auto-save folder | `/EffectCraft Auto-Save/` in browser storage (`ConfigStore::files`) |
|
||||
| media reads (`MediaPool`, `probe`) | `files::WebImporter`: bytes from the file table, handed to `MediaPool::add_bytes` / `probe_bytes` |
|
||||
| Memory & CPU cache budgets, scaled to the system's RAM | the page's memory, at most 4 GiB (wasm32), which the caches share with the decoders' own decoded frames (FilmCraft keeps up to 384 MB per open movie): the Layer Cache stays within 512 MB and the Footage Frame Cache within 256 MB (`Prefs::cache_budgets`) |
|
||||
| export writes (`effectcraft-export`) | the job's `sink` (`effectcraft_host::FileExporter { sink }`): files land in the table and download after the render; several files (an image sequence) download as one stored `.zip` |
|
||||
| rfd file dialogs | `<input type=file>` for File ▸ Open / Import; drop files anywhere on the page (`.ecproj` opens, everything else imports); "Save As" / "Output To" pick a download name |
|
||||
| Media Browser on the file system | browser storage and folders opened with the File System Access API (below) |
|
||||
|
||||
Reference in new issue
Block a user