2023-08-15 16:20:26 +02:00
|
|
|
/* SPDX-FileCopyrightText: 2011 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2019-02-17 22:08:12 +01:00
|
|
|
/** \file
|
|
|
|
* \ingroup bke
|
2011-10-23 19:52:20 +02:00
|
|
|
*/
|
|
|
|
|
2012-07-10 16:43:50 +02:00
|
|
|
#undef DEBUG_MESSAGES
|
|
|
|
|
2022-03-14 16:55:17 +01:00
|
|
|
#include <cstdlib> /* for qsort */
|
2011-10-23 19:52:20 +02:00
|
|
|
#include <memory.h>
|
2022-03-14 11:32:46 +01:00
|
|
|
#include <mutex>
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
#include "MEM_CacheLimiterC-Api.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "MEM_guardedalloc.h"
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
#include "BLI_ghash.h"
|
|
|
|
#include "BLI_mempool.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_string.h"
|
2012-09-14 16:55:59 +02:00
|
|
|
#include "BLI_threads.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_utildefines.h"
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
#include "IMB_moviecache.h"
|
|
|
|
|
|
|
|
#include "IMB_imbuf.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "IMB_imbuf_types.h"
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-07-10 16:43:50 +02:00
|
|
|
#ifdef DEBUG_MESSAGES
|
2017-09-29 11:10:08 +02:00
|
|
|
# if defined __GNUC__
|
2012-07-10 16:43:50 +02:00
|
|
|
# define PRINT(format, args...) printf(format, ##args)
|
|
|
|
# else
|
|
|
|
# define PRINT(format, ...) printf(__VA_ARGS__)
|
|
|
|
# endif
|
|
|
|
#else
|
|
|
|
# define PRINT(format, ...)
|
|
|
|
#endif
|
|
|
|
|
2022-03-14 16:55:17 +01:00
|
|
|
static MEM_CacheLimiterC *limitor = nullptr;
|
2022-03-14 11:32:46 +01:00
|
|
|
|
|
|
|
/* Image buffers managed by a moviecache might be using their own movie caches (used by color
|
|
|
|
* management). In practice this means that, for example, freeing MovieCache used by MovieClip
|
|
|
|
* will request freeing MovieCache owned by ImBuf. Freeing MovieCache needs to be thread-safe,
|
|
|
|
* so regular mutex will not work here, hence the recursive lock. */
|
|
|
|
static std::recursive_mutex limitor_lock;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2022-03-14 16:55:17 +01:00
|
|
|
struct MovieCache {
|
2012-07-10 16:43:50 +02:00
|
|
|
char name[64];
|
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
GHash *hash;
|
|
|
|
GHashHashFP hashfp;
|
|
|
|
GHashCmpFP cmpfp;
|
|
|
|
MovieCacheGetKeyDataFP getdatafp;
|
|
|
|
|
2012-07-10 16:43:50 +02:00
|
|
|
MovieCacheGetPriorityDataFP getprioritydatafp;
|
|
|
|
MovieCacheGetItemPriorityFP getitempriorityfp;
|
|
|
|
MovieCachePriorityDeleterFP prioritydeleterfp;
|
|
|
|
|
2023-06-03 00:36:28 +02:00
|
|
|
BLI_mempool *keys_pool;
|
|
|
|
BLI_mempool *items_pool;
|
|
|
|
BLI_mempool *userkeys_pool;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
int keysize;
|
2012-07-10 16:43:50 +02:00
|
|
|
|
|
|
|
void *last_userkey;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
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;
|
2022-03-14 16:55:17 +01:00
|
|
|
};
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2022-03-14 16:55:17 +01:00
|
|
|
struct MovieCacheKey {
|
2011-10-23 19:52:20 +02:00
|
|
|
MovieCache *cache_owner;
|
|
|
|
void *userkey;
|
2022-03-14 16:55:17 +01:00
|
|
|
};
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2022-03-14 16:55:17 +01:00
|
|
|
struct MovieCacheItem {
|
2011-10-23 19:52:20 +02:00
|
|
|
MovieCache *cache_owner;
|
|
|
|
ImBuf *ibuf;
|
2012-05-16 11:26:37 +02:00
|
|
|
MEM_CacheLimiterHandleC *c_handle;
|
2012-07-10 16:43:50 +02:00
|
|
|
void *priority_data;
|
2021-11-02 11:15:05 +01:00
|
|
|
/* Indicates that #ibuf is null, because there was an error during load. */
|
|
|
|
bool added_empty;
|
2022-03-14 16:55:17 +01:00
|
|
|
};
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2022-09-13 08:29:06 +02:00
|
|
|
static uint moviecache_hashhash(const void *keyv)
|
2011-10-23 19:52:20 +02:00
|
|
|
{
|
2022-03-14 11:28:45 +01:00
|
|
|
const MovieCacheKey *key = (const MovieCacheKey *)keyv;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
return key->cache_owner->hashfp(key->userkey);
|
|
|
|
}
|
|
|
|
|
2014-09-24 22:15:52 +02:00
|
|
|
static bool moviecache_hashcmp(const void *av, const void *bv)
|
2011-10-23 19:52:20 +02:00
|
|
|
{
|
2022-03-14 11:28:45 +01:00
|
|
|
const MovieCacheKey *a = (const MovieCacheKey *)av;
|
|
|
|
const MovieCacheKey *b = (const 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)
|
|
|
|
{
|
2022-03-14 11:28:45 +01:00
|
|
|
MovieCacheKey *key = (MovieCacheKey *)val;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-07-10 16:43:50 +02:00
|
|
|
BLI_mempool_free(key->cache_owner->userkeys_pool, key->userkey);
|
|
|
|
|
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;
|
2012-07-10 16:43:50 +02:00
|
|
|
MovieCache *cache = item->cache_owner;
|
|
|
|
|
|
|
|
PRINT("%s: cache '%s' free item %p buffer %p\n", __func__, cache->name, item, item->ibuf);
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2021-11-05 04:58:32 +01:00
|
|
|
if (item->c_handle) {
|
2022-03-14 11:32:46 +01:00
|
|
|
limitor_lock.lock();
|
2021-11-05 04:58:32 +01:00
|
|
|
MEM_CacheLimiter_unmanage(item->c_handle);
|
2022-03-14 11:32:46 +01:00
|
|
|
limitor_lock.unlock();
|
2021-11-05 04:58:32 +01:00
|
|
|
}
|
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
if (item->ibuf) {
|
|
|
|
IMB_freeImBuf(item->ibuf);
|
|
|
|
}
|
|
|
|
|
2012-07-10 16:43:50 +02:00
|
|
|
if (item->priority_data && cache->prioritydeleterfp) {
|
|
|
|
cache->prioritydeleterfp(item->priority_data);
|
|
|
|
}
|
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
BLI_mempool_free(item->cache_owner->items_pool, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void check_unused_keys(MovieCache *cache)
|
|
|
|
{
|
2015-02-06 05:31:08 +01:00
|
|
|
GHashIterator gh_iter;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2015-02-06 14:28:08 +01:00
|
|
|
BLI_ghashIterator_init(&gh_iter, cache->hash);
|
|
|
|
|
|
|
|
while (!BLI_ghashIterator_done(&gh_iter)) {
|
2022-03-14 11:28:45 +01:00
|
|
|
const MovieCacheKey *key = (const MovieCacheKey *)BLI_ghashIterator_getKey(&gh_iter);
|
|
|
|
const MovieCacheItem *item = (const MovieCacheItem *)BLI_ghashIterator_getValue(&gh_iter);
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2015-02-06 14:28:08 +01:00
|
|
|
BLI_ghashIterator_step(&gh_iter);
|
|
|
|
|
2021-11-02 11:15:05 +01:00
|
|
|
if (item->added_empty) {
|
|
|
|
/* Don't remove entries that have been added empty. Those indicate that the image couldn't be
|
|
|
|
* loaded correctly. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool remove = !item->ibuf;
|
2012-07-10 16:43:50 +02:00
|
|
|
|
2012-07-10 17:28:32 +02:00
|
|
|
if (remove) {
|
2012-07-10 16:43:50 +02:00
|
|
|
PRINT("%s: cache '%s' remove item %p without buffer\n", __func__, cache->name, item);
|
2012-07-10 17:28:32 +02:00
|
|
|
}
|
2012-07-10 16:43:50 +02:00
|
|
|
|
2019-04-23 03:01:30 +02:00
|
|
|
if (remove) {
|
2011-10-23 19:52:20 +02:00
|
|
|
BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int compare_int(const void *av, const void *bv)
|
|
|
|
{
|
2022-03-14 11:28:45 +01:00
|
|
|
const int *a = (int *)av;
|
|
|
|
const int *b = (int *)bv;
|
2012-03-26 18:04:10 +02:00
|
|
|
return *a - *b;
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
2022-03-14 11:20:48 +01:00
|
|
|
static void moviecache_destructor(void *p)
|
2011-10-23 19:52:20 +02:00
|
|
|
{
|
2012-09-05 03:42:52 +02:00
|
|
|
MovieCacheItem *item = (MovieCacheItem *)p;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
if (item && item->ibuf) {
|
2012-09-05 03:42:52 +02:00
|
|
|
MovieCache *cache = item->cache_owner;
|
|
|
|
|
|
|
|
PRINT("%s: cache '%s' destroy item %p buffer %p\n", __func__, cache->name, item, item->ibuf);
|
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
IMB_freeImBuf(item->ibuf);
|
|
|
|
|
2022-03-14 16:55:17 +01:00
|
|
|
item->ibuf = nullptr;
|
|
|
|
item->c_handle = nullptr;
|
2012-07-10 16:43:50 +02:00
|
|
|
|
|
|
|
/* force cached segments to be updated */
|
2021-08-06 05:59:38 +02:00
|
|
|
MEM_SAFE_FREE(cache->points);
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-28 23:13:41 +02:00
|
|
|
static size_t get_size_in_memory(ImBuf *ibuf)
|
2011-10-23 19:52:20 +02:00
|
|
|
{
|
2019-04-28 23:13:41 +02:00
|
|
|
/* Keep textures in the memory to avoid constant file reload on viewport update. */
|
2014-03-25 07:30:41 +01:00
|
|
|
if (ibuf->userflags & IB_PERSISTENT) {
|
|
|
|
return 0;
|
|
|
|
}
|
2020-08-07 12:39:50 +02:00
|
|
|
|
|
|
|
return IMB_get_size_in_memory(ibuf);
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
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
|
|
|
|
2019-04-23 03:01:30 +02:00
|
|
|
if (item->ibuf) {
|
2019-04-28 23:13:41 +02:00
|
|
|
size += get_size_in_memory(item->ibuf);
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2012-07-10 16:43:50 +02:00
|
|
|
static int get_item_priority(void *item_v, int default_priority)
|
|
|
|
{
|
|
|
|
MovieCacheItem *item = (MovieCacheItem *)item_v;
|
|
|
|
MovieCache *cache = item->cache_owner;
|
|
|
|
int priority;
|
|
|
|
|
|
|
|
if (!cache->getitempriorityfp) {
|
|
|
|
PRINT("%s: cache '%s' item %p use default priority %d\n",
|
|
|
|
__func__,
|
|
|
|
cache->name,
|
|
|
|
item,
|
|
|
|
default_priority);
|
|
|
|
|
|
|
|
return default_priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
priority = cache->getitempriorityfp(cache->last_userkey, item->priority_data);
|
|
|
|
|
|
|
|
PRINT("%s: cache '%s' item %p priority %d\n", __func__, cache->name, item, priority);
|
|
|
|
|
|
|
|
return priority;
|
|
|
|
}
|
|
|
|
|
2013-12-10 09:40:09 +01:00
|
|
|
static bool get_item_destroyable(void *item_v)
|
|
|
|
{
|
|
|
|
MovieCacheItem *item = (MovieCacheItem *)item_v;
|
2022-03-14 16:55:17 +01:00
|
|
|
if (item->ibuf == nullptr) {
|
2021-11-09 13:30:15 +01:00
|
|
|
return true;
|
|
|
|
}
|
2013-12-10 09:40:09 +01:00
|
|
|
/* IB_BITMAPDIRTY means image was modified from inside blender and
|
|
|
|
* changes are not saved to disk.
|
|
|
|
*
|
|
|
|
* Such buffers are never to be freed.
|
|
|
|
*/
|
2014-01-13 13:42:40 +01:00
|
|
|
if ((item->ibuf->userflags & IB_BITMAPDIRTY) || (item->ibuf->userflags & IB_PERSISTENT)) {
|
2013-12-10 09:40:09 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-07-02 11:37:22 +02:00
|
|
|
void IMB_moviecache_init()
|
2011-10-23 19:52:20 +02:00
|
|
|
{
|
2022-03-14 11:20:48 +01:00
|
|
|
limitor = new_MEM_CacheLimiter(moviecache_destructor, get_item_size);
|
2012-07-10 16:43:50 +02:00
|
|
|
|
|
|
|
MEM_CacheLimiter_ItemPriority_Func_set(limitor, get_item_priority);
|
2013-12-10 09:40:09 +01:00
|
|
|
MEM_CacheLimiter_ItemDestroyable_Func_set(limitor, get_item_destroyable);
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
2023-07-02 11:37:22 +02:00
|
|
|
void IMB_moviecache_destruct()
|
2011-10-23 19:52:20 +02:00
|
|
|
{
|
2019-04-23 03:01:30 +02:00
|
|
|
if (limitor) {
|
2011-10-23 19:52:20 +02:00
|
|
|
delete_MEM_CacheLimiter(limitor);
|
2022-03-14 16:55:17 +01:00
|
|
|
limitor = nullptr;
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
2012-07-10 16:43:50 +02:00
|
|
|
MovieCache *IMB_moviecache_create(const char *name,
|
|
|
|
int keysize,
|
|
|
|
GHashHashFP hashfp,
|
|
|
|
GHashCmpFP cmpfp)
|
2012-05-18 01:21:11 +02:00
|
|
|
{
|
2011-10-23 19:52:20 +02:00
|
|
|
MovieCache *cache;
|
|
|
|
|
2012-07-10 16:43:50 +02:00
|
|
|
PRINT("%s: cache '%s' create\n", __func__, name);
|
|
|
|
|
2022-03-14 11:28:45 +01:00
|
|
|
cache = (MovieCache *)MEM_callocN(sizeof(MovieCache), "MovieCache");
|
2012-07-10 16:43:50 +02:00
|
|
|
|
2023-05-09 04:50:37 +02:00
|
|
|
STRNCPY(cache->name, name);
|
2012-07-10 16:43:50 +02:00
|
|
|
|
2014-04-08 03:59:28 +02:00
|
|
|
cache->keys_pool = BLI_mempool_create(sizeof(MovieCacheKey), 0, 64, BLI_MEMPOOL_NOP);
|
|
|
|
cache->items_pool = BLI_mempool_create(sizeof(MovieCacheItem), 0, 64, BLI_MEMPOOL_NOP);
|
|
|
|
cache->userkeys_pool = BLI_mempool_create(keysize, 0, 64, BLI_MEMPOOL_NOP);
|
2012-03-26 18:04:10 +02:00
|
|
|
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->proxy = -1;
|
2011-10-23 19:52:20 +02:00
|
|
|
|
|
|
|
return cache;
|
|
|
|
}
|
|
|
|
|
2012-07-10 16:43:50 +02:00
|
|
|
void IMB_moviecache_set_getdata_callback(MovieCache *cache, MovieCacheGetKeyDataFP getdatafp)
|
|
|
|
{
|
|
|
|
cache->getdatafp = getdatafp;
|
|
|
|
}
|
|
|
|
|
2023-06-03 00:36:28 +02:00
|
|
|
void IMB_moviecache_set_priority_callback(MovieCache *cache,
|
2012-07-10 16:43:50 +02:00
|
|
|
MovieCacheGetPriorityDataFP getprioritydatafp,
|
|
|
|
MovieCacheGetItemPriorityFP getitempriorityfp,
|
|
|
|
MovieCachePriorityDeleterFP prioritydeleterfp)
|
|
|
|
{
|
|
|
|
cache->last_userkey = MEM_mallocN(cache->keysize, "movie cache last user key");
|
|
|
|
|
|
|
|
cache->getprioritydatafp = getprioritydatafp;
|
|
|
|
cache->getitempriorityfp = getitempriorityfp;
|
|
|
|
cache->prioritydeleterfp = prioritydeleterfp;
|
|
|
|
}
|
|
|
|
|
2014-04-01 02:34:00 +02:00
|
|
|
static void do_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf, bool need_lock)
|
2011-10-23 19:52:20 +02:00
|
|
|
{
|
|
|
|
MovieCacheKey *key;
|
|
|
|
MovieCacheItem *item;
|
|
|
|
|
2019-04-23 03:01:30 +02:00
|
|
|
if (!limitor) {
|
2011-10-23 19:52:20 +02:00
|
|
|
IMB_moviecache_init();
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2022-03-14 16:55:17 +01:00
|
|
|
if (ibuf != nullptr) {
|
2021-11-02 11:15:05 +01:00
|
|
|
IMB_refImBuf(ibuf);
|
|
|
|
}
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2022-03-14 11:28:45 +01:00
|
|
|
key = (MovieCacheKey *)BLI_mempool_alloc(cache->keys_pool);
|
2012-03-26 18:04:10 +02:00
|
|
|
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);
|
|
|
|
|
2022-03-14 11:28:45 +01:00
|
|
|
item = (MovieCacheItem *)BLI_mempool_alloc(cache->items_pool);
|
2012-07-10 16:43:50 +02:00
|
|
|
|
|
|
|
PRINT("%s: cache '%s' put %p, item %p\n", __func__, cache->name, ibuf, item);
|
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
item->ibuf = ibuf;
|
|
|
|
item->cache_owner = cache;
|
2022-03-14 16:55:17 +01:00
|
|
|
item->c_handle = nullptr;
|
|
|
|
item->priority_data = nullptr;
|
|
|
|
item->added_empty = ibuf == nullptr;
|
2012-07-10 16:43:50 +02:00
|
|
|
|
|
|
|
if (cache->getprioritydatafp) {
|
|
|
|
item->priority_data = cache->getprioritydatafp(userkey);
|
|
|
|
}
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2015-01-08 09:58:01 +01:00
|
|
|
BLI_ghash_reinsert(cache->hash, key, item, moviecache_keyfree, moviecache_valfree);
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2012-07-10 16:43:50 +02:00
|
|
|
if (cache->last_userkey) {
|
|
|
|
memcpy(cache->last_userkey, userkey, cache->keysize);
|
|
|
|
}
|
|
|
|
|
2019-04-23 03:01:30 +02:00
|
|
|
if (need_lock) {
|
2022-03-14 11:32:46 +01:00
|
|
|
limitor_lock.lock();
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2012-09-14 16:55:59 +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);
|
|
|
|
|
2019-04-23 03:01:30 +02:00
|
|
|
if (need_lock) {
|
2022-03-14 11:32:46 +01:00
|
|
|
limitor_lock.unlock();
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2012-09-14 16:55:59 +02:00
|
|
|
|
2018-09-03 16:49:08 +02:00
|
|
|
/* cache limiter can't remove unused keys which points to destroyed values */
|
2011-10-23 19:52:20 +02:00
|
|
|
check_unused_keys(cache);
|
|
|
|
|
2021-08-06 05:59:38 +02:00
|
|
|
MEM_SAFE_FREE(cache->points);
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
2013-03-20 18:03:20 +01:00
|
|
|
void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
|
|
|
|
{
|
2014-04-01 02:34:00 +02:00
|
|
|
do_moviecache_put(cache, userkey, ibuf, true);
|
2013-03-20 18:03:20 +01:00
|
|
|
}
|
|
|
|
|
2014-02-03 08:55:59 +01:00
|
|
|
bool IMB_moviecache_put_if_possible(MovieCache *cache, void *userkey, ImBuf *ibuf)
|
2013-03-20 18:03:20 +01:00
|
|
|
{
|
|
|
|
size_t mem_in_use, mem_limit, elem_size;
|
2014-02-03 08:55:59 +01:00
|
|
|
bool result = false;
|
2013-03-20 18:03:20 +01:00
|
|
|
|
2022-03-14 16:55:17 +01:00
|
|
|
elem_size = (ibuf == nullptr) ? 0 : get_size_in_memory(ibuf);
|
2013-03-20 18:03:20 +01:00
|
|
|
mem_limit = MEM_CacheLimiter_get_maximum();
|
|
|
|
|
2022-03-14 11:32:46 +01:00
|
|
|
limitor_lock.lock();
|
2013-03-20 18:03:20 +01:00
|
|
|
mem_in_use = MEM_CacheLimiter_get_memory_in_use(limitor);
|
|
|
|
|
|
|
|
if (mem_in_use + elem_size <= mem_limit) {
|
2014-04-01 02:34:00 +02:00
|
|
|
do_moviecache_put(cache, userkey, ibuf, false);
|
|
|
|
result = true;
|
2013-03-20 18:03:20 +01:00
|
|
|
}
|
|
|
|
|
2022-03-14 11:32:46 +01:00
|
|
|
limitor_lock.unlock();
|
2013-03-20 18:03:20 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
void IMB_moviecache_remove(MovieCache *cache, void *userkey)
|
|
|
|
{
|
|
|
|
MovieCacheKey key;
|
|
|
|
key.cache_owner = cache;
|
|
|
|
key.userkey = userkey;
|
|
|
|
BLI_ghash_remove(cache->hash, &key, moviecache_keyfree, moviecache_valfree);
|
|
|
|
}
|
|
|
|
|
2021-11-02 11:15:05 +01:00
|
|
|
ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey, bool *r_is_cached_empty)
|
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
|
|
|
|
2021-11-02 11:15:05 +01:00
|
|
|
if (r_is_cached_empty) {
|
|
|
|
*r_is_cached_empty = false;
|
|
|
|
}
|
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (item) {
|
|
|
|
if (item->ibuf) {
|
2022-03-14 11:32:46 +01:00
|
|
|
limitor_lock.lock();
|
2011-10-23 19:52:20 +02:00
|
|
|
MEM_CacheLimiter_touch(item->c_handle);
|
2022-03-14 11:32:46 +01:00
|
|
|
limitor_lock.unlock();
|
2012-09-14 16:55:59 +02:00
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
IMB_refImBuf(item->ibuf);
|
|
|
|
|
|
|
|
return item->ibuf;
|
|
|
|
}
|
2021-11-02 11:15:05 +01:00
|
|
|
if (r_is_cached_empty) {
|
|
|
|
*r_is_cached_empty = true;
|
|
|
|
}
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
2022-03-14 16:55:17 +01:00
|
|
|
return nullptr;
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
|
2014-02-03 08:55:59 +01:00
|
|
|
bool IMB_moviecache_has_frame(MovieCache *cache, void *userkey)
|
2013-03-20 18:03:20 +01:00
|
|
|
{
|
|
|
|
MovieCacheKey key;
|
|
|
|
MovieCacheItem *item;
|
|
|
|
|
|
|
|
key.cache_owner = cache;
|
|
|
|
key.userkey = userkey;
|
|
|
|
item = (MovieCacheItem *)BLI_ghash_lookup(cache->hash, &key);
|
|
|
|
|
2022-03-14 16:55:17 +01:00
|
|
|
return item != nullptr;
|
2013-03-20 18:03:20 +01:00
|
|
|
}
|
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
void IMB_moviecache_free(MovieCache *cache)
|
|
|
|
{
|
2012-09-20 14:59:16 +02:00
|
|
|
PRINT("%s: cache '%s' free\n", __func__, cache->name);
|
2012-07-10 16:43:50 +02:00
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
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);
|
|
|
|
|
2019-04-23 03:01:30 +02:00
|
|
|
if (cache->points) {
|
2011-10-23 19:52:20 +02:00
|
|
|
MEM_freeN(cache->points);
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2011-10-23 19:52:20 +02:00
|
|
|
|
2019-04-23 03:01:30 +02:00
|
|
|
if (cache->last_userkey) {
|
2012-07-10 16:43:50 +02:00
|
|
|
MEM_freeN(cache->last_userkey);
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2012-07-10 16:43:50 +02:00
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
MEM_freeN(cache);
|
|
|
|
}
|
|
|
|
|
2013-12-13 11:22:08 +01:00
|
|
|
void IMB_moviecache_cleanup(MovieCache *cache,
|
|
|
|
bool(cleanup_check_cb)(ImBuf *ibuf, void *userkey, void *userdata),
|
|
|
|
void *userdata)
|
2012-08-08 14:16:46 +02:00
|
|
|
{
|
2015-02-06 05:31:08 +01:00
|
|
|
GHashIterator gh_iter;
|
2012-08-08 14:16:46 +02:00
|
|
|
|
2013-12-16 17:05:27 +01:00
|
|
|
check_unused_keys(cache);
|
|
|
|
|
2015-02-06 17:39:26 +01:00
|
|
|
BLI_ghashIterator_init(&gh_iter, cache->hash);
|
|
|
|
|
|
|
|
while (!BLI_ghashIterator_done(&gh_iter)) {
|
2022-03-14 11:28:45 +01:00
|
|
|
MovieCacheKey *key = (MovieCacheKey *)BLI_ghashIterator_getKey(&gh_iter);
|
|
|
|
MovieCacheItem *item = (MovieCacheItem *)BLI_ghashIterator_getValue(&gh_iter);
|
2012-08-08 14:16:46 +02:00
|
|
|
|
2015-02-06 17:39:26 +01:00
|
|
|
BLI_ghashIterator_step(&gh_iter);
|
|
|
|
|
2013-12-16 17:05:27 +01:00
|
|
|
if (cleanup_check_cb(item->ibuf, key->userkey, userdata)) {
|
2012-08-08 14:16:46 +02:00
|
|
|
PRINT("%s: cache '%s' remove item %p\n", __func__, cache->name, item);
|
|
|
|
|
|
|
|
BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
void IMB_moviecache_get_cache_segments(
|
2020-03-25 07:58:58 +01:00
|
|
|
MovieCache *cache, int proxy, int render_flags, int *r_totseg, int **r_points)
|
2011-10-23 19:52:20 +02:00
|
|
|
{
|
2020-03-25 07:58:58 +01:00
|
|
|
*r_totseg = 0;
|
2022-03-14 16:55:17 +01:00
|
|
|
*r_points = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-23 03:01:30 +02:00
|
|
|
if (!cache->getdatafp) {
|
2011-10-23 19:52:20 +02:00
|
|
|
return;
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-26 18:04:10 +02:00
|
|
|
if (cache->proxy != proxy || cache->render_flags != render_flags) {
|
2021-08-06 05:59:38 +02:00
|
|
|
MEM_SAFE_FREE(cache->points);
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (cache->points) {
|
2020-03-25 07:58:58 +01:00
|
|
|
*r_totseg = cache->totseg;
|
|
|
|
*r_points = cache->points;
|
2012-03-24 07:38:07 +01:00
|
|
|
}
|
|
|
|
else {
|
2018-02-15 13:36:11 +01:00
|
|
|
int totframe = BLI_ghash_len(cache->hash);
|
2022-03-14 11:28:45 +01:00
|
|
|
int *frames = (int *)MEM_callocN(totframe * sizeof(int), "movieclip cache frames");
|
2012-03-26 18:04:10 +02:00
|
|
|
int a, totseg = 0;
|
2015-02-06 05:31:08 +01:00
|
|
|
GHashIterator gh_iter;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-04 01:47:39 +02:00
|
|
|
a = 0;
|
2015-02-06 05:31:08 +01:00
|
|
|
GHASH_ITER (gh_iter, cache->hash) {
|
2022-03-14 11:28:45 +01:00
|
|
|
MovieCacheKey *key = (MovieCacheKey *)BLI_ghashIterator_getKey(&gh_iter);
|
|
|
|
MovieCacheItem *item = (MovieCacheItem *)BLI_ghashIterator_getValue(&gh_iter);
|
2011-10-23 19:52:20 +02:00
|
|
|
int framenr, curproxy, curflags;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
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);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-23 03:01:30 +02:00
|
|
|
if (curproxy == proxy && curflags == render_flags) {
|
2012-03-26 18:04:10 +02:00
|
|
|
frames[a++] = framenr;
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
qsort(frames, totframe, sizeof(int), compare_int);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
/* count */
|
2012-03-26 18:04:10 +02:00
|
|
|
for (a = 0; a < totframe; a++) {
|
2019-04-23 03:01:30 +02:00
|
|
|
if (a && frames[a] - frames[a - 1] != 1) {
|
2011-10-23 19:52:20 +02:00
|
|
|
totseg++;
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-23 03:01:30 +02:00
|
|
|
if (a == totframe - 1) {
|
2011-10-23 19:52:20 +02:00
|
|
|
totseg++;
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 07:38:07 +01:00
|
|
|
if (totseg) {
|
2011-10-23 19:52:20 +02:00
|
|
|
int b, *points;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-14 11:28:45 +01:00
|
|
|
points = (int *)MEM_callocN(sizeof(int[2]) * totseg, "movieclip cache segments");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
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++) {
|
2019-04-23 03:01:30 +02:00
|
|
|
if (a == 0) {
|
2012-03-26 18:04:10 +02:00
|
|
|
points[b++] = frames[a];
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +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
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-23 03:01:30 +02:00
|
|
|
if (a == totframe - 1) {
|
2012-03-26 18:04:10 +02:00
|
|
|
points[b++] = frames[a];
|
2019-04-23 03:01:30 +02:00
|
|
|
}
|
2011-10-23 19:52:20 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-25 07:58:58 +01:00
|
|
|
*r_totseg = totseg;
|
|
|
|
*r_points = points;
|
2019-04-17 06:17:24 +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
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-10-23 19:52:20 +02:00
|
|
|
MEM_freeN(frames);
|
|
|
|
}
|
|
|
|
}
|
2013-12-13 11:22:08 +01:00
|
|
|
|
2023-06-03 00:36:28 +02:00
|
|
|
MovieCacheIter *IMB_moviecacheIter_new(MovieCache *cache)
|
2013-12-13 11:22:08 +01:00
|
|
|
{
|
2013-12-16 17:05:27 +01:00
|
|
|
GHashIterator *iter;
|
|
|
|
|
|
|
|
check_unused_keys(cache);
|
|
|
|
iter = BLI_ghashIterator_new(cache->hash);
|
|
|
|
|
2023-06-03 00:36:28 +02:00
|
|
|
return (MovieCacheIter *)iter;
|
2013-12-13 11:22:08 +01:00
|
|
|
}
|
|
|
|
|
2023-06-03 00:36:28 +02:00
|
|
|
void IMB_moviecacheIter_free(MovieCacheIter *iter)
|
2013-12-13 11:22:08 +01:00
|
|
|
{
|
|
|
|
BLI_ghashIterator_free((GHashIterator *)iter);
|
|
|
|
}
|
|
|
|
|
2023-06-03 00:36:28 +02:00
|
|
|
bool IMB_moviecacheIter_done(MovieCacheIter *iter)
|
2013-12-13 11:22:08 +01:00
|
|
|
{
|
|
|
|
return BLI_ghashIterator_done((GHashIterator *)iter);
|
|
|
|
}
|
|
|
|
|
2023-06-03 00:36:28 +02:00
|
|
|
void IMB_moviecacheIter_step(MovieCacheIter *iter)
|
2013-12-13 11:22:08 +01:00
|
|
|
{
|
|
|
|
BLI_ghashIterator_step((GHashIterator *)iter);
|
|
|
|
}
|
|
|
|
|
2023-06-03 00:36:28 +02:00
|
|
|
ImBuf *IMB_moviecacheIter_getImBuf(MovieCacheIter *iter)
|
2013-12-13 11:22:08 +01:00
|
|
|
{
|
2022-03-14 11:28:45 +01:00
|
|
|
MovieCacheItem *item = (MovieCacheItem *)BLI_ghashIterator_getValue((GHashIterator *)iter);
|
2013-12-13 11:22:08 +01:00
|
|
|
return item->ibuf;
|
|
|
|
}
|
|
|
|
|
2023-06-03 00:36:28 +02:00
|
|
|
void *IMB_moviecacheIter_getUserKey(MovieCacheIter *iter)
|
2013-12-13 11:22:08 +01:00
|
|
|
{
|
2022-03-14 11:28:45 +01:00
|
|
|
MovieCacheKey *key = (MovieCacheKey *)BLI_ghashIterator_getKey((GHashIterator *)iter);
|
2013-12-13 11:22:08 +01:00
|
|
|
return key->userkey;
|
|
|
|
}
|