Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py78
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h53
-rw-r--r--source/blender/blenkernel/intern/blender.c1
-rw-r--r--source/blender/blenkernel/intern/seqcache.c614
-rw-r--r--source/blender/blenkernel/intern/sequencer.c301
-rw-r--r--source/blender/blenloader/intern/readfile.c1
-rw-r--r--source/blender/blenloader/intern/versioning_280.c18
-rw-r--r--source/blender/editors/render/render_internal.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c177
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c2
-rw-r--r--source/blender/editors/transform/transform_generics.c5
-rw-r--r--source/blender/imbuf/IMB_imbuf.h7
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c29
-rw-r--r--source/blender/imbuf/intern/moviecache.c47
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h38
-rw-r--r--source/blender/makesrna/intern/rna_camera.c5
-rw-r--r--source/blender/makesrna/intern/rna_color.c10
-rw-r--r--source/blender/makesrna/intern/rna_scene.c18
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c84
20 files changed, 1068 insertions, 426 deletions
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 87ebf365a1e..bd3eb2bc304 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -159,6 +159,25 @@ class SEQUENCER_MT_view_toggle(Menu):
layout.operator("sequencer.view_toggle").type = 'SEQUENCER_PREVIEW'
+class SEQUENCER_MT_view_cache(Menu):
+ bl_label = "Cache"
+
+ def draw(self, context):
+ layout = self.layout
+
+ ed = context.scene.sequence_editor
+ layout.prop(ed, "show_cache")
+ layout.separator()
+
+ col = layout.column()
+ col.enabled = ed.show_cache
+
+ col.prop(ed, "show_cache_final_out")
+ col.prop(ed, "show_cache_raw")
+ col.prop(ed, "show_cache_preprocessed")
+ col.prop(ed, "show_cache_composite")
+
+
class SEQUENCER_MT_view(Menu):
bl_label = "View"
@@ -212,6 +231,7 @@ class SEQUENCER_MT_view(Menu):
layout.prop(st, "show_frame_indicator")
layout.prop(st, "show_strip_offset")
layout.prop(st, "show_marker_lines")
+ layout.menu("SEQUENCER_MT_view_cache")
layout.prop_menu_enum(st, "waveform_display_type")
@@ -1145,9 +1165,29 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
layout.prop(strip, "use_float", text="Convert to Float")
+class SEQUENCER_PT_cache_settings(SequencerButtonsPanel, Panel):
+ bl_label = "Cache Settings"
+ bl_category = "Proxy & Cache"
+
+ @classmethod
+ def poll(cls, context):
+ return cls.has_sequencer(context)
+
+ def draw(self, context):
+ layout = self.layout
+ ed = context.scene.sequence_editor
+
+ layout.prop(ed, "cache_raw")
+ layout.prop(ed, "cache_preprocessed")
+ layout.prop(ed, "cache_composite")
+ layout.prop(ed, "cache_final")
+ layout.separator()
+ layout.prop(ed, "recycle_max_cost")
+
+
class SEQUENCER_PT_proxy_settings(SequencerButtonsPanel, Panel):
- bl_label = "Proxy settings"
- bl_category = "Proxy"
+ bl_label = "Proxy Settings"
+ bl_category = "Proxy & Cache"
@classmethod
def poll(cls, context):
return cls.has_sequencer(context)
@@ -1168,8 +1208,8 @@ class SEQUENCER_PT_proxy_settings(SequencerButtonsPanel, Panel):
class SEQUENCER_PT_strip_proxy(SequencerButtonsPanel, Panel):
- bl_label = "Strip Proxy/Timecode"
- bl_category = "Proxy"
+ bl_label = "Strip Proxy & Timecode"
+ bl_category = "Proxy & Cache"
@classmethod
def poll(cls, context):
@@ -1225,8 +1265,33 @@ class SEQUENCER_PT_strip_proxy(SequencerButtonsPanel, Panel):
col.prop(proxy, "timecode")
+class SEQUENCER_PT_strip_cache(SequencerButtonsPanel, Panel):
+ bl_label = "Strip Cache"
+ bl_category = "Proxy & Cache"
+
+ @classmethod
+ def poll(cls, context):
+ if not cls.has_sequencer(context):
+ return False
+ if act_strip(context) is not None:
+ return True
+
+ def draw_header(self, context):
+ strip = act_strip(context)
+ self.layout.prop(strip, "override_cache_settings", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ strip = act_strip(context)
+ layout.active = strip.override_cache_settings
+
+ layout.prop(strip, "cache_raw")
+ layout.prop(strip, "cache_preprocessed")
+ layout.prop(strip, "cache_composite")
+
+
class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel):
- bl_label = "Scene Preview/Render"
+ bl_label = "Scene Preview & Render"
bl_space_type = 'SEQUENCE_EDITOR'
bl_region_type = 'UI'
bl_category = "Strip"
@@ -1411,6 +1476,7 @@ classes = (
SEQUENCER_HT_header,
SEQUENCER_MT_editor_menus,
SEQUENCER_MT_view,
+ SEQUENCER_MT_view_cache,
SEQUENCER_MT_view_toggle,
SEQUENCER_MT_select,
SEQUENCER_MT_marker,
@@ -1430,8 +1496,10 @@ classes = (
SEQUENCER_PT_scene,
SEQUENCER_PT_mask,
SEQUENCER_PT_filter,
+ SEQUENCER_PT_cache_settings,
SEQUENCER_PT_proxy_settings,
SEQUENCER_PT_strip_proxy,
+ SEQUENCER_PT_strip_cache,
SEQUENCER_PT_preview,
SEQUENCER_PT_view,
SEQUENCER_PT_view_safe_areas,
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 16655d9b060..e01f6a6b751 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,7 +27,7 @@
* \note Use #STRINGIFY() rather than defining with quotes.
*/
#define BLENDER_VERSION 280
-#define BLENDER_SUBVERSION 59
+#define BLENDER_SUBVERSION 60
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 820f28fb363..5485b2d3619 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -302,46 +302,33 @@ void BKE_sequencer_proxy_set(struct Sequence *seq, bool value);
* Sequencer memory cache management functions
* ********************************************************************** */
-typedef enum {
- SEQ_STRIPELEM_IBUF,
- SEQ_STRIPELEM_IBUF_COMP,
- SEQ_STRIPELEM_IBUF_STARTSTILL,
- SEQ_STRIPELEM_IBUF_ENDSTILL,
-} eSeqStripElemIBuf;
+#define SEQ_CACHE_COST_MAX 10.0f
-void BKE_sequencer_cache_destruct(void);
-void BKE_sequencer_cache_cleanup(void);
-
-/* returned ImBuf is properly refed and has to be freed */
struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context,
struct Sequence *seq,
float cfra,
- eSeqStripElemIBuf type);
-
-/* passed ImBuf is properly refed, so ownership is *not*
- * transferred to the cache.
- * you can pass the same ImBuf multiple times to the cache without problems.
- */
-
+ int type);
void BKE_sequencer_cache_put(const SeqRenderData *context,
struct Sequence *seq,
float cfra,
- eSeqStripElemIBuf type,
- struct ImBuf *nval);
-
-void BKE_sequencer_cache_cleanup_sequence(struct Sequence *seq);
-
-struct ImBuf *BKE_sequencer_preprocessed_cache_get(const SeqRenderData *context,
- struct Sequence *seq,
- float cfra,
- eSeqStripElemIBuf type);
-void BKE_sequencer_preprocessed_cache_put(const SeqRenderData *context,
- struct Sequence *seq,
- float cfra,
- eSeqStripElemIBuf type,
- struct ImBuf *ibuf);
-void BKE_sequencer_preprocessed_cache_cleanup(void);
-void BKE_sequencer_preprocessed_cache_cleanup_sequence(struct Sequence *seq);
+ int type,
+ struct ImBuf *nval,
+ float cost);
+bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context,
+ struct Sequence *seq,
+ float cfra,
+ int type,
+ struct ImBuf *nval,
+ float cost);
+void BKE_sequencer_cache_free_temp_cache(struct Scene *scene, short id, int cfra);
+void BKE_sequencer_cache_destruct(struct Scene *scene);
+void BKE_sequencer_cache_cleanup_all(struct Main *bmain);
+void BKE_sequencer_cache_cleanup(struct Scene *scene);
+void BKE_sequencer_cache_cleanup_sequence(struct Scene *scene, struct Sequence *seq);
+void BKE_sequencer_cache_iterate(
+ struct Scene *scene,
+ void *userdata,
+ bool callback(void *userdata, struct Sequence *seq, int cfra, int cache_type, float cost));
/* **********************************************************************
* seqeffects.c
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index d6599498a65..48b271cf277 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -97,7 +97,6 @@ void BKE_blender_free(void)
BLI_callback_global_finalize();
- BKE_sequencer_cache_destruct();
IMB_moviecache_destruct();
free_nodesystem();
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index b022819ca8c..c50f3f3f141 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -21,49 +21,84 @@
*/
#include <stddef.h>
-
-#include "BLI_sys_types.h" /* for intptr_t */
+#include <memory.h>
#include "MEM_guardedalloc.h"
#include "DNA_sequence_types.h"
#include "DNA_scene_types.h"
-#include "IMB_moviecache.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "BLI_mempool.h"
+#include "BLI_threads.h"
#include "BLI_listbase.h"
+#include "BLI_ghash.h"
#include "BKE_sequencer.h"
#include "BKE_scene.h"
+#include "BKE_main.h"
+
+/* ***************************** Sequencer cache design notes ******************************
+ *
+ * Cache key members:
+ * is_temp_cache - this cache entry will be freed before rendering next frame
+ * creator_id - ID of thread that created entry
+ * cost - In short: render time divided by playback frame rate
+ * link_prev/next - link to another entry created during rendering of the frame
+ *
+ * Linking: We use links to reduce number of iterations needed to manage cache.
+ * Entries are linked in order as they are put into cache.
+ * Only pernament (is_temp_cache = 0) cache entries are linked.
+ * Putting SEQ_CACHE_STORE_FINAL_OUT will reset linking
+ *
+ * Function:
+ * All images created during rendering are added to cache, even if the cache is already full.
+ * This is because:
+ * - one image may be needed multiple times during rendering.
+ * - keeping the last rendered frame allows us for faster re-render when user edits strip in stack
+ * - we can decide if we keep frame only when it's completely rendered. Otherwise we risk having
+ * "holes" in the cache, which can be annoying
+ * If the cache is full all entries for pending frame will have is_temp_cache set.
+ *
+ * Only entire frame can be freed to release resources for new entries (recycling).
+ * Once again, this is to reduce number of iterations, but also more controllable than removing
+ * entries one by one in reverse order to their creation.
+ *
+ * User can exclude caching of some images. Such entries will have is_temp_cache set.
+ */
+
+typedef struct SeqCache {
+ struct GHash *hash;
+ ThreadMutex iterator_mutex;
+ struct BLI_mempool *keys_pool;
+ struct BLI_mempool *items_pool;
+ struct SeqCacheKey *last_key;
+ size_t memory_used;
+} SeqCache;
+
+typedef struct SeqCacheItem {
+ struct SeqCache *cache_owner;
+ struct ImBuf *ibuf;
+} SeqCacheItem;
typedef struct SeqCacheKey {
+ struct SeqCache *cache_owner;
+ void *userkey;
+ struct SeqCacheKey *link_prev; /* Used for linking intermediate items to final frame */
+ struct SeqCacheKey *link_next; /* Used for linking intermediate items to final frame */
struct Sequence *seq;
SeqRenderData context;
float cfra;
- eSeqStripElemIBuf type;
+ float nfra;
+ float cost;
+ bool is_temp_cache;
+ short creator_id;
+ int type;
} SeqCacheKey;
-typedef struct SeqPreprocessCacheElem {
- struct SeqPreprocessCacheElem *next, *prev;
-
- struct Sequence *seq;
- SeqRenderData context;
- eSeqStripElemIBuf type;
-
- ImBuf *ibuf;
-} SeqPreprocessCacheElem;
-
-typedef struct SeqPreprocessCache {
- int cfra;
- ListBase elems;
-} SeqPreprocessCache;
-
-static struct MovieCache *moviecache = NULL;
-static struct SeqPreprocessCache *preprocess_cache = NULL;
-
-static void preprocessed_cache_destruct(void);
+static ThreadMutex cache_create_lock = BLI_MUTEX_INITIALIZER;
static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
{
@@ -88,209 +123,536 @@ static unsigned int seq_hash_render_data(const SeqRenderData *a)
return rval;
}
-static unsigned int seqcache_hashhash(const void *key_)
+static unsigned int seq_cache_hashhash(const void *key_)
{
const SeqCacheKey *key = key_;
unsigned int rval = seq_hash_render_data(&key->context);
- rval ^= *(const unsigned int *)&key->cfra;
+ rval ^= *(const unsigned int *)&key->nfra;
rval += key->type;
rval ^= ((intptr_t)key->seq) << 6;
return rval;
}
-static bool seqcache_hashcmp(const void *a_, const void *b_)
+static bool seq_cache_hashcmp(const void *a_, const void *b_)
{
const SeqCacheKey *a = a_;
const SeqCacheKey *b = b_;
- return ((a->seq != b->seq) || (a->cfra != b->cfra) || (a->type != b->type) ||
+ return ((a->seq != b->seq) || (a->nfra != b->nfra) || (a->type != b->type) ||
seq_cmp_render_data(&a->context, &b->context));
}
-void BKE_sequencer_cache_destruct(void)
+static SeqCache *seq_cache_get_from_scene(Scene *scene)
{
- if (moviecache) {
- IMB_moviecache_free(moviecache);
+ if (scene && scene->ed && scene->ed->cache) {
+ return scene->ed->cache;
}
- preprocessed_cache_destruct();
+ return NULL;
+}
+
+static void seq_cache_lock(Scene *scene)
+{
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+
+ if (cache) {
+ BLI_mutex_lock(&cache->iterator_mutex);
+ }
}
-void BKE_sequencer_cache_cleanup(void)
+static void seq_cache_unlock(Scene *scene)
{
- if (moviecache) {
- IMB_moviecache_free(moviecache);
- moviecache = IMB_moviecache_create(
- "seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+
+ if (cache) {
+ BLI_mutex_unlock(&cache->iterator_mutex);
}
+}
- BKE_sequencer_preprocessed_cache_cleanup();
+static void seq_cache_keyfree(void *val)
+{
+ SeqCacheKey *key = val;
+ BLI_mempool_free(key->cache_owner->keys_pool, key);
}
-static bool seqcache_key_check_seq(ImBuf *UNUSED(ibuf), void *userkey, void *userdata)
+static void seq_cache_valfree(void *val)
{
- SeqCacheKey *key = (SeqCacheKey *)userkey;
- Sequence *seq = (Sequence *)userdata;
+ SeqCacheItem *item = (SeqCacheItem *)val;
+ SeqCache *cache = item->cache_owner;
+
+ if (item->ibuf) {
+ cache->memory_used -= IMB_get_size_in_memory(item->ibuf);
+ IMB_freeImBuf(item->ibuf);
+ }
- return key->seq == seq;
+ BLI_mempool_free(item->cache_owner->items_pool, item);
}
-void BKE_sequencer_cache_cleanup_sequence(Sequence *seq)
+static void seq_cache_put(SeqCache *cache, SeqCacheKey *key, ImBuf *ibuf)
{
- if (moviecache) {
- IMB_moviecache_cleanup(moviecache, seqcache_key_check_seq, seq);
+ SeqCacheItem *item;
+ item = BLI_mempool_alloc(cache->items_pool);
+ item->cache_owner = cache;
+ item->ibuf = ibuf;
+
+ if (BLI_ghash_reinsert(cache->hash, key, item, seq_cache_keyfree, seq_cache_valfree)) {
+ IMB_refImBuf(ibuf);
+ cache->last_key = key;
+ cache->memory_used += IMB_get_size_in_memory(ibuf);
}
}
-struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context,
- Sequence *seq,
- float cfra,
- eSeqStripElemIBuf type)
+static ImBuf *seq_cache_get(SeqCache *cache, void *key)
{
- if (moviecache && seq) {
- SeqCacheKey key;
+ SeqCacheItem *item = BLI_ghash_lookup(cache->hash, key);
- key.seq = seq;
- key.context = *context;
- key.cfra = cfra - seq->start;
- key.type = type;
+ if (item && item->ibuf) {
+ IMB_refImBuf(item->ibuf);
- return IMB_moviecache_get(moviecache, &key);
+ return item->ibuf;
}
return NULL;
}
-void BKE_sequencer_cache_put(
- const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *i)
+static void seq_cache_relink_keys(SeqCacheKey *link_next, SeqCacheKey *link_prev)
+{
+ if (link_next) {
+ link_next->link_prev = link_prev;
+ }
+ if (link_prev) {
+ link_prev->link_next = link_next;
+ }
+}
+
+static SeqCacheKey *seq_cache_choose_key(Scene *scene, SeqCacheKey *lkey, SeqCacheKey *rkey)
{
- SeqCacheKey key;
+ SeqCacheKey *finalkey = NULL;
+
+ if (rkey && lkey) {
+ if (lkey->cfra > rkey->cfra) {
+ SeqCacheKey *swapkey = lkey;
+ lkey = rkey;
+ rkey = swapkey;
+ }
+
+ int l_diff = scene->r.cfra - lkey->cfra;
+ int r_diff = rkey->cfra - scene->r.cfra;
+
+ if (l_diff > r_diff) {
+ finalkey = lkey;
+ }
+ else {
+ finalkey = rkey;
+ }
+ }
+ else {
+ if (lkey) {
+ finalkey = lkey;
+ }
+ else {
+ finalkey = rkey;
+ }
+ }
+ return finalkey;
+}
- if (i == NULL || context->skip_cache) {
+static void seq_cache_recycle_linked(Scene *scene, SeqCacheKey *base)
+{
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ if (!cache) {
return;
}
- if (!moviecache) {
- moviecache = IMB_moviecache_create(
- "seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
+ SeqCacheKey *next = base->link_next;
+
+ while (base) {
+ SeqCacheKey *prev = base->link_prev;
+ BLI_ghash_remove(cache->hash, base, seq_cache_keyfree, seq_cache_valfree);
+ base = prev;
+ }
+
+ base = next;
+ while (base) {
+ next = base->link_next;
+ BLI_ghash_remove(cache->hash, base, seq_cache_keyfree, seq_cache_valfree);
+ base = next;
+ }
+}
+
+static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene)
+{
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ SeqCacheKey *finalkey = NULL;
+ /*leftmost key*/
+ SeqCacheKey *lkey = NULL;
+ /*rightmost key*/
+ SeqCacheKey *rkey = NULL;
+ SeqCacheKey *key = NULL;
+
+ GHashIterator gh_iter;
+ BLI_ghashIterator_init(&gh_iter, cache->hash);
+ int total_count = 0;
+ int cheap_count = 0;
+
+ while (!BLI_ghashIterator_done(&gh_iter)) {
+ key = BLI_ghashIterator_getKey(&gh_iter);
+ SeqCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
+ BLI_ghashIterator_step(&gh_iter);
+
+ /* this shouldn't happen, but better be safe than sorry */
+ if (!item->ibuf) {
+ seq_cache_recycle_linked(scene, key);
+ /* can not continue iterating after linked remove */
+ BLI_ghashIterator_init(&gh_iter, cache->hash);
+ continue;
+ }
+
+ if (key->is_temp_cache || key->link_next != NULL) {
+ continue;
+ }
+
+ total_count++;
+
+ if (key->cost <= scene->ed->recycle_max_cost) {
+ cheap_count++;
+ if (lkey) {
+ if (key->cfra < lkey->cfra) {
+ lkey = key;
+ }
+ }
+ else {
+ lkey = key;
+ }
+ if (rkey) {
+ if (key->cfra > rkey->cfra) {
+ rkey = key;
+ }
+ }
+ else {
+ rkey = key;
+ }
+ }
+ }
+
+ finalkey = seq_cache_choose_key(scene, lkey, rkey);
+ return finalkey;
+}
+
+/* Find only "base" keys
+ * Sources(other types) for a frame must be freed all at once
+ */
+static bool seq_cache_recycle_item(Scene *scene)
+{
+ size_t memory_total = ((size_t)U.memcachelimit) * 1024 * 1024;
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ if (!cache) {
+ return false;
}
- key.seq = seq;
- key.context = *context;
- key.cfra = cfra - seq->start;
- key.type = type;
+ seq_cache_lock(scene);
+
+ while (cache->memory_used > memory_total) {
+ SeqCacheKey *finalkey = seq_cache_get_item_for_removal(scene);
- IMB_moviecache_put(moviecache, &key, i);
+ if (finalkey) {
+ seq_cache_recycle_linked(scene, finalkey);
+ }
+ else {
+ seq_cache_unlock(scene);
+ return false;
+ }
+ }
+ seq_cache_unlock(scene);
+ return true;
}
-void BKE_sequencer_preprocessed_cache_cleanup(void)
+static void seq_cache_set_temp_cache_linked(Scene *scene, SeqCacheKey *base)
{
- SeqPreprocessCacheElem *elem;
+ SeqCache *cache = seq_cache_get_from_scene(scene);
- if (!preprocess_cache) {
+ if (!cache || !base) {
return;
}
- for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
- IMB_freeImBuf(elem->ibuf);
+ SeqCacheKey *next = base->link_next;
+
+ while (base) {
+ SeqCacheKey *prev = base->link_prev;
+ base->is_temp_cache = true;
+ base = prev;
}
- BLI_freelistN(&preprocess_cache->elems);
- BLI_listbase_clear(&preprocess_cache->elems);
+ base = next;
+ while (base) {
+ next = base->link_next;
+ base->is_temp_cache = true;
+ base = next;
+ }
}
-static void preprocessed_cache_destruct(void)
+static void BKE_sequencer_cache_create(Scene *scene)
{
- if (!preprocess_cache) {
+ BLI_mutex_lock(&cache_create_lock);
+ if (scene->ed->cache == NULL) {
+ SeqCache *cache = MEM_callocN(sizeof(SeqCache), "SeqCache");
+ cache->keys_pool = BLI_mempool_create(sizeof(SeqCacheKey), 0, 64, BLI_MEMPOOL_NOP);
+ cache->items_pool = BLI_mempool_create(sizeof(SeqCacheItem), 0, 64, BLI_MEMPOOL_NOP);
+ cache->hash = BLI_ghash_new(seq_cache_hashhash, seq_cache_hashcmp, "SeqCache hash");
+ cache->last_key = NULL;
+ BLI_mutex_init(&cache->iterator_mutex);
+ scene->ed->cache = cache;
+ }
+ BLI_mutex_unlock(&cache_create_lock);
+}
+
+/* ***************************** API ****************************** */
+
+void BKE_sequencer_cache_free_temp_cache(Scene *scene, short id, int cfra)
+{
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ if (!cache) {
return;
}
- BKE_sequencer_preprocessed_cache_cleanup();
+ seq_cache_lock(scene);
- MEM_freeN(preprocess_cache);
- preprocess_cache = NULL;
+ GHashIterator gh_iter;
+ BLI_ghashIterator_init(&gh_iter, cache->hash);
+ while (!BLI_ghashIterator_done(&gh_iter)) {
+ SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
+ BLI_ghashIterator_step(&gh_iter);
+
+ if (key->is_temp_cache && key->creator_id == id && key->cfra != cfra) {
+ BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree);
+ }
+ }
+ seq_cache_unlock(scene);
}
-ImBuf *BKE_sequencer_preprocessed_cache_get(const SeqRenderData *context,
- Sequence *seq,
- float cfra,
- eSeqStripElemIBuf type)
+void BKE_sequencer_cache_destruct(Scene *scene)
{
- SeqPreprocessCacheElem *elem;
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ if (!cache) {
+ return;
+ }
- if (!preprocess_cache) {
- return NULL;
+ BLI_ghash_free(cache->hash, seq_cache_keyfree, seq_cache_valfree);
+ BLI_mempool_destroy(cache->keys_pool);
+ BLI_mempool_destroy(cache->items_pool);
+ BLI_mutex_end(&cache->iterator_mutex);
+ MEM_freeN(cache);
+ scene->ed->cache = NULL;
+}
+
+void BKE_sequencer_cache_cleanup_all(Main *bmain)
+{
+ for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ BKE_sequencer_cache_cleanup(scene);
+ }
+}
+void BKE_sequencer_cache_cleanup(Scene *scene)
+{
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ if (!cache) {
+ return;
}
- if (preprocess_cache->cfra != cfra) {
- return NULL;
+ seq_cache_lock(scene);
+
+ GHashIterator gh_iter;
+ BLI_ghashIterator_init(&gh_iter, cache->hash);
+ while (!BLI_ghashIterator_done(&gh_iter)) {
+ SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
+
+ BLI_ghashIterator_step(&gh_iter);
+ BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree);
}
+ cache->last_key = NULL;
+ seq_cache_unlock(scene);
+}
- for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
- if (elem->seq != seq) {
- continue;
- }
+void BKE_sequencer_cache_cleanup_sequence(Scene *scene, Sequence *seq)
+{
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ if (!cache) {
+ return;
+ }
- if (elem->type != type) {
- continue;
- }
+ seq_cache_lock(scene);
- if (seq_cmp_render_data(&elem->context, context) != 0) {
- continue;
+ GHashIterator gh_iter;
+ BLI_ghashIterator_init(&gh_iter, cache->hash);
+ while (!BLI_ghashIterator_done(&gh_iter)) {
+ SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
+ BLI_ghashIterator_step(&gh_iter);
+
+ if (key->seq == seq) {
+ /* Relink keys, so we don't end up with orphaned keys */
+ if (key->link_next || key->link_prev) {
+ seq_cache_relink_keys(key->link_next, key->link_prev);
+ }
+
+ BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree);
}
+ }
+ cache->last_key = NULL;
+ seq_cache_unlock(scene);
+}
+
+struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ int type)
+{
+ Scene *scene = context->scene;
- IMB_refImBuf(elem->ibuf);
- return elem->ibuf;
+ if (!scene->ed->cache) {
+ BKE_sequencer_cache_create(scene);
+ return NULL;
}
- return NULL;
+ seq_cache_lock(scene);
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ ImBuf *ibuf = NULL;
+
+ if (cache && seq) {
+ SeqCacheKey key;
+
+ key.seq = seq;
+ key.context = *context;
+ key.nfra = cfra - seq->start;
+ key.type = type;
+
+ ibuf = seq_cache_get(cache, &key);
+ }
+ seq_cache_unlock(scene);
+
+ return ibuf;
}
-void BKE_sequencer_preprocessed_cache_put(
- const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *ibuf)
+bool BKE_sequencer_cache_put_if_possible(
+ const SeqRenderData *context, Sequence *seq, float cfra, int type, ImBuf *ibuf, float cost)
{
- SeqPreprocessCacheElem *elem;
+ Scene *scene = context->scene;
- if (!preprocess_cache) {
- preprocess_cache = MEM_callocN(sizeof(SeqPreprocessCache), "sequencer preprocessed cache");
+ if (seq_cache_recycle_item(scene)) {
+ BKE_sequencer_cache_put(context, seq, cfra, type, ibuf, cost);
+ return true;
}
else {
- if (preprocess_cache->cfra != cfra) {
- BKE_sequencer_preprocessed_cache_cleanup();
- }
+ seq_cache_set_temp_cache_linked(scene, scene->ed->cache->last_key);
+ scene->ed->cache->last_key = NULL;
+ return false;
}
+}
+
+void BKE_sequencer_cache_put(
+ const SeqRenderData *context, Sequence *seq, float cfra, int type, ImBuf *i, float cost)
+{
+ Scene *scene = context->scene;
+ short creator_id = 0;
- elem = MEM_callocN(sizeof(SeqPreprocessCacheElem), "sequencer preprocessed cache element");
+ if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) {
+ return;
+ }
- elem->seq = seq;
- elem->type = type;
- elem->context = *context;
- elem->ibuf = ibuf;
+ /* Prevent reinserting, it breaks cache key linking */
+ ImBuf *test = BKE_sequencer_cache_get(context, seq, cfra, type);
+ if (test) {
+ IMB_freeImBuf(test);
+ return;
+ }
- preprocess_cache->cfra = cfra;
+ if (!scene->ed->cache) {
+ BKE_sequencer_cache_create(scene);
+ }
- IMB_refImBuf(ibuf);
+ seq_cache_lock(scene);
- BLI_addtail(&preprocess_cache->elems, elem);
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ int flag;
+
+ if (seq->cache_flag & SEQ_CACHE_OVERRIDE) {
+ flag = seq->cache_flag;
+ flag |= scene->ed->cache_flag & SEQ_CACHE_STORE_FINAL_OUT;
+ }
+ else {
+ flag = scene->ed->cache_flag;
+ }
+
+ if (cost > SEQ_CACHE_COST_MAX) {
+ cost = SEQ_CACHE_COST_MAX;
+ }
+
+ SeqCacheKey *key;
+ key = BLI_mempool_alloc(cache->keys_pool);
+ key->cache_owner = cache;
+ key->seq = seq;
+ key->context = *context;
+ key->cfra = cfra;
+ key->nfra = cfra - seq->start;
+ key->type = type;
+ key->cost = cost;
+ key->cache_owner = cache;
+ key->link_prev = NULL;
+ key->link_next = NULL;
+ key->is_temp_cache = true;
+ key->creator_id = creator_id;
+
+ /* Item stored for later use */
+ if (flag & type) {
+ key->is_temp_cache = false;
+ key->link_prev = cache->last_key;
+ }
+
+ SeqCacheKey *temp_last_key = cache->last_key;
+ seq_cache_put(cache, key, i);
+
+ /* Restore pointer to previous item as this one will be freed when stack is rendered */
+ if (key->is_temp_cache) {
+ cache->last_key = temp_last_key;
+ }
+
+ /* Set last_key's reference to this key so we can look up chain backwards
+ * Item is already put in cache, so cache->last_key points to current key;
+ */
+ if (flag & type && temp_last_key) {
+ temp_last_key->link_next = cache->last_key;
+ }
+
+ /* Reset linking */
+ if (key->type == SEQ_CACHE_STORE_FINAL_OUT) {
+ cache->last_key = NULL;
+ }
+
+ seq_cache_unlock(scene);
}
-void BKE_sequencer_preprocessed_cache_cleanup_sequence(Sequence *seq)
+void BKE_sequencer_cache_iterate(
+ struct Scene *scene,
+ void *userdata,
+ bool callback(void *userdata, struct Sequence *seq, int cfra, int cache_type, float cost))
{
- SeqPreprocessCacheElem *elem, *elem_next;
-
- if (!preprocess_cache) {
+ SeqCache *cache = seq_cache_get_from_scene(scene);
+ if (!cache) {
return;
}
- for (elem = preprocess_cache->elems.first; elem; elem = elem_next) {
- elem_next = elem->next;
+ seq_cache_lock(scene);
+ GHashIterator gh_iter;
+ BLI_ghashIterator_init(&gh_iter, cache->hash);
+ bool interrupt = false;
- if (elem->seq == seq) {
- IMB_freeImBuf(elem->ibuf);
+ while (!BLI_ghashIterator_done(&gh_iter) && !interrupt) {
+ SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
+ BLI_ghashIterator_step(&gh_iter);
- BLI_freelinkN(&preprocess_cache->elems, elem);
- }
+ interrupt = callback(userdata, key->seq, key->cfra, key->type, key->cost);
}
+
+ cache->last_key = NULL;
+ seq_cache_unlock(scene);
}
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 68c2869b5d2..2887f30532e 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -27,7 +27,7 @@
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
-#include <math.h>
+#include <time.h>
#include "MEM_guardedalloc.h"
@@ -464,6 +464,11 @@ Editing *BKE_sequencer_editing_ensure(Scene *scene)
ed = scene->ed = MEM_callocN(sizeof(Editing), "addseq");
ed->seqbasep = &ed->seqbase;
+ ed->cache = NULL;
+ ed->cache_flag = SEQ_CACHE_STORE_FINAL_OUT;
+ ed->cache_flag |= SEQ_CACHE_VIEW_FINAL_OUT;
+ ed->cache_flag |= SEQ_CACHE_VIEW_ENABLE;
+ ed->recycle_max_cost = 10.0f;
}
return scene->ed;
@@ -478,8 +483,7 @@ void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
return;
}
- /* this may not be the active scene!, could be smarter about this */
- BKE_sequencer_cache_cleanup();
+ BKE_sequencer_cache_destruct(scene);
SEQ_BEGIN (ed, seq) {
/* handle cache freeing above */
@@ -2639,7 +2643,7 @@ bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context,
{
float mul;
- if (context->is_proxy_render) {
+ if (context && context->is_proxy_render) {
return false;
}
@@ -2809,54 +2813,6 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
return ibuf;
}
-static ImBuf *copy_from_ibuf_still(const SeqRenderData *context, Sequence *seq, float nr)
-{
- ImBuf *rval = NULL;
- ImBuf *ibuf = NULL;
-
- if (nr == 0) {
- ibuf = BKE_sequencer_cache_get(context, seq, seq->start, SEQ_STRIPELEM_IBUF_STARTSTILL);
- }
- else if (nr == seq->len - 1) {
- ibuf = BKE_sequencer_cache_get(context, seq, seq->start, SEQ_STRIPELEM_IBUF_ENDSTILL);
- }
-
- if (ibuf) {
- rval = IMB_dupImBuf(ibuf);
- IMB_metadata_copy(rval, ibuf);
- IMB_freeImBuf(ibuf);
- }
-
- return rval;
-}
-
-static void copy_to_ibuf_still(const SeqRenderData *context, Sequence *seq, float nr, ImBuf *ibuf)
-{
- /* warning: ibuf may be NULL if the video fails to load */
- if (nr == 0 || nr == seq->len - 1) {
- /* we have to store a copy, since the passed ibuf
- * could be preprocessed afterwards (thereby silently
- * changing the cached image... */
- ImBuf *oibuf = ibuf;
- ibuf = IMB_dupImBuf(oibuf);
-
- if (ibuf) {
- IMB_metadata_copy(ibuf, oibuf);
- sequencer_imbuf_assign_spaces(context->scene, ibuf);
- }
-
- if (nr == 0) {
- BKE_sequencer_cache_put(context, seq, seq->start, SEQ_STRIPELEM_IBUF_STARTSTILL, ibuf);
- }
-
- if (nr == seq->len - 1) {
- BKE_sequencer_cache_put(context, seq, seq->start, SEQ_STRIPELEM_IBUF_ENDSTILL, ibuf);
- }
-
- IMB_freeImBuf(ibuf);
- }
-}
-
/*********************** strip rendering functions *************************/
typedef struct RenderEffectInitData {
@@ -3062,7 +3018,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
static ImBuf *seq_render_image_strip(const SeqRenderData *context,
Sequence *seq,
- float nr,
+ float UNUSED(nr),
float cfra)
{
ImBuf *ibuf = NULL;
@@ -3138,8 +3094,8 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
if (i != context->view_id) {
- copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
- BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
+ BKE_sequencer_cache_put(
+ &localcontext, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibufs_arr[i], 0);
}
}
}
@@ -3253,8 +3209,8 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[i], false);
}
if (i != context->view_id) {
- copy_to_ibuf_still(&localcontext, seq, nr, ibuf_arr[i]);
- BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf_arr[i]);
+ BKE_sequencer_cache_put(
+ &localcontext, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibuf_arr[i], 0);
}
}
@@ -3656,8 +3612,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
}
if (i != context->view_id) {
- copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
- BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_CACHE_STORE_RAW, ibufs_arr[i], 0);
}
RE_ReleaseResultImage(re);
@@ -3781,8 +3736,6 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
/* Scene strips update all animation, so we need to restore original state.*/
BKE_animsys_evaluate_all_animation(
context->bmain, context->depsgraph, context->scene, cfra);
-
- copy_to_ibuf_still(context, seq, nr, ibuf);
}
break;
}
@@ -3820,13 +3773,11 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
case SEQ_TYPE_IMAGE: {
ibuf = seq_render_image_strip(context, seq, nr, cfra);
- copy_to_ibuf_still(context, seq, nr, ibuf);
break;
}
case SEQ_TYPE_MOVIE: {
ibuf = seq_render_movie_strip(context, seq, nr, cfra);
- copy_to_ibuf_still(context, seq, nr, ibuf);
break;
}
@@ -3842,8 +3793,6 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
if (ibuf->rect_float) {
BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
}
-
- copy_to_ibuf_still(context, seq, nr, ibuf);
}
break;
@@ -3852,8 +3801,6 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
case SEQ_TYPE_MASK: {
/* ibuf is always new */
ibuf = seq_render_mask_strip(context, seq, nr);
-
- copy_to_ibuf_still(context, seq, nr, ibuf);
break;
}
}
@@ -3865,6 +3812,26 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
return ibuf;
}
+/* Estimate time spent by the program rendering the strip */
+static clock_t seq_estimate_render_cost_begin(void)
+{
+ return clock();
+}
+
+static float seq_estimate_render_cost_end(Scene *scene, clock_t begin)
+{
+ clock_t end = clock();
+ float time_spent = (float)(end - begin);
+ float time_max = (1.0f / scene->r.frs_sec) * CLOCKS_PER_SEC;
+
+ if (time_max != 0) {
+ return time_spent / time_max;
+ }
+ else {
+ return 1;
+ }
+}
+
static ImBuf *seq_render_strip(const SeqRenderData *context,
SeqRenderState *state,
Sequence *seq,
@@ -3873,37 +3840,32 @@ static ImBuf *seq_render_strip(const SeqRenderData *context,
ImBuf *ibuf = NULL;
bool use_preprocess = false;
bool is_proxy_image = false;
- float nr = give_stripelem_index(seq, cfra);
/* all effects are handled similarly with the exception of speed effect */
int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT :
seq->type;
bool is_preprocessed = !ELEM(
type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP);
- ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
+ clock_t begin = seq_estimate_render_cost_begin();
- if (ibuf == NULL) {
- ibuf = copy_from_ibuf_still(context, seq, nr);
+ ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED);
+ if (ibuf == NULL) {
+ ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_RAW);
if (ibuf == NULL) {
- ibuf = BKE_sequencer_preprocessed_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
+ /* MOVIECLIPs have their own proxy management */
+ if (seq->type != SEQ_TYPE_MOVIECLIP) {
+ ibuf = seq_proxy_fetch(context, seq, cfra);
+ is_proxy_image = (ibuf != NULL);
+ }
if (ibuf == NULL) {
- /* MOVIECLIPs have their own proxy management */
- if (seq->type != SEQ_TYPE_MOVIECLIP) {
- ibuf = seq_proxy_fetch(context, seq, cfra);
- is_proxy_image = (ibuf != NULL);
- }
-
- if (ibuf == NULL) {
- ibuf = do_render_strip_uncached(context, state, seq, cfra);
- }
+ ibuf = do_render_strip_uncached(context, state, seq, cfra);
+ }
- if (ibuf) {
- if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) {
- is_proxy_image = (context->preview_render_size != 100);
- }
- BKE_sequencer_preprocessed_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf);
+ if (ibuf) {
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) {
+ is_proxy_image = (context->preview_render_size != 100);
}
}
}
@@ -3911,30 +3873,29 @@ static ImBuf *seq_render_strip(const SeqRenderData *context,
if (ibuf) {
use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
}
- }
- else {
- /* currently, we cache preprocessed images in SEQ_STRIPELEM_IBUF,
- * but not(!) on SEQ_STRIPELEM_IBUF_ENDSTILL and ..._STARTSTILL
- * so, no need in check for preprocess here
- */
- }
- if (ibuf == NULL) {
- ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- sequencer_imbuf_assign_spaces(context->scene, ibuf);
- }
+ if (ibuf == NULL) {
+ ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ sequencer_imbuf_assign_spaces(context->scene, ibuf);
+ }
- if (context->is_proxy_render == false &&
- (ibuf->x != context->rectx || ibuf->y != context->recty)) {
- use_preprocess = true;
- }
+ if (context->is_proxy_render == false &&
+ (ibuf->x != context->rectx || ibuf->y != context->recty)) {
+ use_preprocess = true;
+ }
- if (use_preprocess) {
- ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image, is_preprocessed);
- }
+ if (use_preprocess) {
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_RAW, ibuf, cost);
- BKE_sequencer_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf);
+ /* reset timer so we can get partial render time */
+ begin = seq_estimate_render_cost_begin();
+ ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image, is_preprocessed);
+ }
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibuf, cost);
+ }
return ibuf;
}
@@ -4015,6 +3976,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
int count;
int i;
ImBuf *out = NULL;
+ clock_t begin;
count = get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr);
@@ -4022,73 +3984,11 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
return NULL;
}
-#if 0 /* commentind since this breaks keyframing, since it resets the value on draw */
- if (scene->r.cfra != cfra) {
- /* XXX for prefetch and overlay offset!..., very bad!!! */
- AnimData *adt = BKE_animdata_from_id(&scene->id);
- BKE_animsys_evaluate_animdata(scene, &scene->id, adt, cfra, ADT_RECALC_ANIM);
- }
-#endif
-
- out = BKE_sequencer_cache_get(context, seq_arr[count - 1], cfra, SEQ_STRIPELEM_IBUF_COMP);
-
- if (out) {
- return out;
- }
-
- if (count == 1) {
- Sequence *seq = seq_arr[0];
-
- /* Some of the blend modes are unclear how to apply with only single input,
- * or some of them will just produce an empty result..
- */
- if (ELEM(seq->blend_mode, SEQ_BLEND_REPLACE, SEQ_TYPE_CROSS, SEQ_TYPE_ALPHAOVER)) {
- int early_out;
- if (seq->blend_mode == SEQ_BLEND_REPLACE) {
- early_out = EARLY_NO_INPUT;
- }
- else {
- early_out = seq_get_early_out_for_blend_mode(seq);
- }
-
- if (ELEM(early_out, EARLY_NO_INPUT, EARLY_USE_INPUT_2)) {
- out = seq_render_strip(context, state, seq, cfra);
- }
- else if (early_out == EARLY_USE_INPUT_1) {
- out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- }
- else {
- out = seq_render_strip(context, state, seq, cfra);
-
- if (early_out == EARLY_DO_EFFECT) {
- ImBuf *ibuf1 = IMB_allocImBuf(
- context->rectx, context->recty, 32, out->rect_float ? IB_rectfloat : IB_rect);
- ImBuf *ibuf2 = out;
-
- out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
- if (out) {
- IMB_metadata_copy(out, ibuf2);
- }
-
- IMB_freeImBuf(ibuf1);
- IMB_freeImBuf(ibuf2);
- }
- }
- }
- else {
- out = seq_render_strip(context, state, seq, cfra);
- }
-
- BKE_sequencer_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF_COMP, out);
-
- return out;
- }
-
for (i = count - 1; i >= 0; i--) {
int early_out;
Sequence *seq = seq_arr[i];
- out = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF_COMP);
+ out = BKE_sequencer_cache_get(context, seq, cfra, SEQ_CACHE_STORE_COMPOSITE);
if (out) {
break;
@@ -4112,15 +4012,19 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
break;
case EARLY_DO_EFFECT:
if (i == 0) {
+ begin = seq_estimate_render_cost_begin();
+
ImBuf *ibuf1 = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
ImBuf *ibuf2 = seq_render_strip(context, state, seq, cfra);
out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put(context, seq_arr[i], cfra, SEQ_CACHE_STORE_COMPOSITE, out, cost);
+
IMB_freeImBuf(ibuf1);
IMB_freeImBuf(ibuf2);
}
-
break;
}
if (out) {
@@ -4128,11 +4032,9 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
}
}
- BKE_sequencer_cache_put(context, seq_arr[i], cfra, SEQ_STRIPELEM_IBUF_COMP, out);
-
i++;
-
for (; i < count; i++) {
+ begin = seq_estimate_render_cost_begin();
Sequence *seq = seq_arr[i];
if (seq_get_early_out_for_blend_mode(seq) == EARLY_DO_EFFECT) {
@@ -4145,7 +4047,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
IMB_freeImBuf(ibuf2);
}
- BKE_sequencer_cache_put(context, seq_arr[i], cfra, SEQ_STRIPELEM_IBUF_COMP, out);
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put(context, seq_arr[i], cfra, SEQ_CACHE_STORE_COMPOSITE, out, cost);
}
return out;
@@ -4158,7 +4061,8 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int chanshown)
{
- Editing *ed = BKE_sequencer_editing_get(context->scene, false);
+ Scene *scene = context->scene;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
ListBase *seqbasep;
if (ed == NULL) {
@@ -4176,8 +4080,29 @@ ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int cha
SeqRenderState state;
sequencer_state_init(&state);
+ ImBuf *out = NULL;
+ Sequence *seq_arr[MAXSEQ + 1];
+ int count;
- return seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
+ count = get_shown_sequences(seqbasep, cfra, chanshown, seq_arr);
+
+ if (count) {
+ out = BKE_sequencer_cache_get(context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT);
+ }
+
+ BKE_sequencer_cache_free_temp_cache(context->scene, 0, cfra);
+
+ clock_t begin = seq_estimate_render_cost_begin();
+ float cost = 0;
+
+ if (count && !out) {
+ out = seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
+ cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put_if_possible(
+ context, seq_arr[count - 1], cfra, SEQ_CACHE_STORE_FINAL_OUT, out, cost);
+ }
+
+ return out;
}
ImBuf *BKE_sequencer_give_ibuf_seqbase(const SeqRenderData *context,
@@ -4196,7 +4121,9 @@ ImBuf *BKE_sequencer_give_ibuf_direct(const SeqRenderData *context, float cfra,
SeqRenderState state;
sequencer_state_init(&state);
- return seq_render_strip(context, &state, seq, cfra);
+ ImBuf *ibuf = seq_render_strip(context, &state, seq, cfra);
+
+ return ibuf;
}
/* *********************** threading api ******************* */
@@ -4368,7 +4295,7 @@ bool BKE_sequence_check_depend(Sequence *seq, Sequence *cur)
return true;
}
-static void sequence_do_invalidate_dependent(Sequence *seq, ListBase *seqbase)
+static void sequence_do_invalidate_dependent(Scene *scene, Sequence *seq, ListBase *seqbase)
{
Sequence *cur;
@@ -4378,12 +4305,11 @@ static void sequence_do_invalidate_dependent(Sequence *seq, ListBase *seqbase)
}
if (BKE_sequence_check_depend(seq, cur)) {
- BKE_sequencer_cache_cleanup_sequence(cur);
- BKE_sequencer_preprocessed_cache_cleanup_sequence(cur);
+ BKE_sequencer_cache_cleanup_sequence(scene, cur);
}
if (cur->seqbase.first) {
- sequence_do_invalidate_dependent(seq, &cur->seqbase);
+ sequence_do_invalidate_dependent(scene, seq, &cur->seqbase);
}
}
}
@@ -4391,7 +4317,7 @@ static void sequence_do_invalidate_dependent(Sequence *seq, ListBase *seqbase)
static void sequence_invalidate_cache(Scene *scene,
Sequence *seq,
bool invalidate_self,
- bool invalidate_preprocess)
+ bool UNUSED(invalidate_preprocess))
{
Editing *ed = scene->ed;
@@ -4402,7 +4328,7 @@ static void sequence_invalidate_cache(Scene *scene,
* re-open the animation.
*/
BKE_sequence_free_anim(seq);
- BKE_sequencer_cache_cleanup_sequence(seq);
+ BKE_sequencer_cache_cleanup_sequence(scene, seq);
}
/* if invalidation is invoked from sequence free routine, effectdata would be NULL here */
@@ -4410,16 +4336,12 @@ static void sequence_invalidate_cache(Scene *scene,
BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
}
- if (invalidate_preprocess) {
- BKE_sequencer_preprocessed_cache_cleanup_sequence(seq);
- }
-
/* invalidate cache for all dependent sequences */
/* NOTE: can not use SEQ_BEGIN/SEQ_END here because that macro will change sequence's depth,
* which makes transformation routines work incorrect
*/
- sequence_do_invalidate_dependent(seq, &ed->seqbase);
+ sequence_do_invalidate_dependent(scene, seq, &ed->seqbase);
}
void BKE_sequence_invalidate_cache(Scene *scene, Sequence *seq)
@@ -4441,7 +4363,7 @@ void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
{
Sequence *seq;
- BKE_sequencer_cache_cleanup();
+ BKE_sequencer_cache_cleanup(scene);
for (seq = seqbase->first; seq; seq = seq->next) {
if (for_render && CFRA >= seq->startdisp && CFRA <= seq->enddisp) {
@@ -5449,6 +5371,7 @@ Sequence *BKE_sequence_alloc(ListBase *lb, int cfra, int machine)
seq->scene_sound = NULL;
seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
+ seq->cache_flag = SEQ_CACHE_ALL_TYPES;
return seq;
}
@@ -6080,7 +6003,6 @@ static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int cfra)
void BKE_sequencer_all_free_anim_ibufs(Main *bmain, int cfra)
{
- BKE_sequencer_cache_cleanup();
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
Editing *ed = BKE_sequencer_editing_get(scene, false);
if (ed == NULL) {
@@ -6088,5 +6010,6 @@ void BKE_sequencer_all_free_anim_ibufs(Main *bmain, int cfra)
continue;
}
sequencer_all_free_anim_ibufs(&ed->seqbase, cfra);
+ BKE_sequencer_cache_cleanup(scene);
}
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 6646a46be56..bb766d7c6db 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -6735,6 +6735,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
ed = sce->ed = newdataadr(fd, sce->ed);
ed->act_seq = newdataadr(fd, ed->act_seq);
+ ed->cache = NULL;
/* recursive link sequences, lb will be correctly initialized */
link_recurs_seq(fd, &ed->seqbase);
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 73109cd9a6b..1359684e221 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -1077,6 +1077,14 @@ static void do_versions_seq_unique_name_all_strips(Scene *sce, ListBase *seqbase
}
}
+static void do_versions_seq_set_cache_defaults(Editing *ed)
+{
+ ed->cache_flag = SEQ_CACHE_STORE_FINAL_OUT;
+ ed->cache_flag |= SEQ_CACHE_VIEW_FINAL_OUT;
+ ed->cache_flag |= SEQ_CACHE_VIEW_ENABLE;
+ ed->recycle_max_cost = 10.0f;
+}
+
void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
bool use_collection_compat_28 = true;
@@ -3242,7 +3250,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 60)) {
if (!DNA_struct_elem_find(fd->filesdna, "bSplineIKConstraint", "short", "yScaleMode")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
if (ob->pose) {
@@ -3300,6 +3308,14 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
BKE_animdata_main_cb(bmain, do_version_bbone_scale_animdata_cb, NULL);
}
+ for (Scene *sce = bmain->scenes.first; sce != NULL; sce = sce->id.next) {
+ if (sce->ed != NULL) {
+ do_versions_seq_set_cache_defaults(sce->ed);
+ }
+ }
+ }
+
+ {
/* Versioning code until next subversion bump goes here. */
}
}
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 8403f178284..bc3a18313d6 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -358,7 +358,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
* otherwise, invalidated cache entries can make their way into
* the output rendering. We can't put that into RE_BlenderFrame,
* since sequence rendering can call that recursively... (peter) */
- BKE_sequencer_cache_cleanup();
+ BKE_sequencer_cache_cleanup(scene);
RE_SetReports(re, op->reports);
@@ -978,7 +978,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
* otherwise, invalidated cache entries can make their way into
* the output rendering. We can't put that into RE_BlenderFrame,
* since sequence rendering can call that recursively... (peter) */
- BKE_sequencer_cache_cleanup();
+ BKE_sequencer_cache_cleanup(scene);
// store spare
// get view3d layer, local layer, make this nice api call to render
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 550aa9d7f8d..2fce8c42a24 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -1812,6 +1812,182 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
GPU_blend(false);
}
+typedef struct CacheDrawData {
+ const bContext *C;
+ uint pos;
+ float stripe_offs;
+ float stripe_ht;
+} CacheDrawData;
+
+/* Called as a callback */
+static bool draw_cache_view_cb(
+ void *userdata, struct Sequence *seq, int cfra, int cache_type, float UNUSED(cost))
+{
+ CacheDrawData *drawdata = userdata;
+ const bContext *C = drawdata->C;
+ Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
+ struct View2D *v2d = &ar->v2d;
+ Editing *ed = scene->ed;
+ uint pos = drawdata->pos;
+
+ if ((ed->cache_flag & SEQ_CACHE_VIEW_FINAL_OUT) == 0) {
+ return true;
+ }
+
+ float stripe_bot, stripe_top, stripe_offs, stripe_ht;
+ float color[4];
+ color[3] = 0.4f;
+
+ switch (cache_type) {
+ case SEQ_CACHE_STORE_FINAL_OUT:
+ if (scene->ed->cache_flag & SEQ_CACHE_VIEW_FINAL_OUT) {
+ color[0] = 1.0f;
+ color[1] = 0.4f;
+ color[2] = 0.2f;
+ stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) -
+ v2d->cur.ymin;
+ ;
+ stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HEIGHT_TEXT);
+ stripe_top = stripe_bot + stripe_ht;
+ break;
+ }
+ else {
+ return false;
+ }
+
+ case SEQ_CACHE_STORE_RAW:
+ if (scene->ed->cache_flag & SEQ_CACHE_VIEW_RAW) {
+ color[0] = 1.0f;
+ color[1] = 0.1f;
+ color[2] = 0.02f;
+ stripe_offs = drawdata->stripe_offs;
+ stripe_ht = drawdata->stripe_ht;
+ stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs;
+ stripe_top = stripe_bot + stripe_ht;
+ break;
+ }
+ else {
+ return false;
+ }
+
+ case SEQ_CACHE_STORE_PREPROCESSED:
+ if (scene->ed->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED) {
+ color[0] = 0.1f;
+ color[1] = 0.1f;
+ color[2] = 0.75f;
+ stripe_offs = drawdata->stripe_offs;
+ stripe_ht = drawdata->stripe_ht;
+ stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + (stripe_offs + stripe_ht) + stripe_offs;
+ stripe_top = stripe_bot + stripe_ht;
+ break;
+ }
+ else {
+ return false;
+ }
+
+ case SEQ_CACHE_STORE_COMPOSITE:
+ if (scene->ed->cache_flag & SEQ_CACHE_VIEW_COMPOSITE) {
+ color[0] = 1.0f;
+ color[1] = 0.6f;
+ color[2] = 0.0f;
+ stripe_offs = drawdata->stripe_offs;
+ stripe_ht = drawdata->stripe_ht;
+ stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_offs;
+ stripe_bot = stripe_top - stripe_ht;
+ break;
+ }
+ else {
+ return false;
+ }
+ }
+
+ immUniformColor4f(color[0], color[1], color[2], color[3]);
+ immRectf(pos, cfra, stripe_bot, cfra + 1, stripe_top);
+
+ return false;
+}
+
+static void draw_cache_view(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
+ struct View2D *v2d = &ar->v2d;
+
+ if ((scene->ed->cache_flag & SEQ_CACHE_VIEW_ENABLE) == 0) {
+ return;
+ }
+
+ GPU_blend(true);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ float stripe_bot, stripe_top, stripe_offs;
+ float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) -
+ v2d->cur.ymin;
+
+ if (scene->ed->cache_flag & SEQ_CACHE_VIEW_FINAL_OUT) {
+ stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HEIGHT_TEXT);
+ stripe_top = stripe_bot + stripe_ht;
+ float bg_color[4] = {1.0f, 0.4f, 0.2f, 0.1f};
+
+ immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
+ immRectf(pos, scene->r.sfra, stripe_bot, scene->r.efra, stripe_top);
+ }
+
+ for (Sequence *seq = scene->ed->seqbasep->first; seq != NULL; seq = seq->next) {
+ if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ continue;
+ }
+
+ if (seq->startdisp > v2d->cur.xmax || seq->enddisp < v2d->cur.xmin) {
+ continue;
+ }
+
+ CLAMP_MAX(stripe_ht, 0.2f);
+ stripe_offs = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin;
+ CLAMP_MIN(stripe_offs, stripe_ht / 2);
+
+ stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs;
+ stripe_top = stripe_bot + stripe_ht;
+
+ if (scene->ed->cache_flag & SEQ_CACHE_VIEW_RAW) {
+ float bg_color[4] = {1.0f, 0.1f, 0.02f, 0.1f};
+ immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
+ immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
+ }
+
+ stripe_bot += stripe_ht + stripe_offs;
+ stripe_top = stripe_bot + stripe_ht;
+
+ if (scene->ed->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED) {
+ float bg_color[4] = {0.1f, 0.1f, 0.75f, 0.1f};
+ immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
+ immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
+ }
+
+ stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_offs;
+ stripe_bot = stripe_top - stripe_ht;
+
+ if (scene->ed->cache_flag & SEQ_CACHE_VIEW_COMPOSITE) {
+ float bg_color[4] = {1.0f, 0.6f, 0.0f, 0.1f};
+ immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
+ immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
+ }
+ }
+
+ CacheDrawData userdata;
+ userdata.C = C;
+ userdata.pos = pos;
+ userdata.stripe_offs = stripe_offs;
+ userdata.stripe_ht = stripe_ht;
+
+ BKE_sequencer_cache_iterate(scene, &userdata, draw_cache_view_cb);
+
+ immUnbindProgram();
+ GPU_blend(false);
+}
+
/* Draw Timeline/Strip Editor Mode for Sequencer */
void draw_timeline_seq(const bContext *C, ARegion *ar)
{
@@ -1860,6 +2036,7 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
if (ed) {
/* draw the data */
draw_seq_strips(C, ed, ar);
+ draw_cache_view(C);
/* text draw cached (for sequence names), in pixelspace now */
UI_view2d_text_cache_draw(ar);
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index b2c231d649e..2b0c29a02ad 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -695,8 +695,6 @@ static void sequencer_preview_region_listener(wmWindow *UNUSED(win),
case NC_ANIMATION:
switch (wmn->data) {
case ND_KEYFRAME:
- /* Otherwise, often prevents seeing immediately effects of keyframe editing... */
- BKE_sequencer_cache_cleanup();
ED_region_tag_redraw(ar);
break;
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 5f4311f68eb..7f049f480d7 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1111,19 +1111,16 @@ static void recalcData_sequencer(TransInfo *t)
if (seq != seq_prev) {
if (BKE_sequence_tx_fullupdate_test(seq)) {
- /* A few effect strip types need a complete recache on transform. */
BKE_sequence_invalidate_cache(t->scene, seq);
}
else {
- BKE_sequence_invalidate_dependent(t->scene, seq);
+ BKE_sequence_invalidate_cache(t->scene, seq);
}
}
seq_prev = seq;
}
- BKE_sequencer_preprocessed_cache_cleanup();
-
flushTransSeq(t);
}
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index bdc1abf3132..f8df14cf317 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -173,6 +173,13 @@ bool addzbufImBuf(struct ImBuf *ibuf);
bool addzbuffloatImBuf(struct ImBuf *ibuf);
/**
+ * Approximate size of ImBuf in memory
+ *
+ * \attention Defined in allocimbuf.c
+ */
+size_t IMB_get_size_in_memory(struct ImBuf *ibuf);
+
+/**
*
* \attention Defined in rectop.c
*/
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 76304b33a6f..fe24ccc99a9 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -618,6 +618,35 @@ ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
return (ibuf2);
}
+size_t IMB_get_size_in_memory(ImBuf *ibuf)
+{
+ int a;
+ size_t size = 0, channel_size = 0;
+
+ size += sizeof(ImBuf);
+
+ if (ibuf->rect)
+ channel_size += sizeof(char);
+
+ if (ibuf->rect_float)
+ channel_size += sizeof(float);
+
+ size += channel_size * ibuf->x * ibuf->y * ibuf->channels;
+
+ if (ibuf->miptot) {
+ for (a = 0; a < ibuf->miptot; a++) {
+ if (ibuf->mipmap[a])
+ size += IMB_get_size_in_memory(ibuf->mipmap[a]);
+ }
+ }
+
+ if (ibuf->tiles) {
+ size += sizeof(unsigned int) * ibuf->ytiles * ibuf->xtiles;
+ }
+
+ return size;
+}
+
#if 0 /* remove? - campbell */
/* support for cache limiting */
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index 4424e5548ca..3cb976a6d9f 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -186,58 +186,23 @@ static void IMB_moviecache_destructor(void *p)
}
}
-/* approximate size of ImBuf in memory */
-static size_t IMB_get_size_in_memory(ImBuf *ibuf)
+static size_t get_size_in_memory(ImBuf *ibuf)
{
- int a;
- size_t size = 0, channel_size = 0;
-
- /* Persistent images should have no affect on how "normal"
- * images are cached.
- *
- * This is a bit arbitrary, but would make it so only movies
- * and sequences are memory limited, keeping textures in the
- * memory in order to avoid constant file reload on viewport
- * update.
- */
+ /* Keep textures in the memory to avoid constant file reload on viewport update. */
if (ibuf->userflags & IB_PERSISTENT) {
return 0;
}
-
- size += sizeof(ImBuf);
-
- if (ibuf->rect) {
- channel_size += sizeof(char);
- }
-
- if (ibuf->rect_float) {
- channel_size += sizeof(float);
- }
-
- size += channel_size * ibuf->x * ibuf->y * ibuf->channels;
-
- if (ibuf->miptot) {
- for (a = 0; a < ibuf->miptot; a++) {
- if (ibuf->mipmap[a]) {
- size += IMB_get_size_in_memory(ibuf->mipmap[a]);
- }
- }
- }
-
- if (ibuf->tiles) {
- size += sizeof(unsigned int) * ibuf->ytiles * ibuf->xtiles;
+ else {
+ return IMB_get_size_in_memory(ibuf);
}
-
- return size;
}
-
static size_t get_item_size(void *p)
{
size_t size = sizeof(MovieCacheItem);
MovieCacheItem *item = (MovieCacheItem *)p;
if (item->ibuf) {
- size += IMB_get_size_in_memory(item->ibuf);
+ size += get_size_in_memory(item->ibuf);
}
return size;
@@ -407,7 +372,7 @@ bool IMB_moviecache_put_if_possible(MovieCache *cache, void *userkey, ImBuf *ibu
size_t mem_in_use, mem_limit, elem_size;
bool result = false;
- elem_size = IMB_get_size_in_memory(ibuf);
+ elem_size = get_size_in_memory(ibuf);
mem_limit = MEM_CacheLimiter_get_maximum();
BLI_mutex_lock(&limitor_lock);
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index ba3dee405ad..2a4d1b5d9d3 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -229,6 +229,9 @@ typedef struct Sequence {
/* modifiers */
ListBase modifiers;
+
+ int cache_flag;
+ int _pad2[3];
} Sequence;
typedef struct MetaStack {
@@ -258,6 +261,12 @@ typedef struct Editing {
int over_ofs, over_cfra;
int over_flag, proxy_storage;
rctf over_border;
+
+ struct SeqCache *cache;
+
+ /* Cache control */
+ float recycle_max_cost;
+ int cache_flag;
} Editing;
/* ************* Effect Variable Structs ********* */
@@ -635,4 +644,33 @@ enum {
SEQUENCE_MASK_TIME_ABSOLUTE = 1,
};
+/* Sequence->cache_flag
+ * SEQ_CACHE_STORE_RAW
+ * SEQ_CACHE_STORE_PREPROCESSED
+ * SEQ_CACHE_STORE_COMPOSITE
+ * FINAL_OUT is ignored
+ *
+ * Editing->cache_flag
+ * all entries
+ */
+enum {
+ SEQ_CACHE_STORE_RAW = (1 << 0),
+ SEQ_CACHE_STORE_PREPROCESSED = (1 << 1),
+ SEQ_CACHE_STORE_COMPOSITE = (1 << 2),
+ SEQ_CACHE_STORE_FINAL_OUT = (1 << 3),
+
+ /* For lookup purposes */
+ SEQ_CACHE_ALL_TYPES = SEQ_CACHE_STORE_RAW | SEQ_CACHE_STORE_PREPROCESSED |
+ SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT,
+
+ SEQ_CACHE_OVERRIDE = (1 << 4),
+
+ /* enable cache visualization overlay in timeline UI */
+ SEQ_CACHE_VIEW_ENABLE = (1 << 5),
+ SEQ_CACHE_VIEW_RAW = (1 << 6),
+ SEQ_CACHE_VIEW_PREPROCESSED = (1 << 7),
+ SEQ_CACHE_VIEW_COMPOSITE = (1 << 8),
+ SEQ_CACHE_VIEW_FINAL_OUT = (1 << 9),
+};
+
#endif /* __DNA_SEQUENCE_TYPES_H__ */
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index ddea98a135a..1f356624f3f 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -124,11 +124,10 @@ static void rna_Camera_background_images_clear(Camera *cam)
WM_main_add_notifier(NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
}
-static void rna_Camera_dof_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_Camera_dof_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
{
/* TODO(sergey): Can be more selective here. */
- BKE_sequencer_cache_cleanup();
- BKE_sequencer_preprocessed_cache_cleanup();
+ BKE_sequencer_cache_cleanup_all(bmain);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
}
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 934847fed50..40ee069657c 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -577,10 +577,6 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain,
BKE_movieclip_reload(bmain, clip);
- /* all sequencers for now, we don't know which scenes are using this clip as a strip */
- BKE_sequencer_cache_cleanup();
- BKE_sequencer_preprocessed_cache_cleanup();
-
WM_main_add_notifier(NC_MOVIECLIP | ND_DISPLAY, &clip->id);
WM_main_add_notifier(NC_MOVIECLIP | NA_EDITED, &clip->id);
}
@@ -612,21 +608,19 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain,
}
BKE_sequence_invalidate_cache(scene, seq);
- BKE_sequencer_preprocessed_cache_cleanup_sequence(seq);
}
else {
SEQ_BEGIN (scene->ed, seq) {
BKE_sequence_free_anim(seq);
}
SEQ_END;
-
- BKE_sequencer_cache_cleanup();
- BKE_sequencer_preprocessed_cache_cleanup();
}
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
}
}
+
+ BKE_sequencer_cache_cleanup_all(bmain);
}
static char *rna_ColorManagedSequencerColorspaceSettings_path(PointerRNA *UNUSED(ptr))
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 53cfc0bc3c0..8802eb07149 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -1988,22 +1988,21 @@ static void rna_Scene_update_active_object_data(bContext *C, PointerRNA *UNUSED(
}
}
-static void rna_SceneCamera_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_SceneCamera_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
Object *camera = scene->camera;
+ BKE_sequencer_cache_cleanup_all(bmain);
+
if (camera && (camera->type == OB_CAMERA)) {
DEG_id_tag_update(&camera->id, ID_RECALC_GEOMETRY);
}
}
-static void rna_SceneSequencer_update(Main *UNUSED(bmain),
- Scene *UNUSED(scene),
- PointerRNA *UNUSED(ptr))
+static void rna_SceneSequencer_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
- BKE_sequencer_cache_cleanup();
- BKE_sequencer_preprocessed_cache_cleanup();
+ BKE_sequencer_cache_cleanup(scene);
}
static char *rna_ToolSettings_path(PointerRNA *UNUSED(ptr))
@@ -2157,11 +2156,10 @@ static void rna_GPUDOFSettings_blades_set(PointerRNA *ptr, const int value)
}
}
-static void rna_GPUDOFSettings_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_GPUDOFSettings_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
{
/* TODO(sergey): Can be more selective here. */
- BKE_sequencer_cache_cleanup();
- BKE_sequencer_preprocessed_cache_cleanup();
+ BKE_sequencer_cache_cleanup_all(bmain);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
}
@@ -5608,7 +5606,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_ui_range(prop, 1, 100, 10, 1);
RNA_def_property_ui_text(prop, "Resolution %", "Percentage scale for render resolution");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneSequencer_update");
prop = RNA_def_property(srna, "tile_x", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "tilex");
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 6f524be7473..7daf4474eb6 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -1726,6 +1726,31 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting this strip");
rna_def_sequence_modifiers(brna, prop);
+ prop = RNA_def_property(srna, "cache_raw", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_STORE_RAW);
+ RNA_def_property_ui_text(prop,
+ "Cache Raw",
+ "Cache raw images read from disk, for faster tweaking of strip "
+ "parameters at the cost of memory usage");
+
+ prop = RNA_def_property(srna, "cache_preprocessed", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_STORE_PREPROCESSED);
+ RNA_def_property_ui_text(
+ prop,
+ "Cache Rreprocessed",
+ "Cache preprocessed images, for faster tweaking of effects at the cost of memory usage");
+
+ prop = RNA_def_property(srna, "cache_composite", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_STORE_COMPOSITE);
+ RNA_def_property_ui_text(prop,
+ "Cache Composite",
+ "Cache intermediate composited images, for faster tweaking of stacked "
+ "strips at the cost of memory usage");
+
+ prop = RNA_def_property(srna, "override_cache_settings", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_OVERRIDE);
+ RNA_def_property_ui_text(prop, "Override Cache Settings", "Override global cache settings");
+
RNA_api_sequence_strip(srna);
}
@@ -1809,6 +1834,65 @@ static void rna_def_editor(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "proxy_dir");
RNA_def_property_ui_text(prop, "Proxy Directory", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, "rna_SequenceEditor_update_cache");
+
+ /* cache flags */
+
+ prop = RNA_def_property(srna, "show_cache", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_VIEW_ENABLE);
+ RNA_def_property_ui_text(prop, "Show Cache", "Visualize cached images on the timeline");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_cache_final_out", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_VIEW_FINAL_OUT);
+ RNA_def_property_ui_text(prop, "Final Images", "Visualize cached complete frames");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_cache_raw", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_VIEW_RAW);
+ RNA_def_property_ui_text(prop, "Raw Images", "Visualize cached raw images");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_cache_preprocessed", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_VIEW_PREPROCESSED);
+ RNA_def_property_ui_text(prop, "Preprocessed Images", "Visualize cached preprocessed images");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_cache_composite", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_VIEW_COMPOSITE);
+ RNA_def_property_ui_text(prop, "Composite Images", "Visualize cached composite images");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "cache_raw", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_STORE_RAW);
+ RNA_def_property_ui_text(prop,
+ "Cache Raw",
+ "Cache raw images read from disk, for faster tweaking of strip "
+ "parameters at the cost of memory usage");
+
+ prop = RNA_def_property(srna, "cache_preprocessed", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_STORE_PREPROCESSED);
+ RNA_def_property_ui_text(
+ prop,
+ "Cache Preprocessed",
+ "Cache preprocessed images, for faster tweaking of effects at the cost of memory usage");
+
+ prop = RNA_def_property(srna, "cache_composite", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_STORE_COMPOSITE);
+ RNA_def_property_ui_text(prop,
+ "Cache Composite",
+ "Cache intermediate composited images, for faster tweaking of stacked "
+ "strips at the cost of memory usage");
+
+ prop = RNA_def_property(srna, "cache_final", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_STORE_FINAL_OUT);
+ RNA_def_property_ui_text(prop, "Cache Final", "Cache final image for each frame");
+
+ prop = RNA_def_property(srna, "recycle_max_cost", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, SEQ_CACHE_COST_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, SEQ_CACHE_COST_MAX, 0.1f, 1);
+ RNA_def_property_float_sdna(prop, NULL, "recycle_max_cost");
+ RNA_def_property_ui_text(
+ prop, "Recycle Up To Cost", "Only frames with cost lower than this value will be recycled");
}
static void rna_def_filter_video(StructRNA *srna)