2011-10-23 19:52:20 +02:00
|
|
|
/*
|
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2011 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s): Blender Foundation,
|
|
|
|
* Sergey Sharybin,
|
|
|
|
* Peter Schlaile
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
2011-11-05 02:48:10 +01:00
|
|
|
/** \file blender/imbuf/intern/moviecache.c
|
2011-10-23 19:52:20 +02:00
|
|
|
* \ingroup bke
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h> /* for qsort */
|
|
|
|
#include <memory.h>
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "MEM_CacheLimiterC-Api.h"
|
|
|
|
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "BLI_ghash.h"
|
|
|
|
#include "BLI_mempool.h"
|
|
|
|
|
|
|
|
#include "IMB_moviecache.h"
|
|
|
|
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
#include "IMB_imbuf.h"
|
|
|
|
|
2012-05-04 01:47:39 +02:00
|
|
|
static MEM_CacheLimiterC *limitor = NULL;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
typedef struct MovieCache {
|
|
|
|
GHash *hash;
|
|
|
|
GHashHashFP hashfp;
|
|
|
|
GHashCmpFP cmpfp;
|
|
|
|
MovieCacheGetKeyDataFP getdatafp;
|
|
|
|
|
|
|
|
struct BLI_mempool *keys_pool;
|
|
|
|
struct BLI_mempool *items_pool;
|
|
|
|
struct BLI_mempool *userkeys_pool;
|
|
|
|
|
|
|
|
int keysize;
|
|
|
|
unsigned long curtime;
|
|
|
|
|
2012-05-16 11:26:37 +02:00
|
|
|
int totseg, *points, proxy, render_flags; /* for visual statistics optimization */
|
2011-10-23 19:52:20 +02:00
|
|
|
int pad;
|
|
|
|
} MovieCache;
|
|
|
|
|
|
|
|
typedef struct MovieCacheKey {
|
|
|
|
MovieCache *cache_owner;
|
|
|
|
void *userkey;
|
|
|
|
} MovieCacheKey;
|
|
|
|
|
|
|
|
typedef struct MovieCacheItem {
|
|
|
|
MovieCache *cache_owner;
|
|
|
|
ImBuf *ibuf;
|
2012-05-16 11:26:37 +02:00
|
|
|
MEM_CacheLimiterHandleC *c_handle;
|
2011-10-23 19:52:20 +02:00
|
|
|
unsigned long last_access;
|
|
|
|
} MovieCacheItem;
|
|
|
|
|
|
|
|
static unsigned int moviecache_hashhash(const void *keyv)
|
|
|
|
{
|
2012-05-16 11:26:37 +02:00
|
|
|
MovieCacheKey *key = (MovieCacheKey *)keyv;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
return key->cache_owner->hashfp(key->userkey);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int moviecache_hashcmp(const void *av, const void *bv)
|
|
|
|
{
|
2012-05-16 11:26:37 +02:00
|
|
|
const MovieCacheKey *a = (MovieCacheKey *)av;
|
|
|
|
const MovieCacheKey *b = (MovieCacheKey *)bv;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
return a->cache_owner->cmpfp(a->userkey, b->userkey);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void moviecache_keyfree(void *val)
|
|
|
|
{
|
2012-05-16 11:26:37 +02:00
|
|
|
MovieCacheKey *key = (MovieCacheKey *)val;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
BLI_mempool_free(key->cache_owner->keys_pool, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void moviecache_valfree(void *val)
|
|
|
|
{
|
2012-05-16 11:26:37 +02:00
|
|
|
MovieCacheItem *item = (MovieCacheItem *)val;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
if (item->ibuf) {
|
|
|
|
MEM_CacheLimiter_unmanage(item->c_handle);
|
|
|
|
IMB_freeImBuf(item->ibuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_mempool_free(item->cache_owner->items_pool, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void check_unused_keys(MovieCache *cache)
|
|
|
|
{
|
|
|
|
GHashIterator *iter;
|
|
|
|
|
2012-05-04 01:47:39 +02:00
|
|
|
iter = BLI_ghashIterator_new(cache->hash);
|
2012-03-24 08:52:14 +01:00
|
|
|
while (!BLI_ghashIterator_isDone(iter)) {
|
2012-03-26 18:04:10 +02:00
|
|
|
MovieCacheKey *key = BLI_ghashIterator_getKey(iter);
|
|
|
|
MovieCacheItem *item = BLI_ghashIterator_getValue(iter);
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
BLI_ghashIterator_step(iter);
|
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (!item->ibuf)
|
2011-10-23 19:52:20 +02:00
|
|
|
BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_ghashIterator_free(iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int compare_int(const void *av, const void *bv)
|
|
|
|
{
|
2012-03-26 18:04:10 +02:00
|
|
|
const int *a = (int *)av;
|
|
|
|
const int *b = (int *)bv;
|
|
|
|
return *a - *b;
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void IMB_moviecache_destructor(void *p)
|
|
|
|
{
|
2012-03-26 18:04:10 +02:00
|
|
|
MovieCacheItem *item = (MovieCacheItem *) p;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
if (item && item->ibuf) {
|
|
|
|
IMB_freeImBuf(item->ibuf);
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
item->ibuf = NULL;
|
|
|
|
item->c_handle = NULL;
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* approximate size of ImBuf in memory */
|
2012-01-31 12:11:56 +01:00
|
|
|
static size_t IMB_get_size_in_memory(ImBuf *ibuf)
|
2011-10-23 19:52:20 +02:00
|
|
|
{
|
|
|
|
int a;
|
2012-03-26 18:04:10 +02:00
|
|
|
size_t size = 0, channel_size = 0;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
size += sizeof(ImBuf);
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (ibuf->rect)
|
2012-03-26 18:04:10 +02:00
|
|
|
channel_size += sizeof(char);
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (ibuf->rect_float)
|
2012-03-26 18:04:10 +02:00
|
|
|
channel_size += sizeof(float);
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-05-16 11:26:37 +02:00
|
|
|
size += channel_size * ibuf->x * ibuf->y * ibuf->channels;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (ibuf->miptot) {
|
2012-03-26 18:04:10 +02:00
|
|
|
for (a = 0; a < ibuf->miptot; a++) {
|
2012-03-24 07:38:07 +01:00
|
|
|
if (ibuf->mipmap[a])
|
2012-03-26 18:04:10 +02:00
|
|
|
size += IMB_get_size_in_memory(ibuf->mipmap[a]);
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (ibuf->tiles) {
|
2012-05-16 11:26:37 +02:00
|
|
|
size += sizeof(unsigned int) * ibuf->ytiles * ibuf->xtiles;
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2012-05-16 11:26:37 +02:00
|
|
|
static size_t get_item_size(void *p)
|
2011-10-23 19:52:20 +02:00
|
|
|
{
|
2012-03-26 18:04:10 +02:00
|
|
|
size_t size = sizeof(MovieCacheItem);
|
|
|
|
MovieCacheItem *item = (MovieCacheItem *) p;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (item->ibuf)
|
2012-03-26 18:04:10 +02:00
|
|
|
size += IMB_get_size_in_memory(item->ibuf);
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMB_moviecache_init(void)
|
|
|
|
{
|
2012-03-26 18:04:10 +02:00
|
|
|
limitor = new_MEM_CacheLimiter(IMB_moviecache_destructor, get_item_size);
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void IMB_moviecache_destruct(void)
|
|
|
|
{
|
2012-03-24 07:38:07 +01:00
|
|
|
if (limitor)
|
2011-10-23 19:52:20 +02:00
|
|
|
delete_MEM_CacheLimiter(limitor);
|
|
|
|
}
|
|
|
|
|
2012-05-18 01:21:11 +02:00
|
|
|
MovieCache *IMB_moviecache_create(int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp,
|
|
|
|
MovieCacheGetKeyDataFP getdatafp)
|
|
|
|
{
|
2011-10-23 19:52:20 +02:00
|
|
|
MovieCache *cache;
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
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");
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
cache->keysize = keysize;
|
|
|
|
cache->hashfp = hashfp;
|
|
|
|
cache->cmpfp = cmpfp;
|
|
|
|
cache->getdatafp = getdatafp;
|
|
|
|
cache->proxy = -1;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
return cache;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
|
|
|
|
{
|
|
|
|
MovieCacheKey *key;
|
|
|
|
MovieCacheItem *item;
|
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (!limitor)
|
2011-10-23 19:52:20 +02:00
|
|
|
IMB_moviecache_init();
|
|
|
|
|
|
|
|
IMB_refImBuf(ibuf);
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
key = BLI_mempool_alloc(cache->keys_pool);
|
|
|
|
key->cache_owner = cache;
|
|
|
|
key->userkey = BLI_mempool_alloc(cache->userkeys_pool);
|
2011-10-23 19:52:20 +02:00
|
|
|
memcpy(key->userkey, userkey, cache->keysize);
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
item = BLI_mempool_alloc(cache->items_pool);
|
|
|
|
item->ibuf = ibuf;
|
|
|
|
item->cache_owner = cache;
|
|
|
|
item->last_access = cache->curtime++;
|
|
|
|
item->c_handle = NULL;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
|
|
|
|
BLI_ghash_insert(cache->hash, key, item);
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
item->c_handle = MEM_CacheLimiter_insert(limitor, item);
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
MEM_CacheLimiter_ref(item->c_handle);
|
|
|
|
MEM_CacheLimiter_enforce_limits(limitor);
|
|
|
|
MEM_CacheLimiter_unref(item->c_handle);
|
|
|
|
|
|
|
|
/* cache limiter can't remove unused keys which points to destoryed values */
|
|
|
|
check_unused_keys(cache);
|
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (cache->points) {
|
2011-10-23 19:52:20 +02:00
|
|
|
MEM_freeN(cache->points);
|
2012-05-04 01:47:39 +02:00
|
|
|
cache->points = NULL;
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-16 11:26:37 +02:00
|
|
|
ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey)
|
2011-10-23 19:52:20 +02:00
|
|
|
{
|
|
|
|
MovieCacheKey key;
|
|
|
|
MovieCacheItem *item;
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
key.cache_owner = cache;
|
|
|
|
key.userkey = userkey;
|
2012-05-16 11:26:37 +02:00
|
|
|
item = (MovieCacheItem *)BLI_ghash_lookup(cache->hash, &key);
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (item) {
|
2012-03-26 18:04:10 +02:00
|
|
|
item->last_access = cache->curtime++;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (item->ibuf) {
|
2011-10-23 19:52:20 +02:00
|
|
|
MEM_CacheLimiter_touch(item->c_handle);
|
|
|
|
IMB_refImBuf(item->ibuf);
|
|
|
|
|
|
|
|
return item->ibuf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMB_moviecache_free(MovieCache *cache)
|
|
|
|
{
|
|
|
|
BLI_ghash_free(cache->hash, moviecache_keyfree, moviecache_valfree);
|
|
|
|
|
|
|
|
BLI_mempool_destroy(cache->keys_pool);
|
|
|
|
BLI_mempool_destroy(cache->items_pool);
|
|
|
|
BLI_mempool_destroy(cache->userkeys_pool);
|
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (cache->points)
|
2011-10-23 19:52:20 +02:00
|
|
|
MEM_freeN(cache->points);
|
|
|
|
|
|
|
|
MEM_freeN(cache);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get segments of cached frames. useful for debugging cache policies */
|
|
|
|
void IMB_moviecache_get_cache_segments(MovieCache *cache, int proxy, int render_flags, int *totseg_r, int **points_r)
|
|
|
|
{
|
2012-03-26 18:04:10 +02:00
|
|
|
*totseg_r = 0;
|
|
|
|
*points_r = NULL;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (!cache->getdatafp)
|
2011-10-23 19:52:20 +02:00
|
|
|
return;
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
if (cache->proxy != proxy || cache->render_flags != render_flags) {
|
2012-03-24 07:38:07 +01:00
|
|
|
if (cache->points)
|
2011-10-23 19:52:20 +02:00
|
|
|
MEM_freeN(cache->points);
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
cache->points = NULL;
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (cache->points) {
|
2012-03-26 18:04:10 +02:00
|
|
|
*totseg_r = cache->totseg;
|
|
|
|
*points_r = cache->points;
|
2012-03-24 07:38:07 +01:00
|
|
|
}
|
|
|
|
else {
|
2012-03-26 18:04:10 +02:00
|
|
|
int totframe = BLI_ghash_size(cache->hash);
|
2012-05-16 11:26:37 +02:00
|
|
|
int *frames = MEM_callocN(totframe * sizeof(int), "movieclip cache frames");
|
2012-03-26 18:04:10 +02:00
|
|
|
int a, totseg = 0;
|
2011-10-23 19:52:20 +02:00
|
|
|
GHashIterator *iter;
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
iter = BLI_ghashIterator_new(cache->hash);
|
2012-05-04 01:47:39 +02:00
|
|
|
a = 0;
|
2012-03-24 08:52:14 +01:00
|
|
|
while (!BLI_ghashIterator_isDone(iter)) {
|
2012-03-26 18:04:10 +02:00
|
|
|
MovieCacheKey *key = BLI_ghashIterator_getKey(iter);
|
|
|
|
MovieCacheItem *item = BLI_ghashIterator_getValue(iter);
|
2011-10-23 19:52:20 +02:00
|
|
|
int framenr, curproxy, curflags;
|
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (item->ibuf) {
|
2011-10-23 19:52:20 +02:00
|
|
|
cache->getdatafp(key->userkey, &framenr, &curproxy, &curflags);
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
if (curproxy == proxy && curflags == render_flags)
|
|
|
|
frames[a++] = framenr;
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
BLI_ghashIterator_step(iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_ghashIterator_free(iter);
|
|
|
|
|
|
|
|
qsort(frames, totframe, sizeof(int), compare_int);
|
|
|
|
|
|
|
|
/* count */
|
2012-03-26 18:04:10 +02:00
|
|
|
for (a = 0; a < totframe; a++) {
|
|
|
|
if (a && frames[a] - frames[a - 1] != 1)
|
2011-10-23 19:52:20 +02:00
|
|
|
totseg++;
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
if (a == totframe - 1)
|
2011-10-23 19:52:20 +02:00
|
|
|
totseg++;
|
|
|
|
}
|
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (totseg) {
|
2011-10-23 19:52:20 +02:00
|
|
|
int b, *points;
|
|
|
|
|
2012-05-16 11:26:37 +02:00
|
|
|
points = MEM_callocN(2 * sizeof(int) * totseg, "movieclip cache segments");
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
/* fill */
|
2012-03-26 18:04:10 +02:00
|
|
|
for (a = 0, b = 0; a < totframe; a++) {
|
|
|
|
if (a == 0)
|
|
|
|
points[b++] = frames[a];
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
if (a && frames[a] - frames[a - 1] != 1) {
|
|
|
|
points[b++] = frames[a - 1];
|
|
|
|
points[b++] = frames[a];
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
if (a == totframe - 1)
|
|
|
|
points[b++] = frames[a];
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
*totseg_r = totseg;
|
|
|
|
*points_r = points;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
cache->totseg = totseg;
|
|
|
|
cache->points = points;
|
|
|
|
cache->proxy = proxy;
|
|
|
|
cache->render_flags = render_flags;
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(frames);
|
|
|
|
}
|
|
|
|
}
|