M4.8: Edit ▸ Purge clears what it names: disk and snapshot purges keep the RAM preview, memory purges drop decoded footage
- Every purge emptied the viewers' RAM preview; Purge ▸ All Disk Cache and Snapshot now leave it (Image Cache Memory, All Memory, All Memory & Disk Cache, All and All 3D Cache still clear it). - The memory purges also drop the decoded footage frames (`FootageSource::purge`, the media pool's `clear_frames`; decoders stay open), so footage reads decode again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5ce641c6b3
commit
fa27d621e0
|
|
@ -569,6 +569,7 @@ fn purge_caches(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
let disk = matches!(what.as_str(), "all" | "memoryAndDisk" | "disk");
|
||||
if memory {
|
||||
s.layer_cache.clear();
|
||||
s.footage.purge();
|
||||
}
|
||||
let mut disk_entries = 0;
|
||||
if disk && let Some(dc) = &s.disk_cache {
|
||||
|
|
@ -581,7 +582,11 @@ fn purge_caches(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
if matches!(what.as_str(), "all" | "image" | "memory" | "memoryAndDisk") {
|
||||
effectcraft_effects::roto::purge();
|
||||
}
|
||||
s.events.push(crate::Event::PurgeCaches);
|
||||
// The viewers' RAM preview goes with the memory purges (and the 3D one, whose renders it
|
||||
// holds); purging the disk cache or the snapshot leaves it.
|
||||
if memory || what == "3d" {
|
||||
s.events.push(crate::Event::PurgeCaches);
|
||||
}
|
||||
s.toast(format!("Purged {what} cache"));
|
||||
Ok(json!({"purged": what, "diskEntries": disk_entries}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -263,9 +263,35 @@ fn label_group_purge_and_edit_original() {
|
|||
s.execute("layer.select", json!({"layers": [a]})).unwrap();
|
||||
s.execute("edit.selectLabelGroup", json!({})).unwrap();
|
||||
assert_eq!(s.state.selected_layers.len(), 2);
|
||||
// A footage source that counts purges (the media pool drops its decoded frames).
|
||||
struct Counting(std::sync::atomic::AtomicUsize);
|
||||
impl crate::render::FootageSource for Counting {
|
||||
fn frame(
|
||||
&self,
|
||||
_: effectcraft_project::ItemId,
|
||||
_: &effectcraft_project::Footage,
|
||||
_: effectcraft_time::Tick,
|
||||
) -> Option<std::sync::Arc<crate::render::Image>> {
|
||||
None
|
||||
}
|
||||
fn purge(&self) {
|
||||
self.0.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
let src = std::sync::Arc::new(Counting(Default::default()));
|
||||
s.footage = src.clone();
|
||||
s.drain_events();
|
||||
s.execute("edit.purge", json!({"what": "memory"})).unwrap();
|
||||
assert!(s.drain_events().contains(&Event::PurgeCaches));
|
||||
assert_eq!(src.0.load(std::sync::atomic::Ordering::SeqCst), 1, "decoded footage frames are dropped");
|
||||
// The disk cache and the snapshot purge alone: the RAM preview stays.
|
||||
for what in ["disk", "snapshot"] {
|
||||
s.execute("edit.purge", json!({"what": what})).unwrap();
|
||||
assert!(!s.drain_events().contains(&Event::PurgeCaches), "{what}");
|
||||
}
|
||||
assert_eq!(src.0.load(std::sync::atomic::Ordering::SeqCst), 1);
|
||||
s.execute("edit.purge", json!({"what": "3d"})).unwrap();
|
||||
assert!(s.drain_events().contains(&Event::PurgeCaches));
|
||||
assert!(!s.is_enabled("edit.editOriginal"));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -233,12 +233,16 @@ impl MediaPool {
|
|||
}
|
||||
}
|
||||
|
||||
/// Drop every cached frame and decoder.
|
||||
pub fn clear(&self) {
|
||||
/// Drop every cached frame (decoders stay open).
|
||||
pub fn clear_frames(&self) {
|
||||
let mut c = lock(&self.inner.cache);
|
||||
c.lru = Lru::default();
|
||||
c.last.clear();
|
||||
drop(c);
|
||||
}
|
||||
|
||||
/// Drop every cached frame and decoder.
|
||||
pub fn clear(&self) {
|
||||
self.clear_frames();
|
||||
lock(&self.inner.sources).clear();
|
||||
}
|
||||
|
||||
|
|
@ -602,6 +606,9 @@ impl FootageSource for MediaPool {
|
|||
fn set_cache_budget(&self, bytes: usize) {
|
||||
self.set_budget(bytes);
|
||||
}
|
||||
fn purge(&self) {
|
||||
self.clear_frames();
|
||||
}
|
||||
fn cache_budget(&self) -> Option<usize> {
|
||||
Some(self.budget())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ pub trait FootageSource: Send + Sync {
|
|||
/// Set the decoded-frame cache budget in bytes (Settings ▸ Memory & CPU); sources without
|
||||
/// a cache ignore it.
|
||||
fn set_cache_budget(&self, _bytes: usize) {}
|
||||
/// Drop the decoded frames it keeps (Edit ▸ Purge ▸ All Memory / Image Cache Memory): the
|
||||
/// next reads decode again. Sources without a cache ignore it.
|
||||
fn purge(&self) {}
|
||||
/// Settings ▸ Disk ▸ Conformed Audio Folder: where decoded audio is kept between reads
|
||||
/// (`None` = off); sources that don't decode audio ignore it.
|
||||
fn set_conform_folder(&self, _folder: Option<std::path::PathBuf>) {}
|
||||
|
|
|
|||
Loading…
Reference in New Issue