*/
#include <list>
+#include <queue>
+#include <vector>
#include "MEM_Allocator.h"
template<class T>
void touch() {
parent->touch(this);
}
+ void set_priority(int priority) {
+ this->priority = priority;
+ }
+ int get_priority(void) {
+ return this->priority;
+ }
private:
friend class MEM_CacheLimiter<T>;
T * data;
int refcount;
+ int priority;
typename std::list<MEM_CacheLimiterHandle<T> *,
MEM_Allocator<MEM_CacheLimiterHandle<T> *> >::iterator me;
MEM_CacheLimiter<T> * parent;
template<class T>
class MEM_CacheLimiter {
public:
- typedef typename std::list<MEM_CacheLimiterHandle<T> *,
- MEM_Allocator<MEM_CacheLimiterHandle<T> *> >::iterator iterator;
typedef size_t (*MEM_CacheLimiter_DataSize_Func) (void *data);
+ typedef int (*MEM_CacheLimiter_ItemPriority_Func) (void *item, int default_priority);
MEM_CacheLimiter(MEM_CacheLimiter_DataSize_Func getDataSize_)
: getDataSize(getDataSize_) {
}
delete handle;
}
void enforce_limits() {
+ MEM_CachePriorityQueue priority_queue;
size_t max = MEM_CacheLimiter_get_maximum();
size_t mem_in_use, cur_size;
mem_in_use = MEM_get_memory_in_use();
}
- for (iterator it = queue.begin();
- it != queue.end() && mem_in_use > max;)
- {
- iterator jt = it;
- ++it;
+ if (mem_in_use <= max) {
+ return;
+ }
+
+ priority_queue = get_priority_queue();
+
+ while (!priority_queue.empty() && mem_in_use > max) {
+ MEM_CacheElementPtr elem = priority_queue.top();
if(getDataSize) {
- cur_size= getDataSize((*jt)->get()->get_data());
+ cur_size = getDataSize(elem->get()->get_data());
} else {
- cur_size= mem_in_use;
+ cur_size = mem_in_use;
}
- (*jt)->destroy_if_possible();
+ elem->destroy_if_possible();
- if(getDataSize) {
- mem_in_use-= cur_size;
+ priority_queue.pop();
+
+ if (getDataSize) {
+ mem_in_use -= cur_size;
} else {
- mem_in_use-= cur_size - MEM_get_memory_in_use();
+ mem_in_use -= cur_size - MEM_get_memory_in_use();
}
}
}
--it;
handle->me = it;
}
+ void set_item_priority_func(MEM_CacheLimiter_ItemPriority_Func item_priority_func) {
+ getItemPriority = item_priority_func;
+ }
private:
+ typedef MEM_CacheLimiterHandle<T> *MEM_CacheElementPtr;
+ typedef std::list<MEM_CacheElementPtr, MEM_Allocator<MEM_CacheElementPtr> > MEM_CacheQueue;
+ typedef typename MEM_CacheQueue::iterator iterator;
+
+ struct compare_element_priority : public std::binary_function<MEM_CacheElementPtr, MEM_CacheElementPtr, bool> {
+ bool operator()(const MEM_CacheElementPtr left_elem, const MEM_CacheElementPtr right_elem) const {
+ return left_elem->get_priority() > right_elem->get_priority();
+ }
+ };
+
+ typedef std::priority_queue<MEM_CacheElementPtr, std::vector<MEM_CacheElementPtr>, compare_element_priority > MEM_CachePriorityQueue;
+
size_t total_size() {
size_t size = 0;
for (iterator it = queue.begin(); it != queue.end(); it++) {
return size;
}
- std::list<MEM_CacheLimiterHandle<T>*,
- MEM_Allocator<MEM_CacheLimiterHandle<T> *> > queue;
+ MEM_CachePriorityQueue get_priority_queue(void) {
+ MEM_CachePriorityQueue priority_queue;
+ iterator it;
+ int i;
+
+ for (it = queue.begin(), i = 0; it != queue.end(); it++, i++) {
+ MEM_CacheElementPtr elem = *it;
+ int priority;
+
+ priority = i;
+
+ if (getItemPriority) {
+ priority = getItemPriority(elem->get()->get_data(), priority);
+ }
+
+ elem->set_priority(priority);
+
+ priority_queue.push(elem);
+ }
+
+ return priority_queue;
+ }
+
+ MEM_CacheQueue queue;
MEM_CacheLimiter_DataSize_Func getDataSize;
+ MEM_CacheLimiter_ItemPriority_Func getItemPriority;
};
#endif // __MEM_CACHELIMITER_H__
/* function used to measure stored data element size */
typedef size_t(*MEM_CacheLimiter_DataSize_Func) (void*);
+/* function used to measure priority of item when freeing memory */
+typedef int(*MEM_CacheLimiter_ItemPriority_Func) (void*, int);
+
#ifndef __MEM_CACHELIMITER_H__
extern void MEM_CacheLimiter_set_maximum(size_t m);
extern int MEM_CacheLimiter_get_maximum(void);
extern void * MEM_CacheLimiter_get(MEM_CacheLimiterHandleC * handle);
+extern void MEM_CacheLimiter_ItemPriority_Func_set(MEM_CacheLimiterC *This,
+ MEM_CacheLimiter_ItemPriority_Func item_priority_func);
+
#ifdef __cplusplus
}
#endif
{
return cast(handle)->get()->get_data();
}
+
+void MEM_CacheLimiter_ItemPriority_Func_set(MEM_CacheLimiterC *This,
+ MEM_CacheLimiter_ItemPriority_Func item_priority_func)
+{
+ cast(This)->get_cache()->set_item_priority_func(item_priority_func);
+}
short render_flag;
} MovieClipImBufCacheKey;
+typedef struct MovieClipCachePriorityData {
+ int framenr;
+} MovieClipCachePriorityData;
+
static void moviecache_keydata(void *userkey, int *framenr, int *proxy, int *render_flags)
{
MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *)userkey;
return 0;
}
+void *moviecache_getprioritydata(void *key_v)
+{
+ MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *) key_v;
+ MovieClipCachePriorityData *priority_data;
+
+ priority_data = MEM_callocN(sizeof(priority_data), "movie cache clip priority data");
+ priority_data->framenr = key->framenr;
+
+ return priority_data;
+}
+
+int moviecache_getitempriority(void *last_userkey_v, void *priority_data_v)
+{
+ MovieClipImBufCacheKey *last_userkey = (MovieClipImBufCacheKey *) last_userkey_v;
+ MovieClipCachePriorityData *priority_data = (MovieClipCachePriorityData *) priority_data_v;
+
+ return -abs(last_userkey->framenr - priority_data->framenr);
+}
+
+void moviecache_prioritydeleter(void *priority_data_v)
+{
+ MovieClipCachePriorityData *priority_data = (MovieClipCachePriorityData *) priority_data_v;
+
+ MEM_freeN(priority_data);
+}
+
static ImBuf *get_imbuf_cache(MovieClip *clip, MovieClipUser *user, int flag)
{
if (clip->cache) {
MovieClipImBufCacheKey key;
if (!clip->cache) {
+ struct MovieCache *moviecache;
+
clip->cache = MEM_callocN(sizeof(MovieClipCache), "movieClipCache");
- clip->cache->moviecache = IMB_moviecache_create(sizeof(MovieClipImBufCacheKey), NULL, moviecache_hashhash,
- moviecache_hashcmp, moviecache_keydata, NULL);
+ moviecache = IMB_moviecache_create(sizeof(MovieClipImBufCacheKey), moviecache_hashhash, moviecache_hashcmp);
+
+ IMB_moviecache_set_getdata_callback(moviecache, moviecache_keydata);
+ IMB_moviecache_set_priority_callback(moviecache, moviecache_getprioritydata, moviecache_getitempriority,
+ moviecache_prioritydeleter);
+
+ clip->cache->moviecache = moviecache;
}
key.framenr = user->framenr;
{
if (moviecache) {
IMB_moviecache_free(moviecache);
- moviecache = IMB_moviecache_create(sizeof(SeqCacheKey), NULL, seqcache_hashhash,
- seqcache_hashcmp, NULL, NULL);
+ moviecache = IMB_moviecache_create(sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
}
}
}
if (!moviecache) {
- moviecache = IMB_moviecache_create(sizeof(SeqCacheKey), NULL, seqcache_hashhash,
- seqcache_hashcmp, NULL, NULL);
+ moviecache = IMB_moviecache_create(sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
}
key.seq = seq;
struct MovieCache;
typedef void (*MovieCacheGetKeyDataFP) (void *userkey, int *framenr, int *proxy, int *render_flags);
-typedef void (*MoviKeyDeleterFP) (void *userkey);
+typedef void (*MovieCacheKeyDeleterFP) (void *userkey);
typedef int (*MovieCacheCheckKeyUnusedFP) (void *userkey);
+typedef void *(*MovieCacheGetPriorityDataFP) (void *userkey);
+typedef int (*MovieCacheGetItemPriorityFP) (void *last_userkey, void *priority_data);
+typedef void (*MovieCachePriorityDeleterFP) (void *priority_data);
+
void IMB_moviecache_init(void);
void IMB_moviecache_destruct(void);
-struct MovieCache *IMB_moviecache_create(int keysize, MoviKeyDeleterFP keydeleterfp,
- GHashHashFP hashfp, GHashCmpFP cmpfp,
- MovieCacheGetKeyDataFP getdatafp,
- MovieCacheCheckKeyUnusedFP checkkeyunusedfp);
+struct MovieCache *IMB_moviecache_create(int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp);
+void IMB_moviecache_set_key_deleter_callback(struct MovieCache *cache, MovieCacheKeyDeleterFP keydeleterfp);
+void IMB_moviecache_set_getdata_callback(struct MovieCache *cache, MovieCacheGetKeyDataFP getdatafp);
+void IMB_moviecache_set_check_unused_callback(struct MovieCache *cache, MovieCacheCheckKeyUnusedFP checkkeyunusedfp);
+void IMB_moviecache_set_priority_callback(struct MovieCache *cache, MovieCacheGetPriorityDataFP getprioritydatafp,
+ MovieCacheGetItemPriorityFP getitempriorityfp,
+ MovieCachePriorityDeleterFP prioritydeleterfp);
+
void IMB_moviecache_put(struct MovieCache *cache, void *userkey, struct ImBuf *ibuf);
struct ImBuf* IMB_moviecache_get(struct MovieCache *cache, void *userkey);
void IMB_moviecache_free(struct MovieCache *cache);
static void colormanage_cache_init(void)
{
- colormanage_cache = IMB_moviecache_create(sizeof(ColormanageCacheKey), colormanage_keydeleter,
- colormanage_hashhash, colormanage_hashcmp,
- NULL, colormanage_checkkeyunused);
+ colormanage_cache = IMB_moviecache_create(sizeof(ColormanageCacheKey), colormanage_hashhash, colormanage_hashcmp);
+
+ IMB_moviecache_set_key_deleter_callback(colormanage_cache, colormanage_keydeleter);
+ IMB_moviecache_set_check_unused_callback(colormanage_cache, colormanage_checkkeyunused);
}
static void colormanage_cache_exit(void)
typedef struct MovieCache {
GHash *hash;
- MoviKeyDeleterFP keydeleterfp;
+ MovieCacheKeyDeleterFP keydeleterfp;
GHashHashFP hashfp;
GHashCmpFP cmpfp;
MovieCacheGetKeyDataFP getdatafp;
MovieCacheCheckKeyUnusedFP checkkeyunusedfp;
+ MovieCacheGetPriorityDataFP getprioritydatafp;
+ MovieCacheGetItemPriorityFP getitempriorityfp;
+ MovieCachePriorityDeleterFP prioritydeleterfp;
+
struct BLI_mempool *keys_pool;
struct BLI_mempool *items_pool;
struct BLI_mempool *userkeys_pool;
int keysize;
- unsigned long curtime;
+
+ void *last_userkey;
int totseg, *points, proxy, render_flags; /* for visual statistics optimization */
int pad;
MovieCache *cache_owner;
ImBuf *ibuf;
MEM_CacheLimiterHandleC *c_handle;
- unsigned long last_access;
+ void *priority_data;
} MovieCacheItem;
static unsigned int moviecache_hashhash(const void *keyv)
static void moviecache_valfree(void *val)
{
MovieCacheItem *item = (MovieCacheItem *)val;
+ MovieCache *cache = item->cache_owner;
if (item->ibuf) {
MEM_CacheLimiter_unmanage(item->c_handle);
IMB_freeImBuf(item->ibuf);
}
+ if (item->priority_data && cache->prioritydeleterfp) {
+ cache->prioritydeleterfp(item->priority_data);
+ }
+
BLI_mempool_free(item->cache_owner->items_pool, item);
}
return size;
}
+static int get_item_priority(void *item_v, int default_priority)
+{
+ MovieCacheItem *item = (MovieCacheItem *) item_v;
+ MovieCache *cache = item->cache_owner;
+
+ if (!cache->getitempriorityfp)
+ return default_priority;
+
+ return cache->getitempriorityfp(cache->last_userkey, item->priority_data);
+}
+
void IMB_moviecache_init(void)
{
limitor = new_MEM_CacheLimiter(IMB_moviecache_destructor, get_item_size);
+
+ MEM_CacheLimiter_ItemPriority_Func_set(limitor, get_item_priority);
}
void IMB_moviecache_destruct(void)
delete_MEM_CacheLimiter(limitor);
}
-MovieCache *IMB_moviecache_create(int keysize, MoviKeyDeleterFP keydeleterfp,
- GHashHashFP hashfp, GHashCmpFP cmpfp,
- MovieCacheGetKeyDataFP getdatafp,
- MovieCacheCheckKeyUnusedFP checkkeyunusedfp)
+MovieCache *IMB_moviecache_create(int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp)
{
MovieCache *cache;
cache = MEM_callocN(sizeof(MovieCache), "MovieCache");
+
cache->keys_pool = BLI_mempool_create(sizeof(MovieCacheKey), 64, 64, 0);
cache->items_pool = BLI_mempool_create(sizeof(MovieCacheItem), 64, 64, 0);
cache->userkeys_pool = BLI_mempool_create(keysize, 64, 64, 0);
cache->hash = BLI_ghash_new(moviecache_hashhash, moviecache_hashcmp, "MovieClip ImBuf cache hash");
- cache->keydeleterfp = keydeleterfp;
cache->keysize = keysize;
cache->hashfp = hashfp;
cache->cmpfp = cmpfp;
- cache->getdatafp = getdatafp;
- cache->checkkeyunusedfp = checkkeyunusedfp;
cache->proxy = -1;
return cache;
}
+void IMB_moviecache_set_key_deleter_callback(MovieCache *cache, MovieCacheKeyDeleterFP keydeleterfp)
+{
+ cache->keydeleterfp = keydeleterfp;
+}
+
+void IMB_moviecache_set_getdata_callback(MovieCache *cache, MovieCacheGetKeyDataFP getdatafp)
+{
+ cache->getdatafp = getdatafp;
+}
+
+void IMB_moviecache_set_check_unused_callback(MovieCache *cache, MovieCacheCheckKeyUnusedFP checkkeyunusedfp)
+{
+ cache->checkkeyunusedfp = checkkeyunusedfp;
+}
+
+void IMB_moviecache_set_priority_callback(struct MovieCache *cache, MovieCacheGetPriorityDataFP getprioritydatafp,
+ MovieCacheGetItemPriorityFP getitempriorityfp,
+ MovieCachePriorityDeleterFP prioritydeleterfp)
+{
+ cache->getprioritydatafp = getprioritydatafp;
+ cache->getitempriorityfp = getitempriorityfp;
+ cache->prioritydeleterfp = prioritydeleterfp;
+}
+
void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
{
MovieCacheKey *key;
item = BLI_mempool_alloc(cache->items_pool);
item->ibuf = ibuf;
item->cache_owner = cache;
- item->last_access = cache->curtime++;
item->c_handle = NULL;
+ item->priority_data = NULL;
+
+ if (cache->getprioritydatafp) {
+ item->priority_data = cache->getprioritydatafp(userkey);
+ }
BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
BLI_ghash_insert(cache->hash, key, item);
item->c_handle = MEM_CacheLimiter_insert(limitor, item);
+ cache->last_userkey = userkey;
+
MEM_CacheLimiter_ref(item->c_handle);
MEM_CacheLimiter_enforce_limits(limitor);
MEM_CacheLimiter_unref(item->c_handle);
+ cache->last_userkey = NULL;
+
/* cache limiter can't remove unused keys which points to destoryed values */
check_unused_keys(cache);
item = (MovieCacheItem *)BLI_ghash_lookup(cache->hash, &key);
if (item) {
- item->last_access = cache->curtime++;
-
if (item->ibuf) {
MEM_CacheLimiter_touch(item->c_handle);
IMB_refImBuf(item->ibuf);