diff --git a/intern/memutil/MEM_CacheLimiter.h b/intern/memutil/MEM_CacheLimiter.h index 32f97a21815..88e06833b4a 100644 --- a/intern/memutil/MEM_CacheLimiter.h +++ b/intern/memutil/MEM_CacheLimiter.h @@ -137,6 +137,7 @@ class MEM_CacheLimiter { public: typedef size_t (*MEM_CacheLimiter_DataSize_Func) (void *data); typedef int (*MEM_CacheLimiter_ItemPriority_Func) (void *item, int default_priority); + typedef bool (*MEM_CacheLimiter_ItemDestroyable_Func) (void *item); MEM_CacheLimiter(MEM_CacheLimiter_DataSize_Func data_size_func) : data_size_func(data_size_func) { @@ -230,11 +231,28 @@ public: this->item_priority_func = item_priority_func; } + void set_item_destroyable_func(MEM_CacheLimiter_ItemDestroyable_Func item_destroyable_func) { + this->item_destroyable_func = item_destroyable_func; + } + private: typedef MEM_CacheLimiterHandle *MEM_CacheElementPtr; typedef std::list > MEM_CacheQueue; typedef typename MEM_CacheQueue::iterator iterator; + /* Check whether element can be destroyed when enforcing cache limits */ + bool can_destroy_element(MEM_CacheElementPtr &elem) { + if (!elem->can_destroy()) { + /* Element is referenced */ + return false; + } + if (item_destroyable_func) { + if (!item_destroyable_func(elem->get()->get_data())) + return false; + } + return true; + } + MEM_CacheElementPtr get_least_priority_destroyable_element(void) { if (queue.empty()) return NULL; @@ -244,7 +262,7 @@ private: if (!item_priority_func) { for (iterator it = queue.begin(); it != queue.end(); it++) { MEM_CacheElementPtr elem = *it; - if (!elem->can_destroy()) + if (!can_destroy_element(elem)) continue; best_match_elem = elem; break; @@ -258,7 +276,7 @@ private: for (it = queue.begin(), i = 0; it != queue.end(); it++, i++) { MEM_CacheElementPtr elem = *it; - if (!elem->can_destroy()) + if (!can_destroy_element(elem)) continue; /* by default 0 means highest priority element */ @@ -280,6 +298,7 @@ private: MEM_CacheQueue queue; MEM_CacheLimiter_DataSize_Func data_size_func; MEM_CacheLimiter_ItemPriority_Func item_priority_func; + MEM_CacheLimiter_ItemDestroyable_Func item_destroyable_func; }; #endif // __MEM_CACHELIMITER_H__ diff --git a/intern/memutil/MEM_CacheLimiterC-Api.h b/intern/memutil/MEM_CacheLimiterC-Api.h index 7579dbdd4d1..a6a3ec85777 100644 --- a/intern/memutil/MEM_CacheLimiterC-Api.h +++ b/intern/memutil/MEM_CacheLimiterC-Api.h @@ -47,6 +47,9 @@ 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); +/* function to check whether item could be destroyed */ +typedef bool (*MEM_CacheLimiter_ItemDestroyable_Func) (void*); + #ifndef __MEM_CACHELIMITER_H__ void MEM_CacheLimiter_set_maximum(size_t m); size_t MEM_CacheLimiter_get_maximum(void); @@ -145,6 +148,9 @@ void *MEM_CacheLimiter_get(MEM_CacheLimiterHandleC *handle); void MEM_CacheLimiter_ItemPriority_Func_set(MEM_CacheLimiterC *This, MEM_CacheLimiter_ItemPriority_Func item_priority_func); +void MEM_CacheLimiter_ItemDestroyable_Func_set(MEM_CacheLimiterC *This, + MEM_CacheLimiter_ItemDestroyable_Func item_destroyable_func); + size_t MEM_CacheLimiter_get_memory_in_use(MEM_CacheLimiterC *This); #ifdef __cplusplus diff --git a/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp b/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp index 0e11fbed4e7..6156b511f01 100644 --- a/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp +++ b/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp @@ -203,6 +203,12 @@ void MEM_CacheLimiter_ItemPriority_Func_set(MEM_CacheLimiterC *This, cast(This)->get_cache()->set_item_priority_func(item_priority_func); } +void MEM_CacheLimiter_ItemDestroyable_Func_set(MEM_CacheLimiterC *This, + MEM_CacheLimiter_ItemDestroyable_Func item_destroyable_func) +{ + cast(This)->get_cache()->set_item_destroyable_func(item_destroyable_func); +} + size_t MEM_CacheLimiter_get_memory_in_use(MEM_CacheLimiterC *This) { return cast(This)->get_cache()->get_memory_in_use(); diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c index c042831a93f..3718cb270c9 100644 --- a/source/blender/imbuf/intern/moviecache.c +++ b/source/blender/imbuf/intern/moviecache.c @@ -254,11 +254,26 @@ static int get_item_priority(void *item_v, int default_priority) return priority; } +static bool get_item_destroyable(void *item_v) +{ + MovieCacheItem *item = (MovieCacheItem *) item_v; + /* IB_BITMAPDIRTY means image was modified from inside blender and + * changes are not saved to disk. + * + * Such buffers are never to be freed. + */ + if (item->ibuf->userflags & IB_BITMAPDIRTY) { + return false; + } + return true; +} + void IMB_moviecache_init(void) { limitor = new_MEM_CacheLimiter(IMB_moviecache_destructor, get_item_size); MEM_CacheLimiter_ItemPriority_Func_set(limitor, get_item_priority); + MEM_CacheLimiter_ItemDestroyable_Func_set(limitor, get_item_destroyable); } void IMB_moviecache_destruct(void)