mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-24 10:09:32 -06:00
G5: the playing prefetch window starts at the first uncached frame, ahead × 3 wide
Looking up to the whole RAM preview for uncached frames let the workers spread over the preview while the playhead waited. On the GPU each worker then built a Classic 3D atlas for its own set of layers, and on a cold start of the #1812 project the device ran out of memory far more often (first pass 1-56 % of real time instead of 63-81 %). The window now keeps its old width but starts at the first frame ahead that isn't cached, so a loop or a restart still renders on at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+22
-22
@@ -1238,34 +1238,34 @@ impl EffectcraftApp {
|
||||
}
|
||||
let step = plan.map_or(1, |p| p.step);
|
||||
// Never further ahead than the RAM preview holds: those frames would evict the ones the
|
||||
// preview shows first, or be evicted before it gets there (#595). A playing preview
|
||||
// looks that far for the next uncached frames: after a loop the frames just ahead are
|
||||
// cached, and a shorter window left the workers idle until the playhead came near the
|
||||
// end of the cached run.
|
||||
// preview shows first, or be evicted before it gets there (#595). The window starts at the
|
||||
// first uncached frame ahead: after a loop or a restart the frames just ahead are cached,
|
||||
// and a window from the playhead left the workers idle until it came near the end of the
|
||||
// cached run. It stays ahead × 3 frames wide: workers spread over the whole preview render
|
||||
// frames with different layers at once (on the GPU, an atlas each: #1812).
|
||||
let fit_ahead = self.frames_that_fit(&c, scale) - 1;
|
||||
let window = match plan.filter(|_| self.playback.playing) {
|
||||
Some(p) => fit_ahead.min((p.end - p.start) / p.step.max(1) + 1),
|
||||
None => (ahead * 3).min(fit_ahead),
|
||||
let frame = |k: i64| match plan {
|
||||
Some(p) => p.frame_after(cur, k),
|
||||
None => {
|
||||
let f = cur + k;
|
||||
Some(if f > wb { wa + (f - wb - 1).rem_euclid((wb - wa + 1).max(1)) } else { f })
|
||||
}
|
||||
};
|
||||
let cached = self.frames.cached_frames(&series);
|
||||
for k in 0..window {
|
||||
let uncached = |f: i64| cached.binary_search(&f).is_err();
|
||||
let first = match plan.filter(|_| self.playback.playing) {
|
||||
Some(p) => (0..fit_ahead.min((p.end - p.start) / p.step.max(1) + 1))
|
||||
.map_while(|k| frame(k).map(|f| (k, f)))
|
||||
.find(|&(_, f)| uncached(f))
|
||||
.map_or(0, |(k, _)| k),
|
||||
None => 0,
|
||||
};
|
||||
for k in first..(first + ahead * 3).min(fit_ahead) {
|
||||
if queued >= ahead as usize || !video {
|
||||
break;
|
||||
}
|
||||
let f = match plan {
|
||||
Some(p) => match p.frame_after(cur, k) {
|
||||
Some(f) => f,
|
||||
None => break,
|
||||
},
|
||||
None => {
|
||||
let mut f = cur + k;
|
||||
if f > wb {
|
||||
f = wa + (f - wb - 1).rem_euclid((wb - wa + 1).max(1));
|
||||
}
|
||||
f
|
||||
}
|
||||
};
|
||||
if cached.binary_search(&f).is_err() {
|
||||
let Some(f) = frame(k) else { break };
|
||||
if uncached(f) {
|
||||
self.request_frame(cid, f, scale);
|
||||
queued += 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user