mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-26 11:07:54 -06:00
G5: a reduced still's cache key includes its nominal size (#1812)
Review: two footage items of one file with different nominal sizes could share a sized entry, though one is resampled and the other kept as decoded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,9 @@ struct Key {
|
||||
matte: [u32; 3],
|
||||
/// A movie frame made at this size for a reduced-resolution render ((0, 0): as decoded).
|
||||
size: (u32, u32),
|
||||
/// A still at a reduced `size`: the footage's nominal size, which decides whether it is
|
||||
/// resampled (see `Inner::still_at_size`); (0, 0) otherwise.
|
||||
nominal: (u32, u32),
|
||||
}
|
||||
|
||||
struct Entry {
|
||||
@@ -678,7 +681,7 @@ impl Inner {
|
||||
FloatCurve::Gamma24 => 2,
|
||||
} << 2);
|
||||
let matte = if footage.alpha == AlphaMode::Premultiplied { footage.premul_color.map(f32::to_bits) } else { [0; 3] };
|
||||
let key = |path: &str, frame| Key { path: path.into(), frame, interp, matte, size: (0, 0) };
|
||||
let key = |path: &str, frame| Key { path: path.into(), frame, interp, matte, size: (0, 0), nominal: (0, 0) };
|
||||
match footage.kind {
|
||||
FootageKind::Sequence if !footage.sequence.is_empty() => {
|
||||
let i = Self::frame_index(footage.frame_rate, t, footage.sequence_frames(), footage.loop_count);
|
||||
@@ -719,6 +722,9 @@ impl Inner {
|
||||
// A still asked for at its own size is the unsized frame (one decode, one entry).
|
||||
if let Some(size) = size.filter(|s| movie || *s != (footage.width, footage.height)) {
|
||||
loc.key.size = size;
|
||||
if !movie {
|
||||
loc.key.nominal = (footage.width, footage.height);
|
||||
}
|
||||
}
|
||||
let mut c = lock(&self.cache);
|
||||
// sequential playback of a movie: read the next frame ahead
|
||||
@@ -1074,7 +1080,7 @@ mod tests {
|
||||
fn lru_respects_budget_and_recycles() {
|
||||
let mut c = Lru::default();
|
||||
let img = || Arc::new(Image::new(16, 16)); // 4 KiB + overhead
|
||||
let k = |i| Key { path: "a".into(), frame: i, interp: 0, matte: [0; 3], size: (0, 0) };
|
||||
let k = |i| Key { path: "a".into(), frame: i, interp: 0, matte: [0; 3], size: (0, 0), nominal: (0, 0) };
|
||||
let budget = 3 * (4096 + 64);
|
||||
for i in 0..10 {
|
||||
c.insert(k(i), img(), budget);
|
||||
|
||||
@@ -610,11 +610,12 @@ fn stills_at_reduced_sizes_are_resampled_once() {
|
||||
}
|
||||
// Pixels larger than the nominal size (a smart object's) are resampled as the renderer does;
|
||||
// smaller ones are left as they are (the renderer scales the layer up instead).
|
||||
// One pool, one file, one requested size: the two decisions don't share a cache entry.
|
||||
let larger = Footage { width: 306, height: 48, ..f.clone() };
|
||||
let sized = MediaPool::new().frame_at_size(ItemId(1), &larger, Tick::ZERO, 153, 24).expect("frame");
|
||||
assert_eq!(*sized, effectcraft_raster::resample(&full, 153, 24));
|
||||
let smaller = Footage { width: 1226, height: 194, ..f.clone() };
|
||||
let kept = MediaPool::new().frame_at_size(ItemId(1), &smaller, Tick::ZERO, 306, 48).expect("frame");
|
||||
let sized = pool.frame_at_size(ItemId(2), &larger, Tick::ZERO, 153, 24).expect("frame");
|
||||
assert_eq!(*sized, effectcraft_raster::resample(&full, 153, 24));
|
||||
let kept = pool.frame_at_size(ItemId(3), &smaller, Tick::ZERO, 153, 24).expect("frame");
|
||||
assert_eq!(*kept, *full);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user