Sequencer: refactor clipboard copy to no longer increase user count.
[blender.git] / source / blender / blenkernel / intern / seqcache.c
index 037acaf5660d71636c27f30093c75b0eb187cd98..435d9369faab2a021c0206b1ea2e4db4d118ec2c 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -19,6 +17,8 @@
  *
  * Peter Schlaile <peter [at] schlaile [dot] de> 2010
  *
+ * Contributor(s): Sergey Sharybin
+ *
  * ***** END GPL LICENSE BLOCK *****
  */
 
  *  \ingroup bke
  */
 
-
 #include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
+
+#include "BLI_sys_types.h"  /* for intptr_t */
 
 #include "MEM_guardedalloc.h"
-#include "MEM_CacheLimiterC-Api.h"
 
 #include "DNA_sequence_types.h"
-#include "BKE_sequencer.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_mempool.h"
-#include <pthread.h>
+#include "DNA_scene_types.h"
 
+#include "IMB_moviecache.h"
 #include "IMB_imbuf.h"
 #include "IMB_imbuf_types.h"
 
-typedef struct seqCacheKey 
-{
-       struct Sequence * seq;
+#include "BLI_listbase.h"
+
+#include "BKE_sequencer.h"
+#include "BKE_scene.h"
+
+typedef struct SeqCacheKey {
+       struct Sequence *seq;
        SeqRenderData context;
        float cfra;
-       seq_stripelem_ibuf_t type;
-} seqCacheKey;
+       eSeqStripElemIBuf 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 bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
+{
+       return ((a->preview_render_size != b->preview_render_size) ||
+               (a->rectx != b->rectx) ||
+               (a->recty != b->recty) ||
+               (a->bmain != b->bmain) ||
+               (a->scene != b->scene) ||
+               (a->motion_blur_shutter != b->motion_blur_shutter) ||
+               (a->motion_blur_samples != b->motion_blur_samples) ||
+               (a->scene->r.views_format != b->scene->r.views_format) ||
+               (a->view_id != b->view_id));
+}
 
-typedef struct seqCacheEntry
+static unsigned int seq_hash_render_data(const SeqRenderData *a)
 {
-       ImBuf * ibuf;
-       MEM_CacheLimiterHandleC * c_handle;
-} seqCacheEntry;
-
-static GHash * hash = NULL;
-static MEM_CacheLimiterC * limitor = NULL;
-static struct BLI_mempool * entrypool = NULL;
-static struct BLI_mempool * keypool = NULL;
-static int ibufs_in  = 0;
-static int ibufs_rem = 0;
-
-static unsigned int HashHash(const void *key_)
+       unsigned int rval = a->rectx + a->recty;
+
+       rval ^= a->preview_render_size;
+       rval ^= ((intptr_t) a->bmain) << 6;
+       rval ^= ((intptr_t) a->scene) << 6;
+       rval ^= (int)(a->motion_blur_shutter * 100.0f) << 10;
+       rval ^= a->motion_blur_samples << 16;
+       rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 24;
+
+       return rval;
+}
+
+static unsigned int seqcache_hashhash(const void *key_)
 {
-       const seqCacheKey *key = (seqCacheKey*) key_;
+       const SeqCacheKey *key = key_;
        unsigned int rval = seq_hash_render_data(&key->context);
 
-       rval ^= *(unsigned int*) &key->cfra;
+       rval ^= *(const unsigned int *) &key->cfra;
        rval += key->type;
        rval ^= ((intptr_t) key->seq) << 6;
 
        return rval;
 }
 
-static int HashCmp(const void *a_, const void *b_)
+static bool seqcache_hashcmp(const void *a_, const void *b_)
 {
-       const seqCacheKey * a = (seqCacheKey*) a_;
-       const seqCacheKey * b = (seqCacheKey*) b_;
-
-       if (a->seq < b->seq) {
-               return -1;              
-       }
-       if (a->seq > b->seq) {
-               return 1;
-       }
+       const SeqCacheKey *a = a_;
+       const SeqCacheKey *b = b_;
 
-       if (a->cfra < b->cfra) {
-               return -1;
-       }
-       if (a->cfra > b->cfra) {
-               return 1;
-       }
-
-       if (a->type < b->type) {
-               return -1;
-       }
-       if (a->type > b->type) {
-               return 1;
-       }
-
-       return seq_cmp_render_data(&a->context, &b->context);
+       return ((a->seq != b->seq) ||
+               (a->cfra != b->cfra) ||
+               (a->type != b->type) ||
+               seq_cmp_render_data(&a->context, &b->context));
 }
 
-static void HashKeyFree(void *key)
+void BKE_sequencer_cache_destruct(void)
 {
-       BLI_mempool_free(keypool, key);
+       if (moviecache)
+               IMB_moviecache_free(moviecache);
+
+       preprocessed_cache_destruct();
 }
 
-static void HashValFree(void *val)
+void BKE_sequencer_cache_cleanup(void)
 {
-       seqCacheEntry* e = (seqCacheEntry*) val;
-
-       if (e->ibuf) {
-               /* fprintf(stderr, "Removing: %p, cnt: %d\n", e->ibuf, 
-                  e->ibuf->refcounter); */
-               IMB_freeImBuf(e->ibuf);
-               MEM_CacheLimiter_unmanage(e->c_handle);
-               ibufs_rem++;
+       if (moviecache) {
+               IMB_moviecache_free(moviecache);
+               moviecache = IMB_moviecache_create("seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
        }
 
-       e->ibuf = NULL;
-       e->c_handle = NULL;
+       BKE_sequencer_preprocessed_cache_cleanup();
+}
 
-       BLI_mempool_free(entrypool, e);
+static bool seqcache_key_check_seq(ImBuf *UNUSED(ibuf), void *userkey, void *userdata)
+{
+       SeqCacheKey *key = (SeqCacheKey *) userkey;
+       Sequence *seq = (Sequence *) userdata;
+
+       return key->seq == seq;
 }
 
-static void IMB_seq_cache_destructor(void * p)
+void BKE_sequencer_cache_cleanup_sequence(Sequence *seq)
 {
-       seqCacheEntry* e = (seqCacheEntry*) p;
-       
-       if (e && e->ibuf) {
-               /* fprintf(stderr, "Removing: %p, cnt: %d\n", e->ibuf,
-                  e->ibuf->refcounter); */
-               IMB_freeImBuf(e->ibuf);
-               ibufs_rem++;
-
-               e->ibuf = NULL;
-               e->c_handle = NULL;
-       }
+       if (moviecache)
+               IMB_moviecache_cleanup(moviecache, seqcache_key_check_seq, seq);
 }
 
-void seq_stripelem_cache_init(void)
+struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type)
 {
-       hash = BLI_ghash_new(HashHash, HashCmp, "seq stripelem cache hash");
-       limitor = new_MEM_CacheLimiter( IMB_seq_cache_destructor );
+       if (moviecache && seq) {
+               SeqCacheKey key;
+
+               key.seq = seq;
+               key.context = *context;
+               key.cfra = cfra - seq->start;
+               key.type = type;
+
+               return IMB_moviecache_get(moviecache, &key);
+       }
 
-       entrypool = BLI_mempool_create(sizeof(seqCacheEntry), 64, 64, 0, 0);
-       keypool = BLI_mempool_create(sizeof(seqCacheKey), 64, 64, 0, 0);
+       return NULL;
 }
 
-void seq_stripelem_cache_destruct(void)
+void BKE_sequencer_cache_put(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *i)
 {
-       if (!entrypool) {
+       SeqCacheKey key;
+
+       if (i == NULL || context->skip_cache) {
                return;
        }
-       BLI_ghash_free(hash, HashKeyFree, HashValFree);
-       delete_MEM_CacheLimiter(limitor);
-       BLI_mempool_destroy(entrypool);
-       BLI_mempool_destroy(keypool);
+
+       if (!moviecache) {
+               moviecache = IMB_moviecache_create("seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
+       }
+
+       key.seq = seq;
+       key.context = *context;
+       key.cfra = cfra - seq->start;
+       key.type = type;
+
+       IMB_moviecache_put(moviecache, &key, i);
 }
 
-void seq_stripelem_cache_cleanup(void)
+void BKE_sequencer_preprocessed_cache_cleanup(void)
 {
-       if (!entrypool) {
-               seq_stripelem_cache_init();
+       SeqPreprocessCacheElem *elem;
+
+       if (!preprocess_cache)
+               return;
+
+       for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
+               IMB_freeImBuf(elem->ibuf);
        }
+       BLI_freelistN(&preprocess_cache->elems);
 
-       /* fprintf(stderr, "Stats before cleanup: in: %d rem: %d\n",
-          ibufs_in, ibufs_rem); */
+       BLI_listbase_clear(&preprocess_cache->elems);
+}
 
-       BLI_ghash_free(hash, HashKeyFree, HashValFree);
-       hash = BLI_ghash_new(HashHash, HashCmp, "seq stripelem cache hash");
+static void preprocessed_cache_destruct(void)
+{
+       if (!preprocess_cache)
+               return;
 
-       /* fprintf(stderr, "Stats after cleanup: in: %d rem: %d\n",
-          ibufs_in, ibufs_rem); */
+       BKE_sequencer_preprocessed_cache_cleanup();
 
+       MEM_freeN(preprocess_cache);
+       preprocess_cache = NULL;
 }
 
-struct ImBuf * seq_stripelem_cache_get(
-       SeqRenderData context, struct Sequence * seq, 
-       float cfra, seq_stripelem_ibuf_t type)
+ImBuf *BKE_sequencer_preprocessed_cache_get(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type)
 {
-       seqCacheKey key;
-       seqCacheEntry * e;
+       SeqPreprocessCacheElem *elem;
 
-       if (!seq) {
+       if (!preprocess_cache)
                return NULL;
-       }
 
-       if (!entrypool) {
-               seq_stripelem_cache_init();
-       }
+       if (preprocess_cache->cfra != cfra)
+               return NULL;
 
-       key.seq = seq;
-       key.context = context;
-       key.cfra = cfra - seq->start;
-       key.type = type;
-       
-       e = (seqCacheEntry*) BLI_ghash_lookup(hash, &key);
+       for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
+               if (elem->seq != seq)
+                       continue;
+
+               if (elem->type != type)
+                       continue;
 
-       if (e && e->ibuf) {
-               IMB_refImBuf(e->ibuf);
+               if (seq_cmp_render_data(&elem->context, context) != 0)
+                       continue;
 
-               MEM_CacheLimiter_touch(e->c_handle);
-               return e->ibuf;
+               IMB_refImBuf(elem->ibuf);
+               return elem->ibuf;
        }
+
        return NULL;
 }
 
-void seq_stripelem_cache_put(
-       SeqRenderData context, struct Sequence * seq, 
-       float cfra, seq_stripelem_ibuf_t type, struct ImBuf * i)
+void BKE_sequencer_preprocessed_cache_put(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *ibuf)
 {
-       seqCacheKey * key;
-       seqCacheEntry * e;
+       SeqPreprocessCacheElem *elem;
 
-       if (!i) {
-               return;
+       if (!preprocess_cache) {
+               preprocess_cache = MEM_callocN(sizeof(SeqPreprocessCache), "sequencer preprocessed cache");
+       }
+       else {
+               if (preprocess_cache->cfra != cfra)
+                       BKE_sequencer_preprocessed_cache_cleanup();
        }
 
-       ibufs_in++;
+       elem = MEM_callocN(sizeof(SeqPreprocessCacheElem), "sequencer preprocessed cache element");
 
-       if (!entrypool) {
-               seq_stripelem_cache_init();
-       }
+       elem->seq = seq;
+       elem->type = type;
+       elem->context = *context;
+       elem->ibuf = ibuf;
 
-       key = (seqCacheKey*) BLI_mempool_alloc(keypool);
+       preprocess_cache->cfra = cfra;
 
-       key->seq = seq;
-       key->context = context;
-       key->cfra = cfra - seq->start;
-       key->type = type;
+       IMB_refImBuf(ibuf);
 
-       IMB_refImBuf(i);
+       BLI_addtail(&preprocess_cache->elems, elem);
+}
 
-       e = (seqCacheEntry*) BLI_mempool_alloc(entrypool);
+void BKE_sequencer_preprocessed_cache_cleanup_sequence(Sequence *seq)
+{
+       SeqPreprocessCacheElem *elem, *elem_next;
 
-       e->ibuf = i;
-       e->c_handle = NULL;
+       if (!preprocess_cache)
+               return;
 
-       BLI_ghash_remove(hash, key, HashKeyFree, HashValFree);
-       BLI_ghash_insert(hash, key, e);
+       for (elem = preprocess_cache->elems.first; elem; elem = elem_next) {
+               elem_next = elem->next;
 
-       e->c_handle = MEM_CacheLimiter_insert(limitor, e);
+               if (elem->seq == seq) {
+                       IMB_freeImBuf(elem->ibuf);
 
-       MEM_CacheLimiter_ref(e->c_handle);
-       MEM_CacheLimiter_enforce_limits(limitor);
-       MEM_CacheLimiter_unref(e->c_handle);
+                       BLI_freelinkN(&preprocess_cache->elems, elem);
+               }
+       }
 }