This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/blenkernel/intern/seqcache.c

344 lines
7.2 KiB
C
Raw Normal View History

/*
* ***** 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.
*
* Peter Schlaile <peter [at] schlaile [dot] de> 2010
*
* Contributor(s): Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
2011-02-27 20:40:57 +00:00
/** \file blender/blenkernel/intern/seqcache.c
* \ingroup bke
*/
#include <stddef.h>
#include "BLI_sys_types.h" /* for intptr_t */
#include "MEM_guardedalloc.h"
#include "DNA_sequence_types.h"
#include "IMB_moviecache.h"
#include "IMB_imbuf.h"
2012-08-08 11:52:14 +00:00
#include "IMB_imbuf_types.h"
#include "BLI_listbase.h"
2013-03-08 04:00:06 +00:00
#include "BKE_sequencer.h"
typedef struct SeqCacheKey {
struct Sequence *seq;
SeqRenderData context;
float cfra;
seq_stripelem_ibuf_t type;
} SeqCacheKey;
typedef struct SeqPreprocessCacheElem {
struct SeqPreprocessCacheElem *next, *prev;
struct Sequence *seq;
SeqRenderData context;
seq_stripelem_ibuf_t 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 int seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
{
if (a->preview_render_size < b->preview_render_size) {
return -1;
}
if (a->preview_render_size > b->preview_render_size) {
return 1;
}
if (a->rectx < b->rectx) {
return -1;
}
if (a->rectx > b->rectx) {
return 1;
}
if (a->recty < b->recty) {
return -1;
}
if (a->recty > b->recty) {
return 1;
}
if (a->bmain < b->bmain) {
return -1;
}
if (a->bmain > b->bmain) {
return 1;
}
if (a->scene < b->scene) {
return -1;
}
if (a->scene > b->scene) {
return 1;
}
if (a->motion_blur_shutter < b->motion_blur_shutter) {
return -1;
}
if (a->motion_blur_shutter > b->motion_blur_shutter) {
return 1;
}
if (a->motion_blur_samples < b->motion_blur_samples) {
return -1;
}
if (a->motion_blur_samples > b->motion_blur_samples) {
return 1;
}
return 0;
}
static unsigned int seq_hash_render_data(const SeqRenderData *a)
{
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 << 24;
return rval;
}
static unsigned int seqcache_hashhash(const void *key_)
{
const SeqCacheKey *key = (SeqCacheKey *) key_;
unsigned int rval = seq_hash_render_data(&key->context);
rval ^= *(unsigned int *) &key->cfra;
rval += key->type;
2010-09-12 14:46:41 +00:00
rval ^= ((intptr_t) key->seq) << 6;
return rval;
}
static int 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;
}
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);
}
void BKE_sequencer_cache_destruct(void)
{
if (moviecache)
IMB_moviecache_free(moviecache);
preprocessed_cache_destruct();
}
void BKE_sequencer_cache_cleanup(void)
{
if (moviecache) {
IMB_moviecache_free(moviecache);
moviecache = IMB_moviecache_create("seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
}
BKE_sequencer_preprocessed_cache_cleanup();
}
Image cache rewrite to using generic movie cache Summary: Behaves very much the same as cache for Movie Clip datablock: - Image now have `MovieCache *cache` field which replaced legacy `ListBase ibufs`. This allows image datablock to easily keep of image buffers which are owned by itself. This field isn't saved to the file and getting restored on undo steps. However, cache limit is global for movies, sequences and image datablocks now. So overall cached image buffers size will not go above cache limit size in user preferences. - Image buffers which are marked as BITMAPDIRTY will never be freed from the cache. - Added utility function to iterate over image buffers saved in movie cache. - Movie cache cleanup check callback now have ImBuf argument which can be used in a condition of cleanup. - Added some utility functions which replaces legacy ibufs iterations with image cache iteration which happens from inside a lock. - Fixed `image_mem_size()` which was only counting one of the buffers if both float and byte buffer present. Additional notes: - `BKE_image_get_first_ibuf()` is rather stupid, but direct access to ibufs->first was also the same stupid idea. Would consider avoid this function is another project. - There are some places which doesn't look threadsafe, but they already were not so much threadsafe anyway before. So think not a big deal with solving this later. Finally solves infinite memory usage by image sequences! :) Reviewers: brecht, campbellbarton Reviewed By: brecht CC: sebastian_k Differential Revision: http://developer.blender.org/D95
2013-12-13 16:22:08 +06:00
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;
}
void BKE_sequencer_cache_cleanup_sequence(Sequence *seq)
{
if (moviecache)
IMB_moviecache_cleanup(moviecache, seqcache_key_check_seq, seq);
}
2012-08-08 11:52:14 +00:00
struct ImBuf *BKE_sequencer_cache_get(SeqRenderData context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type)
{
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);
}
return NULL;
}
2012-08-08 11:52:14 +00:00
void BKE_sequencer_cache_put(SeqRenderData context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type, ImBuf *i)
{
SeqCacheKey key;
if (i == NULL || context.skip_cache) {
return;
}
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 BKE_sequencer_preprocessed_cache_cleanup(void)
{
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);
preprocess_cache->elems.first = preprocess_cache->elems.last = NULL;
}
static void preprocessed_cache_destruct(void)
{
if (!preprocess_cache)
return;
BKE_sequencer_preprocessed_cache_cleanup();
MEM_freeN(preprocess_cache);
preprocess_cache = NULL;
}
ImBuf *BKE_sequencer_preprocessed_cache_get(SeqRenderData context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type)
{
SeqPreprocessCacheElem *elem;
if (!preprocess_cache)
return NULL;
if (preprocess_cache->cfra != cfra)
return NULL;
for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
if (elem->seq != seq)
continue;
if (elem->type != type)
continue;
if (seq_cmp_render_data(&elem->context, &context) != 0)
continue;
IMB_refImBuf(elem->ibuf);
return elem->ibuf;
}
return NULL;
}
void BKE_sequencer_preprocessed_cache_put(SeqRenderData context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type, ImBuf *ibuf)
{
SeqPreprocessCacheElem *elem;
if (!preprocess_cache) {
preprocess_cache = MEM_callocN(sizeof(SeqPreprocessCache), "sequencer preprocessed cache");
}
else {
if (preprocess_cache->cfra != cfra)
BKE_sequencer_preprocessed_cache_cleanup();
}
elem = MEM_callocN(sizeof(SeqPreprocessCacheElem), "sequencer preprocessed cache element");
elem->seq = seq;
elem->type = type;
elem->context = context;
elem->ibuf = ibuf;
preprocess_cache->cfra = cfra;
IMB_refImBuf(ibuf);
BLI_addtail(&preprocess_cache->elems, elem);
}
void BKE_sequencer_preprocessed_cache_cleanup_sequence(Sequence *seq)
{
SeqPreprocessCacheElem *elem, *elem_next;
if (!preprocess_cache)
return;
for (elem = preprocess_cache->elems.first; elem; elem = elem_next) {
elem_next = elem->next;
if (elem->seq == seq) {
IMB_freeImBuf(elem->ibuf);
BLI_freelinkN(&preprocess_cache->elems, elem);
}
}
}