Blender V4.3
image_cache.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2010 Peter Schlaile <peter [at] schlaile [dot] de>.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstddef>
10#include <ctime>
11#include <memory.h>
12
13#include "MEM_guardedalloc.h"
14
15#include "DNA_scene_types.h"
16#include "DNA_sequence_types.h"
17#include "DNA_space_types.h" /* for FILE_MAX. */
18
19#include "IMB_imbuf.hh"
20#include "IMB_imbuf_types.hh"
21
22#include "BLI_fileops_types.h"
23#include "BLI_ghash.h"
24#include "BLI_mempool.h"
25#include "BLI_threads.h"
26
27#include "BKE_main.hh"
28
29#include "SEQ_prefetch.hh"
30#include "SEQ_relations.hh"
31#include "SEQ_render.hh"
32#include "SEQ_time.hh"
33
34#include "disk_cache.hh"
35#include "image_cache.hh"
36#include "prefetch.hh"
37
73
78
80
81static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
82{
83 return ((a->preview_render_size != b->preview_render_size) || (a->rectx != b->rectx) ||
84 (a->recty != b->recty) || (a->bmain != b->bmain) || (a->scene != b->scene) ||
85 (a->motion_blur_shutter != b->motion_blur_shutter) ||
86 (a->motion_blur_samples != b->motion_blur_samples) ||
87 (a->scene->r.views_format != b->scene->r.views_format) || (a->view_id != b->view_id));
88}
89
91{
92 uint rval = a->rectx + a->recty;
93
94 rval ^= a->preview_render_size;
95 rval ^= intptr_t(a->bmain) << 6;
96 rval ^= intptr_t(a->scene) << 6;
97 rval ^= int(a->motion_blur_shutter * 100.0f) << 10;
98 rval ^= a->motion_blur_samples << 16;
99 rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 24;
100
101 return rval;
102}
103
104static uint seq_cache_hashhash(const void *key_)
105{
106 const SeqCacheKey *key = static_cast<const SeqCacheKey *>(key_);
107 uint rval = seq_hash_render_data(&key->context);
108
109 rval ^= *(const uint *)&key->frame_index;
110 rval += key->type;
111 rval ^= intptr_t(key->seq) << 6;
112
113 return rval;
114}
115
116static bool seq_cache_hashcmp(const void *a_, const void *b_)
117{
118 const SeqCacheKey *a = static_cast<const SeqCacheKey *>(a_);
119 const SeqCacheKey *b = static_cast<const SeqCacheKey *>(b_);
120
121 return ((a->seq != b->seq) || (a->frame_index != b->frame_index) || (a->type != b->type) ||
122 seq_cmp_render_data(&a->context, &b->context));
123}
124
126 const Sequence *seq,
127 const float timeline_frame,
128 const int type)
129{
130 /* With raw images, map timeline_frame to strip input media frame range. This means that static
131 * images or extended frame range of movies will only generate one cache entry. No special
132 * treatment in converting frame index to timeline_frame is needed. */
133 bool is_effect = seq->type & SEQ_TYPE_EFFECT;
134 if (!is_effect && type == SEQ_CACHE_STORE_RAW) {
135 return SEQ_give_frame_index(scene, seq, timeline_frame);
136 }
137
138 return timeline_frame - SEQ_time_start_frame_get(seq);
139}
140
142{
143 return frame_index + SEQ_time_start_frame_get(seq);
144}
145
147{
148 if (scene && scene->ed && scene->ed->cache) {
149 return scene->ed->cache;
150 }
151
152 return nullptr;
153}
154
155static void seq_cache_lock(Scene *scene)
156{
157 SeqCache *cache = seq_cache_get_from_scene(scene);
158
159 if (cache) {
161 }
162}
163
164static void seq_cache_unlock(Scene *scene)
165{
166 SeqCache *cache = seq_cache_get_from_scene(scene);
167
168 if (cache) {
170 }
171}
172
174{
175 return size_t(U.memcachelimit) * 1024 * 1024;
176}
177
178static void seq_cache_keyfree(void *val)
179{
180 SeqCacheKey *key = static_cast<SeqCacheKey *>(val);
182}
183
184static void seq_cache_valfree(void *val)
185{
186 SeqCacheItem *item = (SeqCacheItem *)val;
187
188 if (item->ibuf) {
189 IMB_freeImBuf(item->ibuf);
190 }
191
193}
194
196{
197 int flag;
198 if (key->seq->cache_flag & SEQ_CACHE_OVERRIDE) {
199 flag = key->seq->cache_flag;
200 }
201 else {
202 flag = scene->ed->cache_flag;
203 }
204
205 /* SEQ_CACHE_STORE_FINAL_OUT can not be overridden by strip cache */
206 flag |= (scene->ed->cache_flag & SEQ_CACHE_STORE_FINAL_OUT);
207
208 return flag;
209}
210
211static void seq_cache_put_ex(Scene *scene, SeqCacheKey *key, ImBuf *ibuf)
212{
213 SeqCache *cache = seq_cache_get_from_scene(scene);
214 SeqCacheItem *item;
215 item = static_cast<SeqCacheItem *>(BLI_mempool_alloc(cache->items_pool));
216 item->cache_owner = cache;
217 item->ibuf = ibuf;
218
219 const int stored_types_flag = get_stored_types_flag(scene, key);
220
221 /* Item stored for later use. */
222 if (stored_types_flag & key->type) {
223 key->is_temp_cache = false;
224 key->link_prev = cache->last_key;
225 }
226
227 BLI_assert(!BLI_ghash_haskey(cache->hash, key));
228 BLI_ghash_insert(cache->hash, key, item);
229 IMB_refImBuf(ibuf);
230
231 /* Store pointer to last cached key. */
232 SeqCacheKey *temp_last_key = cache->last_key;
233 cache->last_key = key;
234
235 /* Set last_key's reference to this key so we can look up chain backwards.
236 * Item is already put in cache, so cache->last_key points to current key.
237 */
238 if (!key->is_temp_cache && temp_last_key) {
239 temp_last_key->link_next = cache->last_key;
240 }
241
242 /* Reset linking. */
243 if (key->type == SEQ_CACHE_STORE_FINAL_OUT) {
244 cache->last_key = nullptr;
245 }
246}
247
249{
250 SeqCacheItem *item = static_cast<SeqCacheItem *>(BLI_ghash_lookup(cache->hash, key));
251
252 if (item && item->ibuf) {
253 IMB_refImBuf(item->ibuf);
254
255 return item->ibuf;
256 }
257
258 return nullptr;
259}
260
262{
263 if (key->link_next) {
264 BLI_assert(key == key->link_next->link_prev);
265 key->link_next->link_prev = key->link_prev;
266 }
267 if (key->link_prev) {
268 BLI_assert(key == key->link_prev->link_next);
269 key->link_prev->link_next = key->link_next;
270 }
271}
272
273/* Choose a key out of 2 candidates(leftmost and rightmost items)
274 * to recycle based on currently used strategy */
276{
277 SeqCacheKey *finalkey = nullptr;
278
279 /* Ideally, cache would not need to check the state of prefetching task
280 * that is tricky to do however, because prefetch would need to know,
281 * if a key, that is about to be created would be removed by itself.
282 *
283 * This can happen because only FINAL_OUT item insertion will trigger recycling
284 * but that is also the point, where prefetch can be suspended.
285 *
286 * We could use temp cache as a shield and later make it a non-temporary entry,
287 * but it is not worth of increasing system complexity.
288 */
289 if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE && seq_prefetch_job_is_running(scene)) {
290 int pfjob_start, pfjob_end;
291 seq_prefetch_get_time_range(scene, &pfjob_start, &pfjob_end);
292
293 if (lkey) {
294 if (lkey->timeline_frame < pfjob_start || lkey->timeline_frame > pfjob_end) {
295 return lkey;
296 }
297 }
298
299 if (rkey) {
300 if (rkey->timeline_frame < pfjob_start || rkey->timeline_frame > pfjob_end) {
301 return rkey;
302 }
303 }
304
305 return nullptr;
306 }
307
308 if (rkey && lkey) {
309 if (lkey->timeline_frame > rkey->timeline_frame) {
310 SeqCacheKey *swapkey = lkey;
311 lkey = rkey;
312 rkey = swapkey;
313 }
314
315 int l_diff = scene->r.cfra - lkey->timeline_frame;
316 int r_diff = rkey->timeline_frame - scene->r.cfra;
317
318 if (l_diff > r_diff) {
319 finalkey = lkey;
320 }
321 else {
322 finalkey = rkey;
323 }
324 }
325 else {
326 if (lkey) {
327 finalkey = lkey;
328 }
329 else {
330 finalkey = rkey;
331 }
332 }
333 return finalkey;
334}
335
337{
338 SeqCache *cache = seq_cache_get_from_scene(scene);
339 if (!cache) {
340 return;
341 }
342
343 SeqCacheKey *next = base->link_next;
344
345 while (base) {
346 if (!BLI_ghash_haskey(cache->hash, base)) {
347 break; /* Key has already been removed from cache. */
348 }
349
350 SeqCacheKey *prev = base->link_prev;
351 if (prev != nullptr && prev->link_next != base) {
352 /* Key has been removed and replaced and doesn't belong to this chain anymore. */
353 base->link_prev = nullptr;
354 break;
355 }
356
359 BLI_assert(base != cache->last_key);
360 base = prev;
361 }
362
363 base = next;
364 while (base) {
365 if (!BLI_ghash_haskey(cache->hash, base)) {
366 break; /* Key has already been removed from cache. */
367 }
368
369 next = base->link_next;
370 if (next != nullptr && next->link_prev != base) {
371 /* Key has been removed and replaced and doesn't belong to this chain anymore. */
372 base->link_next = nullptr;
373 break;
374 }
375
378 BLI_assert(base != cache->last_key);
379 base = next;
380 }
381}
382
384{
385 SeqCache *cache = seq_cache_get_from_scene(scene);
386 SeqCacheKey *finalkey = nullptr;
387 /* Leftmost key. */
388 SeqCacheKey *lkey = nullptr;
389 /* Rightmost key. */
390 SeqCacheKey *rkey = nullptr;
391 SeqCacheKey *key = nullptr;
392
393 GHashIterator gh_iter;
394 BLI_ghashIterator_init(&gh_iter, cache->hash);
395 int total_count = 0;
396
397 while (!BLI_ghashIterator_done(&gh_iter)) {
398 key = static_cast<SeqCacheKey *>(BLI_ghashIterator_getKey(&gh_iter));
399 SeqCacheItem *item = static_cast<SeqCacheItem *>(BLI_ghashIterator_getValue(&gh_iter));
400 BLI_ghashIterator_step(&gh_iter);
401 BLI_assert(key->cache_owner == cache);
402
403 /* This shouldn't happen, but better be safe than sorry. */
404 if (!item->ibuf) {
405 seq_cache_recycle_linked(scene, key);
406 /* Can not continue iterating after linked remove. */
407 BLI_ghashIterator_init(&gh_iter, cache->hash);
408 continue;
409 }
410
411 if (key->is_temp_cache || key->link_next != nullptr) {
412 continue;
413 }
414
415 total_count++;
416
417 if (lkey) {
418 if (key->timeline_frame < lkey->timeline_frame) {
419 lkey = key;
420 }
421 }
422 else {
423 lkey = key;
424 }
425 if (rkey) {
426 if (key->timeline_frame > rkey->timeline_frame) {
427 rkey = key;
428 }
429 }
430 else {
431 rkey = key;
432 }
433 }
434 (void)total_count; /* Quiet set-but-unused warning (may be removed). */
435
436 finalkey = seq_cache_choose_key(scene, lkey, rkey);
437
438 return finalkey;
439}
440
442{
443 SeqCache *cache = seq_cache_get_from_scene(scene);
444 if (!cache) {
445 return false;
446 }
447
448 seq_cache_lock(scene);
449
450 while (seq_cache_is_full()) {
452
453 if (finalkey) {
454 seq_cache_recycle_linked(scene, finalkey);
455 }
456 else {
457 seq_cache_unlock(scene);
458 return false;
459 }
460 }
461 seq_cache_unlock(scene);
462 return true;
463}
464
466{
467 SeqCache *cache = seq_cache_get_from_scene(scene);
468
469 if (!cache || !base) {
470 return;
471 }
472
473 SeqCacheKey *next = base->link_next;
474
475 while (base) {
476 SeqCacheKey *prev = base->link_prev;
477 base->is_temp_cache = true;
478 base = prev;
479 }
480
481 base = next;
482 while (base) {
483 next = base->link_next;
484 base->is_temp_cache = true;
485 base = next;
486 }
487}
488
489static void seq_cache_create(Main *bmain, Scene *scene)
490{
492 if (scene->ed->cache == nullptr) {
493 SeqCache *cache = static_cast<SeqCache *>(MEM_callocN(sizeof(SeqCache), "SeqCache"));
496 cache->hash = BLI_ghash_new(seq_cache_hashhash, seq_cache_hashcmp, "SeqCache hash");
497 cache->last_key = nullptr;
498 cache->bmain = bmain;
500 scene->ed->cache = cache;
501
502 if (scene->ed->disk_cache_timestamp == 0) {
503 scene->ed->disk_cache_timestamp = time(nullptr);
504 }
505 }
507}
508
510 const SeqRenderData *context,
511 Sequence *seq,
512 const float timeline_frame,
513 const int type)
514{
515 key->cache_owner = seq_cache_get_from_scene(context->scene);
516 key->seq = seq;
517 key->context = *context;
519 context->scene, seq, timeline_frame, type);
520 key->timeline_frame = timeline_frame;
521 key->type = type;
522 key->link_prev = nullptr;
523 key->link_next = nullptr;
524 key->is_temp_cache = true;
525 key->task_id = context->task_id;
526}
527
529 const SeqRenderData *context,
530 Sequence *seq,
531 const float timeline_frame,
532 const int type)
533{
534 SeqCacheKey *key = static_cast<SeqCacheKey *>(BLI_mempool_alloc(cache->keys_pool));
535 seq_cache_populate_key(key, context, seq, timeline_frame, type);
536 return key;
537}
538
539/* ***************************** API ****************************** */
540
541void seq_cache_free_temp_cache(Scene *scene, short id, int timeline_frame)
542{
543 SeqCache *cache = seq_cache_get_from_scene(scene);
544 if (!cache) {
545 return;
546 }
547
548 seq_cache_lock(scene);
549
550 GHashIterator gh_iter;
551 BLI_ghashIterator_init(&gh_iter, cache->hash);
552 while (!BLI_ghashIterator_done(&gh_iter)) {
553 SeqCacheKey *key = static_cast<SeqCacheKey *>(BLI_ghashIterator_getKey(&gh_iter));
554 BLI_ghashIterator_step(&gh_iter);
555 BLI_assert(key->cache_owner == cache);
556
557 if (key->is_temp_cache && key->task_id == id) {
558 /* Use frame_index here to avoid freeing raw images if they are used for multiple frames. */
559 float frame_index = seq_cache_timeline_frame_to_frame_index(
560 scene, key->seq, timeline_frame, key->type);
561 if (frame_index != key->frame_index ||
562 timeline_frame > SEQ_time_right_handle_frame_get(scene, key->seq) ||
563 timeline_frame < SEQ_time_left_handle_frame_get(scene, key->seq))
564 {
567 if (key == cache->last_key) {
568 cache->last_key = nullptr;
569 }
570 }
571 }
572 }
573 seq_cache_unlock(scene);
574}
575
577{
578 SeqCache *cache = seq_cache_get_from_scene(scene);
579 if (!cache) {
580 return;
581 }
582
587
588 if (cache->disk_cache != nullptr) {
590 }
591
592 MEM_freeN(cache);
593 scene->ed->cache = nullptr;
594}
595
597{
598 SEQ_prefetch_stop(scene);
599
600 SeqCache *cache = seq_cache_get_from_scene(scene);
601 if (!cache) {
602 return;
603 }
604
605 seq_cache_lock(scene);
606
607 GHashIterator gh_iter;
608 BLI_ghashIterator_init(&gh_iter, cache->hash);
609 while (!BLI_ghashIterator_done(&gh_iter)) {
610 SeqCacheKey *key = static_cast<SeqCacheKey *>(BLI_ghashIterator_getKey(&gh_iter));
611 BLI_assert(key->cache_owner == cache);
612
613 BLI_ghashIterator_step(&gh_iter);
614
615 /* NOTE: no need to call #seq_cache_key_unlink as all keys are removed. */
617 }
618 cache->last_key = nullptr;
619 seq_cache_unlock(scene);
620}
621
623 Sequence *seq,
624 Sequence *seq_changed,
625 int invalidate_types,
626 bool force_seq_changed_range)
627{
628 SeqCache *cache = seq_cache_get_from_scene(scene);
629 if (!cache) {
630 return;
631 }
632
633 if (seq_disk_cache_is_enabled(cache->bmain) && cache->disk_cache != nullptr) {
634 seq_disk_cache_invalidate(cache->disk_cache, scene, seq, seq_changed, invalidate_types);
635 }
636
637 seq_cache_lock(scene);
638
639 const int range_start_seq_changed = seq_cache_timeline_frame_to_frame_index(
640 scene, seq, SEQ_time_left_handle_frame_get(scene, seq_changed), invalidate_types);
641 const int range_end_seq_changed = seq_cache_timeline_frame_to_frame_index(
642 scene, seq, SEQ_time_right_handle_frame_get(scene, seq_changed), invalidate_types);
643
644 int range_start = range_start_seq_changed;
645 int range_end = range_end_seq_changed;
646
647 if (!force_seq_changed_range) {
648 const int range_start_seq = seq_cache_timeline_frame_to_frame_index(
649 scene, seq, SEQ_time_left_handle_frame_get(scene, seq), invalidate_types);
650 const int range_end_seq = seq_cache_timeline_frame_to_frame_index(
651 scene, seq, SEQ_time_right_handle_frame_get(scene, seq), invalidate_types);
652
653 range_start = max_ii(range_start, range_start_seq);
654 range_end = min_ii(range_end, range_end_seq);
655 }
656
657 int invalidate_composite = invalidate_types & SEQ_CACHE_STORE_FINAL_OUT;
658 int invalidate_source = invalidate_types & (SEQ_CACHE_STORE_RAW | SEQ_CACHE_STORE_PREPROCESSED |
660
661 GHashIterator gh_iter;
662 BLI_ghashIterator_init(&gh_iter, cache->hash);
663 while (!BLI_ghashIterator_done(&gh_iter)) {
664 SeqCacheKey *key = static_cast<SeqCacheKey *>(BLI_ghashIterator_getKey(&gh_iter));
665 BLI_ghashIterator_step(&gh_iter);
666 BLI_assert(key->cache_owner == cache);
667
668 /* Clean all final and composite in intersection of seq and seq_changed. */
669 if (key->type & invalidate_composite && key->frame_index >= range_start &&
670 key->frame_index <= range_end)
671 {
674 }
675 else if (key->type & invalidate_source && key->seq == seq &&
676 key->frame_index >= range_start_seq_changed &&
677 key->frame_index <= range_end_seq_changed)
678 {
681 }
682 }
683 cache->last_key = nullptr;
684 seq_cache_unlock(scene);
685}
686
687ImBuf *seq_cache_get(const SeqRenderData *context, Sequence *seq, float timeline_frame, int type)
688{
689
690 if (context->skip_cache || context->is_proxy_render || context->for_render || !seq) {
691 return nullptr;
692 }
693
694 Scene *scene = context->scene;
695
696 if (context->is_prefetch_render) {
697 context = seq_prefetch_get_original_context(context);
698 scene = context->scene;
699 seq = seq_prefetch_get_original_sequence(seq, scene);
700 }
701
702 if (!seq) {
703 return nullptr;
704 }
705
706 if (!scene->ed->cache) {
707 seq_cache_create(context->bmain, scene);
708 }
709
710 seq_cache_lock(scene);
711 SeqCache *cache = seq_cache_get_from_scene(scene);
712 ImBuf *ibuf = nullptr;
713 SeqCacheKey key;
714
715 /* Try RAM cache: */
716 if (cache && seq) {
717 seq_cache_populate_key(&key, context, seq, timeline_frame, type);
718 ibuf = seq_cache_get_ex(cache, &key);
719 }
720 seq_cache_unlock(scene);
721
722 if (ibuf) {
723 return ibuf;
724 }
725
726 /* Try disk cache: */
727 if (seq_disk_cache_is_enabled(context->bmain)) {
728 if (cache->disk_cache == nullptr) {
729 cache->disk_cache = seq_disk_cache_create(context->bmain, context->scene);
730 }
731
732 ibuf = seq_disk_cache_read_file(cache->disk_cache, &key);
733
734 if (ibuf == nullptr) {
735 return nullptr;
736 }
737
738 /* Store read image in RAM. Only recycle item for final type. */
740 SeqCacheKey *new_key = seq_cache_allocate_key(cache, context, seq, timeline_frame, type);
741 seq_cache_put_ex(scene, new_key, ibuf);
742 }
743 }
744
745 return ibuf;
746}
747
749 const SeqRenderData *context, Sequence *seq, float timeline_frame, int type, ImBuf *ibuf)
750{
751 Scene *scene = context->scene;
752
753 if (context->is_prefetch_render) {
754 context = seq_prefetch_get_original_context(context);
755 scene = context->scene;
756 seq = seq_prefetch_get_original_sequence(seq, scene);
757 }
758
759 if (!seq) {
760 return false;
761 }
762
763 if (seq_cache_recycle_item(scene)) {
764 seq_cache_put(context, seq, timeline_frame, type, ibuf);
765 return true;
766 }
767
768 if (scene->ed->cache) {
769 seq_cache_set_temp_cache_linked(scene, scene->ed->cache->last_key);
770 scene->ed->cache->last_key = nullptr;
771 }
772
773 return false;
774}
775
777 const SeqRenderData *context, Sequence *seq, float timeline_frame, int type, ImBuf *i)
778{
779 if (i == nullptr || context->skip_cache || context->is_proxy_render || context->for_render ||
780 !seq)
781 {
782 return;
783 }
784
785 Scene *scene = context->scene;
786
787 if (context->is_prefetch_render) {
788 context = seq_prefetch_get_original_context(context);
789 scene = context->scene;
790 seq = seq_prefetch_get_original_sequence(seq, scene);
791 BLI_assert(seq != nullptr);
792 }
793
794 /* Prevent reinserting, it breaks cache key linking. */
795 ImBuf *test = seq_cache_get(context, seq, timeline_frame, type);
796 if (test) {
797 IMB_freeImBuf(test);
798 return;
799 }
800
801 if (!scene->ed->cache) {
802 seq_cache_create(context->bmain, scene);
803 }
804
805 seq_cache_lock(scene);
806 SeqCache *cache = seq_cache_get_from_scene(scene);
807 SeqCacheKey *key = seq_cache_allocate_key(cache, context, seq, timeline_frame, type);
808 seq_cache_put_ex(scene, key, i);
809 seq_cache_unlock(scene);
810
811 if (!key->is_temp_cache) {
812 if (seq_disk_cache_is_enabled(context->bmain)) {
813 if (cache->disk_cache == nullptr) {
814 seq_disk_cache_create(context->bmain, context->scene);
815 }
816
819 }
820 }
821}
822
824 Scene *scene,
825 void *userdata,
826 bool callback_init(void *userdata, size_t item_count),
827 bool callback_iter(void *userdata, Sequence *seq, int timeline_frame, int cache_type))
828{
829 SeqCache *cache = seq_cache_get_from_scene(scene);
830 if (!cache) {
831 return;
832 }
833
834 seq_cache_lock(scene);
835 bool interrupt = callback_init(userdata, BLI_ghash_len(cache->hash));
836
837 GHashIterator gh_iter;
838 BLI_ghashIterator_init(&gh_iter, cache->hash);
839
840 while (!BLI_ghashIterator_done(&gh_iter) && !interrupt) {
841 SeqCacheKey *key = static_cast<SeqCacheKey *>(BLI_ghashIterator_getKey(&gh_iter));
842 BLI_ghashIterator_step(&gh_iter);
843 BLI_assert(key->cache_owner == cache);
844 int timeline_frame;
845 if (key->type & SEQ_CACHE_STORE_FINAL_OUT) {
846 timeline_frame = key->timeline_frame;
847 }
848 else {
849 /* This is not a final cache image. The cached frame is relative to where the strip is
850 * currently and where it was when it was cached. We can't use the timeline_frame, we need to
851 * derive the timeline frame from key->frame_index.
852 *
853 * NOTE This will not work for RAW caches if they have retiming, strobing, or different
854 * playback rate than the scene. Because it would take quite a bit of effort to properly
855 * convert RAW frames like that to a timeline frame, we skip doing this as visualizing these
856 * are a developer option that not many people will see.
857 */
858 timeline_frame = key->frame_index + SEQ_time_start_frame_get(key->seq);
859 }
860
861 interrupt = callback_iter(userdata, key->seq, timeline_frame, key->type);
862 }
863
864 cache->last_key = nullptr;
865 seq_cache_unlock(scene);
866}
867
#define BLI_assert(a)
Definition BLI_assert.h:50
Some types for dealing with directories.
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:299
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:819
void BLI_ghashIterator_step(GHashIterator *ghi)
Definition BLI_ghash.c:911
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:303
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:686
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:702
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:787
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
Definition BLI_ghash.c:895
BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:311
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
@ BLI_MEMPOOL_NOP
Definition BLI_mempool.h:86
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
unsigned int uint
void BLI_mutex_end(ThreadMutex *mutex)
Definition threads.cc:360
void BLI_mutex_init(ThreadMutex *mutex)
Definition threads.cc:340
#define BLI_MUTEX_INITIALIZER
Definition BLI_threads.h:84
void BLI_mutex_lock(ThreadMutex *mutex)
Definition threads.cc:345
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition threads.cc:350
pthread_mutex_t ThreadMutex
Definition BLI_threads.h:83
@ SEQ_CACHE_STORE_PREPROCESSED
@ SEQ_CACHE_STORE_RAW
@ SEQ_CACHE_STORE_FINAL_OUT
@ SEQ_CACHE_STORE_COMPOSITE
@ SEQ_CACHE_PREFETCH_ENABLE
@ SEQ_CACHE_OVERRIDE
@ SEQ_TYPE_EFFECT
void IMB_refImBuf(ImBuf *ibuf)
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
unsigned int U
Definition btGjkEpa3.h:78
local_group_size(16, 16) .push_constant(Type b
double time
ImBuf * seq_disk_cache_read_file(SeqDiskCache *disk_cache, SeqCacheKey *key)
void seq_disk_cache_invalidate(SeqDiskCache *disk_cache, Scene *scene, Sequence *seq, Sequence *seq_changed, int invalidate_types)
SeqDiskCache * seq_disk_cache_create(Main *bmain, Scene *scene)
void seq_disk_cache_free(SeqDiskCache *disk_cache)
bool seq_disk_cache_enforce_limits(SeqDiskCache *disk_cache)
bool seq_disk_cache_write_file(SeqDiskCache *disk_cache, SeqCacheKey *key, ImBuf *ibuf)
bool seq_disk_cache_is_enabled(Main *bmain)
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void IMB_freeImBuf(ImBuf *)
static float seq_cache_timeline_frame_to_frame_index(const Scene *scene, const Sequence *seq, const float timeline_frame, const int type)
void SEQ_cache_iterate(Scene *scene, void *userdata, bool callback_init(void *userdata, size_t item_count), bool callback_iter(void *userdata, Sequence *seq, int timeline_frame, int cache_type))
static ImBuf * seq_cache_get_ex(SeqCache *cache, SeqCacheKey *key)
static void seq_cache_recycle_linked(Scene *scene, SeqCacheKey *base)
void SEQ_cache_cleanup(Scene *scene)
static SeqCacheKey * seq_cache_allocate_key(SeqCache *cache, const SeqRenderData *context, Sequence *seq, const float timeline_frame, const int type)
static void seq_cache_create(Main *bmain, Scene *scene)
static void seq_cache_unlock(Scene *scene)
ImBuf * seq_cache_get(const SeqRenderData *context, Sequence *seq, float timeline_frame, int type)
bool seq_cache_put_if_possible(const SeqRenderData *context, Sequence *seq, float timeline_frame, int type, ImBuf *ibuf)
static int get_stored_types_flag(Scene *scene, SeqCacheKey *key)
static SeqCacheKey * seq_cache_choose_key(Scene *scene, SeqCacheKey *lkey, SeqCacheKey *rkey)
static void seq_cache_set_temp_cache_linked(Scene *scene, SeqCacheKey *base)
static void seq_cache_valfree(void *val)
bool seq_cache_is_full()
static uint seq_hash_render_data(const SeqRenderData *a)
static uint seq_cache_hashhash(const void *key_)
void seq_cache_put(const SeqRenderData *context, Sequence *seq, float timeline_frame, int type, ImBuf *i)
void seq_cache_free_temp_cache(Scene *scene, short id, int timeline_frame)
static void seq_cache_key_unlink(SeqCacheKey *key)
static ThreadMutex cache_create_lock
static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
static void seq_cache_keyfree(void *val)
static size_t seq_cache_get_mem_total()
static void seq_cache_put_ex(Scene *scene, SeqCacheKey *key, ImBuf *ibuf)
void seq_cache_cleanup_sequence(Scene *scene, Sequence *seq, Sequence *seq_changed, int invalidate_types, bool force_seq_changed_range)
float seq_cache_frame_index_to_timeline_frame(Sequence *seq, float frame_index)
static SeqCache * seq_cache_get_from_scene(Scene *scene)
static bool seq_cache_hashcmp(const void *a_, const void *b_)
static void seq_cache_lock(Scene *scene)
void seq_cache_destruct(Scene *scene)
static void seq_cache_populate_key(SeqCacheKey *key, const SeqRenderData *context, Sequence *seq, const float timeline_frame, const int type)
static SeqCacheKey * seq_cache_get_item_for_removal(Scene *scene)
bool seq_cache_recycle_item(Scene *scene)
size_t(* MEM_get_memory_in_use)(void)
Definition mallocn.cc:62
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
static ulong * next
void seq_prefetch_get_time_range(Scene *scene, int *r_start, int *r_end)
Definition prefetch.cc:174
bool seq_prefetch_job_is_running(Scene *scene)
Definition prefetch.cc:90
void SEQ_prefetch_stop(Scene *scene)
Definition prefetch.cc:247
Sequence * seq_prefetch_get_original_sequence(Sequence *seq, Scene *scene)
Definition prefetch.cc:141
SeqRenderData * seq_prefetch_get_original_context(const SeqRenderData *context)
Definition prefetch.cc:147
_W64 int intptr_t
Definition stdint.h:118
float SEQ_give_frame_index(const Scene *scene, const Sequence *seq, float timeline_frame)
Definition strip_time.cc:60
int SEQ_time_left_handle_frame_get(const Scene *, const Sequence *seq)
float SEQ_time_start_frame_get(const Sequence *seq)
int SEQ_time_right_handle_frame_get(const Scene *scene, const Sequence *seq)
SeqCache * cache_owner
float timeline_frame
SeqCacheKey * link_next
float frame_index
SeqCache * cache_owner
eSeqTaskId task_id
SeqCacheKey * link_prev
bool is_temp_cache
SeqRenderData context
Sequence * seq
ThreadMutex iterator_mutex
BLI_mempool * items_pool
SeqCacheKey * last_key
BLI_mempool * keys_pool
GHash * hash
SeqDiskCache * disk_cache
Main * bmain
uint8_t flag
Definition wm_window.cc:138