VSE: Make cache eviction a bit smarter when wrapping.

Also fix some minor cache and prefetch bugs that became more noticeable
with these changes.

Pull Request: https://projects.blender.org/blender/blender/pulls/139635
This commit is contained in:
Sebastian Parborg
2025-06-11 15:15:46 +02:00
committed by Gitea
parent 5bd03f3618
commit a75fcd5d4a
5 changed files with 24 additions and 15 deletions

View File

@@ -200,17 +200,20 @@ bool final_image_cache_evict(Scene *scene)
/* Only activate the prefetch guards if the cache is active. */
seq_prefetch_get_time_range(scene, &cur_prefetch_start, &cur_prefetch_end);
}
bool prefetch_loops_around = cur_prefetch_start > cur_prefetch_end;
const bool prefetch_loops_around = cur_prefetch_start > cur_prefetch_end;
const int timeline_start = PSFRA;
const int timeline_end = PEFRA;
/* If we wrap around, treat the timeline start as the playback head position.
* This is to try to mitigate un-needed cache evictions. */
const int cur_frame = prefetch_loops_around ? timeline_start : scene->r.cfra;
const int cur_frame = scene->r.cfra;
std::pair<int, int> best_key = {};
ImBuf *best_item = nullptr;
int best_score = 0;
for (const auto &item : cache->map_.items()) {
const int item_frame = item.key.first;
if (prefetch_loops_around) {
int timeline_start = PSFRA;
int timeline_end = PEFRA;
if (item_frame >= timeline_start && item_frame <= cur_prefetch_end) {
continue; /* Within active prefetch range, do not try to remove it. */
}

View File

@@ -268,9 +268,14 @@ bool source_image_cache_evict(Scene *scene)
/* Only activate the prefetch guards if the cache is active. */
seq_prefetch_get_time_range(scene, &cur_prefetch_start, &cur_prefetch_end);
}
bool prefetch_loops_around = cur_prefetch_start > cur_prefetch_end;
const bool prefetch_loops_around = cur_prefetch_start > cur_prefetch_end;
const int timeline_start = PSFRA;
const int timeline_end = PEFRA;
/* If we wrap around, treat the timeline start as the playback head position.
* This is to try to mitigate un-needed cache evictions. */
const int cur_frame = prefetch_loops_around ? timeline_start : scene->r.cfra;
const int cur_frame = scene->r.cfra;
SourceImageCache::StripEntry *best_strip = nullptr;
std::pair<int, int> best_key = {};
int best_score = 0;
@@ -278,8 +283,6 @@ bool source_image_cache_evict(Scene *scene)
for (const auto &entry : strip.value.frames.items()) {
const int item_frame = int(strip.key->start + entry.value.strip_frame);
if (prefetch_loops_around) {
int timeline_start = PSFRA;
int timeline_end = PEFRA;
if (item_frame >= timeline_start && item_frame <= cur_prefetch_end) {
continue; /* Within active prefetch range, do not try to remove it. */
}

View File

@@ -76,7 +76,7 @@ struct PrefetchJob {
int timeline_end = 0;
int timeline_length = 0;
int num_frames_prefetched = 0;
int cache_flags = 0;
int cache_flags = 0; /* Only used to detect cache flag changes. */
/* Control: */
/* Set by prefetch. */
@@ -544,6 +544,7 @@ static void *seq_prefetch_frames(void *job)
}
ImBuf *ibuf = render_give_ibuf(&pfjob->context_cpy, seq_prefetch_cfra(pfjob), 0);
pfjob->num_frames_prefetched++;
IMB_freeImBuf(ibuf);
/* Suspend thread if there is nothing to be prefetched. */
@@ -556,7 +557,6 @@ static void *seq_prefetch_frames(void *job)
}
seq_prefetch_update_area(pfjob);
pfjob->num_frames_prefetched++;
}
pfjob->running = false;

View File

@@ -2004,10 +2004,12 @@ ImBuf *render_give_ibuf(const RenderData *context, float timeline_frame, int cha
if (!strips.is_empty() && !out) {
std::scoped_lock lock(seq_render_mutex);
out = seq_render_strip_stack(context, &state, channels, seqbasep, timeline_frame, chanshown);
/* Try to make space before we add any new frames to the cache if it is full.
* If we do this after we have added the new cache, we risk removing what we just added.*/
evict_caches_if_full(orig_scene);
out = seq_render_strip_stack(context, &state, channels, seqbasep, timeline_frame, chanshown);
if (out && (orig_scene->ed->cache_flag & SEQ_CACHE_STORE_FINAL_OUT) && !context->skip_cache &&
!context->is_proxy_render)
{

View File

@@ -94,11 +94,12 @@ bool evict_caches_if_full(Scene *scene)
bool evicted_source = false;
if (count_source != 0) {
evicted_source = source_image_cache_evict(scene);
/* Only try to enforce the final frame and raw cache ratio when the final cache is active. */
if (evicted_source && scene->ed->cache_flag & SEQ_CACHE_STORE_FINAL_OUT) {
/* Only try to enforce the final frame and raw cache ratio when the final cache is active. */
const size_t source_per_final = divide_ceil_ul(count_source - 1,
const size_t source_per_final = divide_ceil_ul(count_source,
std::max<size_t>(count_final, 1));
for (size_t i = 0; i < source_per_final; i++) {
/* Start at "1" to make sure we only try to evict more frames if the ratio is above 1:1. */
for (size_t i = 1; i < source_per_final; i++) {
if (!source_image_cache_evict(scene)) {
/* Can't evict any more frames, stop. */
break;