2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2010-07-23 16:57:11 +00:00
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup bke
|
2011-02-27 20:40:57 +00:00
|
|
|
*/
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
#include <memory.h>
|
2020-03-19 09:33:03 +01:00
|
|
|
#include <stddef.h>
|
2020-03-19 00:05:18 +01:00
|
|
|
#include <time.h>
|
2010-07-23 16:57:11 +00:00
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
2015-04-06 10:40:12 -03:00
|
|
|
#include "DNA_scene_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_sequence_types.h"
|
2020-03-19 00:05:18 +01:00
|
|
|
#include "DNA_space_types.h" /* for FILE_MAX. */
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "IMB_colormanagement.h"
|
2012-08-19 15:41:56 +00:00
|
|
|
#include "IMB_imbuf.h"
|
2012-08-08 11:52:14 +00:00
|
|
|
#include "IMB_imbuf_types.h"
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BLI_endian_switch.h"
|
|
|
|
#include "BLI_fileops.h"
|
|
|
|
#include "BLI_fileops_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_ghash.h"
|
|
|
|
#include "BLI_listbase.h"
|
|
|
|
#include "BLI_mempool.h"
|
2020-03-19 00:05:18 +01:00
|
|
|
#include "BLI_path_util.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_threads.h"
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
#include "BKE_global.h"
|
2019-04-28 14:13:41 -07:00
|
|
|
#include "BKE_main.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_scene.h"
|
|
|
|
#include "BKE_sequencer.h"
|
2019-04-28 14:13:41 -07:00
|
|
|
|
2019-06-12 09:04:10 +10:00
|
|
|
/**
|
|
|
|
* Sequencer Cache Design Notes
|
|
|
|
* ============================
|
2019-04-28 14:13:41 -07:00
|
|
|
*
|
|
|
|
* Function:
|
|
|
|
* All images created during rendering are added to cache, even if the cache is already full.
|
|
|
|
* This is because:
|
|
|
|
* - one image may be needed multiple times during rendering.
|
|
|
|
* - keeping the last rendered frame allows us for faster re-render when user edits strip in stack
|
|
|
|
* - we can decide if we keep frame only when it's completely rendered. Otherwise we risk having
|
|
|
|
* "holes" in the cache, which can be annoying
|
|
|
|
* If the cache is full all entries for pending frame will have is_temp_cache set.
|
|
|
|
*
|
2019-09-13 17:21:54 -07:00
|
|
|
* Linking: We use links to reduce number of iterations over entries needed to manage cache.
|
|
|
|
* Entries are linked in order as they are put into cache.
|
|
|
|
* Only permanent (is_temp_cache = 0) cache entries are linked.
|
|
|
|
* Putting #SEQ_CACHE_STORE_FINAL_OUT will reset linking
|
|
|
|
*
|
2019-04-28 14:13:41 -07:00
|
|
|
* Only entire frame can be freed to release resources for new entries (recycling).
|
|
|
|
* Once again, this is to reduce number of iterations, but also more controllable than removing
|
|
|
|
* entries one by one in reverse order to their creation.
|
|
|
|
*
|
|
|
|
* User can exclude caching of some images. Such entries will have is_temp_cache set.
|
2020-03-19 00:05:18 +01:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* Disk Cache Design Notes
|
|
|
|
* =======================
|
|
|
|
*
|
|
|
|
* Disk cache uses directory specified in user preferences
|
|
|
|
* For each cached non-temp image, image data and supplementary info are written to HDD.
|
|
|
|
* Multiple(DCACHE_IMAGES_PER_FILE) images share the same file.
|
|
|
|
* Each of these files contains header DiskCacheHeader followed by image data.
|
|
|
|
* Zlib compression with user definable level can be used to compress image data(per image)
|
2020-03-19 12:05:34 +11:00
|
|
|
* Images are written in order in which they are rendered.
|
2020-03-19 00:05:18 +01:00
|
|
|
* Overwriting of individual entry is not possible.
|
|
|
|
* Stored images are deleted by invalidation, or when size of all files exceeds maximum
|
|
|
|
* size specified in user preferences.
|
|
|
|
* To distinguish 2 blend files with same name, scene->ed->disk_cache_timestamp
|
|
|
|
* is used as UID. Blend file can still be copied manually which may cause conflict.
|
|
|
|
*
|
2019-04-28 14:13:41 -07:00
|
|
|
*/
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
/* <cache type>-<resolution X>x<resolution Y>-<rendersize>%(<view_id>)-<frame no>.dcf */
|
|
|
|
#define DCACHE_FNAME_FORMAT "%d-%dx%d-%d%%(%d)-%d.dcf"
|
|
|
|
#define DCACHE_IMAGES_PER_FILE 100
|
|
|
|
#define DCACHE_CURRENT_VERSION 1
|
|
|
|
#define COLORSPACE_NAME_MAX 64 /* XXX: defined in imb intern */
|
|
|
|
|
|
|
|
typedef struct DiskCacheHeaderEntry {
|
|
|
|
unsigned char encoding;
|
|
|
|
uint64_t frameno;
|
|
|
|
uint64_t size_compressed;
|
|
|
|
uint64_t size_raw;
|
|
|
|
uint64_t offset;
|
|
|
|
char colorspace_name[COLORSPACE_NAME_MAX];
|
|
|
|
} DiskCacheHeaderEntry;
|
|
|
|
|
|
|
|
typedef struct DiskCacheHeader {
|
|
|
|
DiskCacheHeaderEntry entry[DCACHE_IMAGES_PER_FILE];
|
|
|
|
} DiskCacheHeader;
|
|
|
|
|
|
|
|
typedef struct SeqDiskCache {
|
|
|
|
Main *bmain;
|
|
|
|
int64_t timestamp;
|
|
|
|
ListBase files;
|
|
|
|
ThreadMutex read_write_mutex;
|
|
|
|
size_t size_total;
|
|
|
|
} SeqDiskCache;
|
|
|
|
|
|
|
|
typedef struct DiskCacheFile {
|
|
|
|
struct DiskCacheFile *next, *prev;
|
|
|
|
char path[FILE_MAX];
|
|
|
|
char dir[FILE_MAXDIR];
|
|
|
|
char file[FILE_MAX];
|
|
|
|
BLI_stat_t fstat;
|
|
|
|
int cache_type;
|
|
|
|
int rectx;
|
|
|
|
int recty;
|
|
|
|
int render_size;
|
|
|
|
int view_id;
|
|
|
|
int start_frame;
|
|
|
|
} DiskCacheFile;
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
typedef struct SeqCache {
|
2020-03-19 00:05:18 +01:00
|
|
|
Main *bmain;
|
2019-04-28 14:13:41 -07:00
|
|
|
struct GHash *hash;
|
|
|
|
ThreadMutex iterator_mutex;
|
|
|
|
struct BLI_mempool *keys_pool;
|
|
|
|
struct BLI_mempool *items_pool;
|
|
|
|
struct SeqCacheKey *last_key;
|
|
|
|
size_t memory_used;
|
2020-03-19 00:05:18 +01:00
|
|
|
SeqDiskCache *disk_cache;
|
2019-04-28 14:13:41 -07:00
|
|
|
} SeqCache;
|
|
|
|
|
|
|
|
typedef struct SeqCacheItem {
|
|
|
|
struct SeqCache *cache_owner;
|
|
|
|
struct ImBuf *ibuf;
|
|
|
|
} SeqCacheItem;
|
2013-03-08 04:00:06 +00:00
|
|
|
|
2012-06-10 15:20:10 +00:00
|
|
|
typedef struct SeqCacheKey {
|
2019-04-28 14:13:41 -07:00
|
|
|
struct SeqCache *cache_owner;
|
|
|
|
void *userkey;
|
2020-03-19 00:05:18 +01:00
|
|
|
struct SeqCacheKey *link_prev; /* Used for linking intermediate items to final frame. */
|
|
|
|
struct SeqCacheKey *link_next; /* Used for linking intermediate items to final frame. */
|
2019-04-17 06:17:24 +02:00
|
|
|
struct Sequence *seq;
|
|
|
|
SeqRenderData context;
|
2019-04-28 14:13:41 -07:00
|
|
|
float nfra;
|
2019-09-13 17:21:54 -07:00
|
|
|
float cost; /* In short: render time(s) divided by playback frame duration(s) */
|
|
|
|
bool is_temp_cache; /* this cache entry will be freed before rendering next frame */
|
|
|
|
/* ID of task for asigning temp cache entries to particular task(thread, etc.) */
|
|
|
|
eSeqTaskId task_id;
|
2019-04-28 14:13:41 -07:00
|
|
|
int type;
|
2012-06-10 15:20:10 +00:00
|
|
|
} SeqCacheKey;
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
static ThreadMutex cache_create_lock = BLI_MUTEX_INITIALIZER;
|
2020-03-19 00:05:18 +01:00
|
|
|
static float seq_cache_cfra_to_frame_index(Sequence *seq, float cfra);
|
|
|
|
static float seq_cache_frame_index_to_cfra(Sequence *seq, float nfra);
|
|
|
|
|
|
|
|
static char *seq_disk_cache_base_dir(void)
|
|
|
|
{
|
|
|
|
return U.sequencer_disk_cache_dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int seq_disk_cache_compression_level(void)
|
|
|
|
{
|
|
|
|
switch (U.sequencer_disk_cache_compression) {
|
|
|
|
case USER_SEQ_DISK_CACHE_COMPRESSION_NONE:
|
|
|
|
return 0;
|
|
|
|
case USER_SEQ_DISK_CACHE_COMPRESSION_LOW:
|
|
|
|
return 1;
|
|
|
|
case USER_SEQ_DISK_CACHE_COMPRESSION_HIGH:
|
|
|
|
return 9;
|
|
|
|
}
|
|
|
|
|
|
|
|
return U.sequencer_disk_cache_compression;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t seq_disk_cache_size_limit(void)
|
|
|
|
{
|
|
|
|
return (size_t)U.sequencer_disk_cache_size_limit * (1024 * 1024 * 1024);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool seq_disk_cache_is_enabled(Main *bmain)
|
|
|
|
{
|
|
|
|
return (U.sequencer_disk_cache_dir[0] != '\0' && U.sequencer_disk_cache_size_limit != 0 &&
|
|
|
|
(U.sequencer_disk_cache_flag & SEQ_CACHE_DISK_CACHE_ENABLE) != 0 &&
|
|
|
|
bmain->name[0] != '\0');
|
|
|
|
}
|
|
|
|
|
|
|
|
static DiskCacheFile *seq_disk_cache_add_file_to_list(SeqDiskCache *disk_cache, const char *path)
|
|
|
|
{
|
|
|
|
|
|
|
|
DiskCacheFile *cache_file = MEM_callocN(sizeof(DiskCacheFile), "SeqDiskCacheFile");
|
|
|
|
char dir[FILE_MAXDIR], file[FILE_MAX];
|
|
|
|
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
|
|
|
|
BLI_strncpy(cache_file->path, path, sizeof(cache_file->path));
|
|
|
|
BLI_strncpy(cache_file->dir, dir, sizeof(cache_file->dir));
|
|
|
|
BLI_strncpy(cache_file->file, file, sizeof(cache_file->file));
|
|
|
|
sscanf(file,
|
|
|
|
DCACHE_FNAME_FORMAT,
|
|
|
|
&cache_file->cache_type,
|
|
|
|
&cache_file->rectx,
|
|
|
|
&cache_file->recty,
|
|
|
|
&cache_file->render_size,
|
|
|
|
&cache_file->view_id,
|
|
|
|
&cache_file->start_frame);
|
|
|
|
cache_file->start_frame *= DCACHE_IMAGES_PER_FILE;
|
|
|
|
BLI_addtail(&disk_cache->files, cache_file);
|
|
|
|
return cache_file;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path)
|
|
|
|
{
|
|
|
|
struct direntry *filelist, *fl;
|
|
|
|
uint nbr, i;
|
|
|
|
disk_cache->size_total = 0;
|
|
|
|
|
|
|
|
i = nbr = BLI_filelist_dir_contents(path, &filelist);
|
|
|
|
fl = filelist;
|
|
|
|
while (i--) {
|
|
|
|
/* Don't follow links. */
|
|
|
|
const eFileAttributes file_attrs = BLI_file_attributes(fl->path);
|
|
|
|
if (file_attrs & FILE_ATTR_ANY_LINK) {
|
|
|
|
fl++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
char file[FILE_MAX];
|
|
|
|
BLI_split_dirfile(fl->path, NULL, file, 0, sizeof(file));
|
|
|
|
|
|
|
|
bool is_dir = BLI_is_dir(fl->path);
|
|
|
|
if (is_dir && !FILENAME_IS_CURRPAR(file)) {
|
|
|
|
char subpath[FILE_MAX];
|
|
|
|
BLI_strncpy(subpath, fl->path, sizeof(subpath));
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_slash_ensure(subpath);
|
2020-03-19 00:05:18 +01:00
|
|
|
seq_disk_cache_get_files(disk_cache, subpath);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_dir) {
|
|
|
|
const char *ext = BLI_path_extension(fl->path);
|
|
|
|
if (ext && ext[1] == 'd' && ext[2] == 'c' && ext[3] == 'f') {
|
|
|
|
DiskCacheFile *cache_file = seq_disk_cache_add_file_to_list(disk_cache, fl->path);
|
|
|
|
cache_file->fstat = fl->s;
|
|
|
|
disk_cache->size_total += cache_file->fstat.st_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fl++;
|
|
|
|
}
|
|
|
|
BLI_filelist_free(filelist, nbr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static DiskCacheFile *seq_disk_cache_get_oldest_file(SeqDiskCache *disk_cache)
|
|
|
|
{
|
2020-03-19 11:50:46 +11:00
|
|
|
DiskCacheFile *oldest_file = disk_cache->files.first;
|
|
|
|
if (oldest_file == NULL) {
|
2020-03-19 00:05:18 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2020-03-19 11:50:46 +11:00
|
|
|
for (DiskCacheFile *cache_file = oldest_file->next; cache_file; cache_file = cache_file->next) {
|
|
|
|
if (cache_file->fstat.st_mtime < oldest_file->fstat.st_mtime) {
|
2020-03-19 00:05:18 +01:00
|
|
|
oldest_file = cache_file;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return oldest_file;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seq_disk_cache_delete_file(SeqDiskCache *disk_cache, DiskCacheFile *file)
|
|
|
|
{
|
|
|
|
disk_cache->size_total -= file->fstat.st_size;
|
|
|
|
BLI_delete(file->path, false, false);
|
|
|
|
BLI_remlink(&disk_cache->files, file);
|
|
|
|
MEM_freeN(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool seq_disk_cache_enforce_limits(SeqDiskCache *disk_cache)
|
|
|
|
{
|
|
|
|
BLI_mutex_lock(&disk_cache->read_write_mutex);
|
|
|
|
while (disk_cache->size_total > seq_disk_cache_size_limit()) {
|
|
|
|
DiskCacheFile *oldest_file = seq_disk_cache_get_oldest_file(disk_cache);
|
|
|
|
|
|
|
|
if (!oldest_file) {
|
|
|
|
/* We shouldn't enforce limits with no files, do re-scan. */
|
|
|
|
seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (BLI_exists(oldest_file->path) == 0) {
|
|
|
|
/* File may have been manually deleted during runtime, do re-scan. */
|
|
|
|
BLI_freelistN(&disk_cache->files);
|
|
|
|
seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
seq_disk_cache_delete_file(disk_cache, oldest_file);
|
|
|
|
}
|
|
|
|
BLI_mutex_unlock(&disk_cache->read_write_mutex);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static DiskCacheFile *seq_disk_cache_get_file_entry_by_path(SeqDiskCache *disk_cache, char *path)
|
|
|
|
{
|
|
|
|
DiskCacheFile *cache_file = disk_cache->files.first;
|
|
|
|
|
|
|
|
for (; cache_file; cache_file = cache_file->next) {
|
|
|
|
if (BLI_strcasecmp(cache_file->path, path) == 0) {
|
|
|
|
return cache_file;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update file size and timestamp. */
|
|
|
|
static void seq_disk_cache_update_file(SeqDiskCache *disk_cache, char *path)
|
|
|
|
{
|
|
|
|
DiskCacheFile *cache_file;
|
|
|
|
int64_t size_before;
|
|
|
|
int64_t size_after;
|
|
|
|
|
|
|
|
cache_file = seq_disk_cache_get_file_entry_by_path(disk_cache, path);
|
|
|
|
size_before = cache_file->fstat.st_size;
|
|
|
|
|
|
|
|
if (BLI_stat(path, &cache_file->fstat) == -1) {
|
|
|
|
BLI_assert(false);
|
|
|
|
memset(&cache_file->fstat, 0, sizeof(BLI_stat_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
size_after = cache_file->fstat.st_size;
|
|
|
|
disk_cache->size_total += size_after - size_before;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Path format:
|
|
|
|
* <cache dir>/<project name>/<scene name>-<timestamp>/<seq name>/DCACHE_FNAME_FORMAT
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void seq_disk_cache_get_project_dir(SeqDiskCache *disk_cache, char *path, size_t path_len)
|
|
|
|
{
|
|
|
|
char main_name[FILE_MAX];
|
|
|
|
BLI_split_file_part(BKE_main_blendfile_path(disk_cache->bmain), main_name, sizeof(main_name));
|
|
|
|
BLI_strncpy(path, seq_disk_cache_base_dir(), path_len);
|
|
|
|
BLI_path_append(path, path_len, main_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seq_disk_cache_get_dir(
|
|
|
|
SeqDiskCache *disk_cache, Scene *scene, Sequence *seq, char *path, size_t path_len)
|
|
|
|
{
|
|
|
|
char scene_name[MAX_ID_NAME + 22]; /* + -%PRId64 */
|
|
|
|
char seq_name[SEQ_NAME_MAXSTR];
|
|
|
|
char project_dir[FILE_MAX];
|
|
|
|
|
|
|
|
seq_disk_cache_get_project_dir(disk_cache, project_dir, sizeof(project_dir));
|
|
|
|
sprintf(scene_name, "%s-%" PRId64, scene->id.name, disk_cache->timestamp);
|
|
|
|
BLI_strncpy(seq_name, seq->name, sizeof(seq_name));
|
|
|
|
BLI_filename_make_safe(scene_name);
|
|
|
|
BLI_filename_make_safe(seq_name);
|
|
|
|
BLI_strncpy(path, project_dir, path_len);
|
|
|
|
BLI_path_append(path, path_len, scene_name);
|
|
|
|
BLI_path_append(path, path_len, seq_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seq_disk_cache_get_file_path(SeqDiskCache *disk_cache,
|
|
|
|
SeqCacheKey *key,
|
|
|
|
char *path,
|
|
|
|
size_t path_len)
|
|
|
|
{
|
|
|
|
seq_disk_cache_get_dir(disk_cache, key->context.scene, key->seq, path, path_len);
|
|
|
|
int frameno = (int)key->nfra / DCACHE_IMAGES_PER_FILE;
|
|
|
|
char cache_filename[FILE_MAXFILE];
|
|
|
|
sprintf(cache_filename,
|
|
|
|
DCACHE_FNAME_FORMAT,
|
|
|
|
key->type,
|
|
|
|
key->context.rectx,
|
|
|
|
key->context.recty,
|
|
|
|
key->context.preview_render_size,
|
|
|
|
key->context.view_id,
|
|
|
|
frameno);
|
|
|
|
|
|
|
|
BLI_path_append(path, path_len, cache_filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seq_disk_cache_create_version_file(char *path)
|
|
|
|
{
|
|
|
|
BLI_make_existing_file(path);
|
|
|
|
|
|
|
|
FILE *file = BLI_fopen(path, "w");
|
|
|
|
if (file) {
|
|
|
|
fprintf(file, "%d", DCACHE_CURRENT_VERSION);
|
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seq_disk_cache_handle_versioning(SeqDiskCache *disk_cache)
|
|
|
|
{
|
|
|
|
char path[FILE_MAX];
|
|
|
|
char path_version_file[FILE_MAX];
|
|
|
|
int version = 0;
|
|
|
|
|
|
|
|
seq_disk_cache_get_project_dir(disk_cache, path, sizeof(path));
|
|
|
|
BLI_strncpy(path_version_file, path, sizeof(path_version_file));
|
|
|
|
BLI_path_append(path_version_file, sizeof(path_version_file), "cache_version");
|
|
|
|
|
|
|
|
if (BLI_exists(path)) {
|
|
|
|
FILE *file = BLI_fopen(path_version_file, "r");
|
|
|
|
|
|
|
|
if (file) {
|
|
|
|
fscanf(file, "%d", &version);
|
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (version != DCACHE_CURRENT_VERSION) {
|
|
|
|
BLI_delete(path, false, true);
|
|
|
|
seq_disk_cache_create_version_file(path_version_file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
seq_disk_cache_create_version_file(path_version_file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seq_disk_cache_delete_invalid_files(SeqDiskCache *disk_cache,
|
|
|
|
Scene *scene,
|
|
|
|
Sequence *seq,
|
|
|
|
int invalidate_types,
|
|
|
|
int range_start,
|
|
|
|
int range_end)
|
|
|
|
{
|
|
|
|
DiskCacheFile *next_file, *cache_file = disk_cache->files.first;
|
|
|
|
char cache_dir[FILE_MAX];
|
|
|
|
seq_disk_cache_get_dir(disk_cache, scene, seq, cache_dir, sizeof(cache_dir));
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_slash_ensure(cache_dir);
|
2020-03-19 00:05:18 +01:00
|
|
|
|
|
|
|
while (cache_file) {
|
|
|
|
next_file = cache_file->next;
|
|
|
|
if (cache_file->cache_type & invalidate_types) {
|
|
|
|
if (strcmp(cache_dir, cache_file->dir) == 0) {
|
|
|
|
int cfra_start = seq_cache_frame_index_to_cfra(seq, cache_file->start_frame);
|
|
|
|
if (cfra_start > range_start && cfra_start <= range_end) {
|
|
|
|
seq_disk_cache_delete_file(disk_cache, cache_file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cache_file = next_file;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seq_disk_cache_invalidate(Scene *scene,
|
|
|
|
Sequence *seq,
|
|
|
|
Sequence *seq_changed,
|
|
|
|
int invalidate_types)
|
|
|
|
{
|
|
|
|
int start;
|
|
|
|
int end;
|
|
|
|
SeqDiskCache *disk_cache = scene->ed->cache->disk_cache;
|
|
|
|
|
|
|
|
BLI_mutex_lock(&disk_cache->read_write_mutex);
|
|
|
|
|
|
|
|
start = seq_changed->startdisp - DCACHE_IMAGES_PER_FILE;
|
|
|
|
end = seq_changed->enddisp;
|
|
|
|
|
|
|
|
seq_disk_cache_delete_invalid_files(disk_cache, scene, seq, invalidate_types, start, end);
|
|
|
|
|
|
|
|
BLI_mutex_unlock(&disk_cache->read_write_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t deflate_imbuf_to_file(ImBuf *ibuf,
|
|
|
|
FILE *file,
|
|
|
|
int level,
|
|
|
|
DiskCacheHeaderEntry *header_entry)
|
|
|
|
{
|
|
|
|
if (ibuf->rect) {
|
|
|
|
return BLI_gzip_mem_to_file_at_pos(
|
|
|
|
ibuf->rect, header_entry->size_raw, file, header_entry->offset, level);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return BLI_gzip_mem_to_file_at_pos(
|
|
|
|
ibuf->rect_float, header_entry->size_raw, file, header_entry->offset, level);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t inflate_file_to_imbuf(ImBuf *ibuf, FILE *file, DiskCacheHeaderEntry *header_entry)
|
|
|
|
{
|
|
|
|
if (ibuf->rect) {
|
|
|
|
return BLI_ungzip_file_to_mem_at_pos(
|
|
|
|
ibuf->rect, header_entry->size_raw, file, header_entry->offset);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return BLI_ungzip_file_to_mem_at_pos(
|
|
|
|
ibuf->rect_float, header_entry->size_raw, file, header_entry->offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seq_disk_cache_read_header(FILE *file, DiskCacheHeader *header)
|
|
|
|
{
|
|
|
|
fseek(file, 0, 0);
|
|
|
|
fread(header, sizeof(*header), 1, file);
|
|
|
|
|
|
|
|
for (int i = 0; i < DCACHE_IMAGES_PER_FILE; i++) {
|
|
|
|
if ((ENDIAN_ORDER == B_ENDIAN) && header->entry[i].encoding == 0) {
|
|
|
|
BLI_endian_switch_uint64(&header->entry[i].frameno);
|
|
|
|
BLI_endian_switch_uint64(&header->entry[i].offset);
|
|
|
|
BLI_endian_switch_uint64(&header->entry[i].size_compressed);
|
|
|
|
BLI_endian_switch_uint64(&header->entry[i].size_raw);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t seq_disk_cache_write_header(FILE *file, DiskCacheHeader *header)
|
|
|
|
{
|
|
|
|
fseek(file, 0, 0);
|
|
|
|
return fwrite(header, sizeof(*header), 1, file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int seq_disk_cache_add_header_entry(SeqCacheKey *key, ImBuf *ibuf, DiskCacheHeader *header)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
uint64_t offset = sizeof(*header);
|
|
|
|
|
|
|
|
/* Lookup free entry, get offset for new data. */
|
|
|
|
for (i = 0; i < DCACHE_IMAGES_PER_FILE; i++) {
|
|
|
|
if (header->entry[i].size_compressed == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Attempt to write beyond set entry limit.
|
|
|
|
* Reset file header and start writing from beginning.
|
|
|
|
*/
|
|
|
|
if (i == DCACHE_IMAGES_PER_FILE) {
|
|
|
|
i = 0;
|
|
|
|
memset(header, 0, sizeof(*header));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate offset for image data. */
|
|
|
|
if (i > 0) {
|
|
|
|
offset = header->entry[i - 1].offset + header->entry[i - 1].size_compressed;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ENDIAN_ORDER == B_ENDIAN) {
|
|
|
|
header->entry[i].encoding = 255;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
header->entry[i].encoding = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
header->entry[i].offset = offset;
|
|
|
|
header->entry[i].frameno = key->nfra;
|
|
|
|
|
|
|
|
/* Store colorspace name of ibuf. */
|
|
|
|
const char *colorspace_name;
|
|
|
|
if (ibuf->rect) {
|
|
|
|
header->entry[i].size_raw = ibuf->x * ibuf->y * ibuf->channels;
|
|
|
|
colorspace_name = IMB_colormanagement_get_rect_colorspace(ibuf);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
header->entry[i].size_raw = ibuf->x * ibuf->y * ibuf->channels * 4;
|
|
|
|
colorspace_name = IMB_colormanagement_get_float_colorspace(ibuf);
|
|
|
|
}
|
|
|
|
BLI_strncpy(
|
|
|
|
header->entry[i].colorspace_name, colorspace_name, sizeof(header->entry[i].colorspace_name));
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int seq_disk_cache_get_header_entry(SeqCacheKey *key, DiskCacheHeader *header)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < DCACHE_IMAGES_PER_FILE; i++) {
|
|
|
|
if (header->entry[i].frameno == key->nfra) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool seq_disk_cache_write_file(SeqDiskCache *disk_cache, SeqCacheKey *key, ImBuf *ibuf)
|
|
|
|
{
|
|
|
|
char path[FILE_MAX];
|
|
|
|
|
|
|
|
seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path));
|
|
|
|
BLI_make_existing_file(path);
|
|
|
|
|
|
|
|
FILE *file = BLI_fopen(path, "rb+");
|
|
|
|
if (!file) {
|
|
|
|
file = BLI_fopen(path, "wb+");
|
|
|
|
if (!file) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
seq_disk_cache_add_file_to_list(disk_cache, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
DiskCacheHeader header;
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
|
|
seq_disk_cache_read_header(file, &header);
|
|
|
|
int entry_index = seq_disk_cache_add_header_entry(key, ibuf, &header);
|
|
|
|
size_t bytes_written = deflate_imbuf_to_file(
|
|
|
|
ibuf, file, seq_disk_cache_compression_level(), &header.entry[entry_index]);
|
|
|
|
|
|
|
|
if (bytes_written != 0) {
|
|
|
|
/* Last step is writing header, as image data can be overwritten,
|
|
|
|
* but missing data would cause problems.
|
|
|
|
*/
|
|
|
|
header.entry[entry_index].size_compressed = bytes_written;
|
|
|
|
seq_disk_cache_write_header(file, &header);
|
|
|
|
seq_disk_cache_update_file(disk_cache, path);
|
|
|
|
fclose(file);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ImBuf *seq_disk_cache_read_file(SeqDiskCache *disk_cache, SeqCacheKey *key)
|
|
|
|
{
|
|
|
|
char path[FILE_MAX];
|
|
|
|
DiskCacheHeader header;
|
|
|
|
|
|
|
|
seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path));
|
|
|
|
BLI_make_existing_file(path);
|
|
|
|
|
|
|
|
FILE *file = BLI_fopen(path, "rb");
|
|
|
|
if (!file) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
seq_disk_cache_read_header(file, &header);
|
|
|
|
int entry_index = seq_disk_cache_get_header_entry(key, &header);
|
|
|
|
|
|
|
|
/* Item not found. */
|
|
|
|
if (entry_index < 0) {
|
|
|
|
fclose(file);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImBuf *ibuf;
|
|
|
|
uint64_t size_char = (uint64_t)key->context.rectx * key->context.recty * 4;
|
|
|
|
uint64_t size_float = (uint64_t)key->context.rectx * key->context.recty * 16;
|
|
|
|
size_t expected_size;
|
|
|
|
|
|
|
|
if (header.entry[entry_index].size_raw == size_char) {
|
|
|
|
expected_size = size_char;
|
|
|
|
ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rect);
|
|
|
|
IMB_colormanagement_assign_rect_colorspace(ibuf, header.entry[entry_index].colorspace_name);
|
|
|
|
}
|
|
|
|
else if (header.entry[entry_index].size_raw == size_float) {
|
|
|
|
expected_size = size_float;
|
|
|
|
ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rectfloat);
|
|
|
|
IMB_colormanagement_assign_float_colorspace(ibuf, header.entry[entry_index].colorspace_name);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fclose(file);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t bytes_read = inflate_file_to_imbuf(ibuf, file, &header.entry[entry_index]);
|
|
|
|
|
|
|
|
/* Sanity check. */
|
|
|
|
if (bytes_read != expected_size) {
|
|
|
|
fclose(file);
|
|
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
BLI_file_touch(path);
|
|
|
|
seq_disk_cache_update_file(disk_cache, path);
|
|
|
|
fclose(file);
|
|
|
|
|
|
|
|
return ibuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef DCACHE_FNAME_FORMAT
|
|
|
|
#undef DCACHE_IMAGES_PER_FILE
|
|
|
|
#undef COLORSPACE_NAME_MAX
|
|
|
|
#undef DCACHE_CURRENT_VERSION
|
2011-10-23 17:52:20 +00:00
|
|
|
|
2014-09-25 06:15:52 +10:00
|
|
|
static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
|
2012-08-08 11:15:32 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
return ((a->preview_render_size != b->preview_render_size) || (a->rectx != b->rectx) ||
|
|
|
|
(a->recty != b->recty) || (a->bmain != b->bmain) || (a->scene != b->scene) ||
|
|
|
|
(a->motion_blur_shutter != b->motion_blur_shutter) ||
|
|
|
|
(a->motion_blur_samples != b->motion_blur_samples) ||
|
|
|
|
(a->scene->r.views_format != b->scene->r.views_format) || (a->view_id != b->view_id));
|
2012-08-08 11:15:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int seq_hash_render_data(const SeqRenderData *a)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
unsigned int rval = a->rectx + a->recty;
|
2012-08-08 11:15:32 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
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 << 16;
|
|
|
|
rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 24;
|
2012-08-08 11:15:32 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return rval;
|
2012-08-08 11:15:32 +00:00
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
static unsigned int seq_cache_hashhash(const void *key_)
|
2010-07-23 16:57:11 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
const SeqCacheKey *key = key_;
|
|
|
|
unsigned int rval = seq_hash_render_data(&key->context);
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
rval ^= *(const unsigned int *)&key->nfra;
|
2019-04-17 06:17:24 +02:00
|
|
|
rval += key->type;
|
|
|
|
rval ^= ((intptr_t)key->seq) << 6;
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return rval;
|
2010-07-23 16:57:11 +00:00
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
static bool seq_cache_hashcmp(const void *a_, const void *b_)
|
2010-07-23 16:57:11 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
const SeqCacheKey *a = a_;
|
|
|
|
const SeqCacheKey *b = b_;
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
return ((a->seq != b->seq) || (a->nfra != b->nfra) || (a->type != b->type) ||
|
2019-04-17 06:17:24 +02:00
|
|
|
seq_cmp_render_data(&a->context, &b->context));
|
2010-07-23 16:57:11 +00:00
|
|
|
}
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
static float seq_cache_cfra_to_frame_index(Sequence *seq, float cfra)
|
|
|
|
{
|
|
|
|
return cfra - seq->start;
|
|
|
|
}
|
|
|
|
|
|
|
|
static float seq_cache_frame_index_to_cfra(Sequence *seq, float nfra)
|
|
|
|
{
|
|
|
|
return nfra + seq->start;
|
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
static SeqCache *seq_cache_get_from_scene(Scene *scene)
|
2010-07-23 16:57:11 +00:00
|
|
|
{
|
2019-04-28 14:13:41 -07:00
|
|
|
if (scene && scene->ed && scene->ed->cache) {
|
|
|
|
return scene->ed->cache;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seq_cache_lock(Scene *scene)
|
|
|
|
{
|
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
|
|
|
|
if (cache) {
|
|
|
|
BLI_mutex_lock(&cache->iterator_mutex);
|
|
|
|
}
|
2010-07-23 16:57:11 +00:00
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
static void seq_cache_unlock(Scene *scene)
|
2010-07-23 16:57:11 +00:00
|
|
|
{
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
|
|
|
|
if (cache) {
|
|
|
|
BLI_mutex_unlock(&cache->iterator_mutex);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-04-28 14:13:41 -07:00
|
|
|
}
|
2012-08-20 15:14:23 +00:00
|
|
|
|
2019-09-13 17:21:54 -07:00
|
|
|
static size_t seq_cache_get_mem_total(void)
|
|
|
|
{
|
|
|
|
return ((size_t)U.memcachelimit) * 1024 * 1024;
|
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
static void seq_cache_keyfree(void *val)
|
|
|
|
{
|
|
|
|
SeqCacheKey *key = val;
|
|
|
|
BLI_mempool_free(key->cache_owner->keys_pool, key);
|
2010-07-23 16:57:11 +00:00
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
static void seq_cache_valfree(void *val)
|
2012-08-08 16:46:40 +00:00
|
|
|
{
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCacheItem *item = (SeqCacheItem *)val;
|
|
|
|
SeqCache *cache = item->cache_owner;
|
|
|
|
|
|
|
|
if (item->ibuf) {
|
|
|
|
cache->memory_used -= IMB_get_size_in_memory(item->ibuf);
|
|
|
|
IMB_freeImBuf(item->ibuf);
|
|
|
|
}
|
2012-08-08 16:46:40 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
BLI_mempool_free(item->cache_owner->items_pool, item);
|
2012-08-08 16:46:40 +00:00
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
static void seq_cache_put(SeqCache *cache, SeqCacheKey *key, ImBuf *ibuf)
|
2012-08-08 16:46:40 +00:00
|
|
|
{
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCacheItem *item;
|
|
|
|
item = BLI_mempool_alloc(cache->items_pool);
|
|
|
|
item->cache_owner = cache;
|
|
|
|
item->ibuf = ibuf;
|
|
|
|
|
|
|
|
if (BLI_ghash_reinsert(cache->hash, key, item, seq_cache_keyfree, seq_cache_valfree)) {
|
|
|
|
IMB_refImBuf(ibuf);
|
|
|
|
cache->last_key = key;
|
|
|
|
cache->memory_used += IMB_get_size_in_memory(ibuf);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-08-08 16:46:40 +00:00
|
|
|
}
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
static ImBuf *seq_cache_get(SeqCache *cache, SeqCacheKey *key)
|
2010-07-23 16:57:11 +00:00
|
|
|
{
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCacheItem *item = BLI_ghash_lookup(cache->hash, key);
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
if (item && item->ibuf) {
|
|
|
|
IMB_refImBuf(item->ibuf);
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
return item->ibuf;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2011-10-23 17:52:20 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return NULL;
|
2010-07-23 16:57:11 +00:00
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
static void seq_cache_relink_keys(SeqCacheKey *link_next, SeqCacheKey *link_prev)
|
|
|
|
{
|
|
|
|
if (link_next) {
|
|
|
|
link_next->link_prev = link_prev;
|
|
|
|
}
|
|
|
|
if (link_prev) {
|
|
|
|
link_prev->link_next = link_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-13 17:21:54 -07:00
|
|
|
/* Choose a key out of 2 candidates(leftmost and rightmost items)
|
|
|
|
* to recycle based on currently used strategy */
|
2019-04-28 14:13:41 -07:00
|
|
|
static SeqCacheKey *seq_cache_choose_key(Scene *scene, SeqCacheKey *lkey, SeqCacheKey *rkey)
|
2010-07-23 16:57:11 +00:00
|
|
|
{
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCacheKey *finalkey = NULL;
|
|
|
|
|
2019-09-13 17:21:54 -07:00
|
|
|
/* Ideally, cache would not need to check the state of prefetching task
|
|
|
|
* that is tricky to do however, because prefetch would need to know,
|
|
|
|
* if a key, that is about to be created would be removed by itself.
|
|
|
|
*
|
|
|
|
* This can happen because only FINAL_OUT item insertion will trigger recycling
|
|
|
|
* but that is also the point, where prefetch can be suspended.
|
|
|
|
*
|
2019-09-30 17:06:28 +10:00
|
|
|
* We could use temp cache as a shield and later make it a non-temporary entry,
|
2019-09-13 17:21:54 -07:00
|
|
|
* but it is not worth of increasing system complexity.
|
|
|
|
*/
|
2019-10-02 13:04:48 -07:00
|
|
|
if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE &&
|
|
|
|
BKE_sequencer_prefetch_job_is_running(scene)) {
|
2019-09-13 17:21:54 -07:00
|
|
|
int pfjob_start, pfjob_end;
|
|
|
|
BKE_sequencer_prefetch_get_time_range(scene, &pfjob_start, &pfjob_end);
|
|
|
|
|
|
|
|
if (lkey) {
|
2020-03-19 00:05:18 +01:00
|
|
|
int lkey_cfra = seq_cache_frame_index_to_cfra(lkey->seq, lkey->nfra);
|
2019-09-13 17:21:54 -07:00
|
|
|
if (lkey_cfra < pfjob_start || lkey_cfra > pfjob_end) {
|
|
|
|
return lkey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rkey) {
|
2020-03-19 00:05:18 +01:00
|
|
|
int rkey_cfra = seq_cache_frame_index_to_cfra(rkey->seq, rkey->nfra);
|
2019-09-13 17:21:54 -07:00
|
|
|
if (rkey_cfra < pfjob_start || rkey_cfra > pfjob_end) {
|
|
|
|
return rkey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
if (rkey && lkey) {
|
2020-03-19 00:05:18 +01:00
|
|
|
int lkey_cfra = seq_cache_frame_index_to_cfra(lkey->seq, lkey->nfra);
|
|
|
|
int rkey_cfra = seq_cache_frame_index_to_cfra(rkey->seq, rkey->nfra);
|
2019-05-21 12:29:17 -07:00
|
|
|
|
|
|
|
if (lkey_cfra > rkey_cfra) {
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCacheKey *swapkey = lkey;
|
|
|
|
lkey = rkey;
|
|
|
|
rkey = swapkey;
|
|
|
|
}
|
|
|
|
|
2019-05-21 12:29:17 -07:00
|
|
|
int l_diff = scene->r.cfra - lkey_cfra;
|
|
|
|
int r_diff = rkey_cfra - scene->r.cfra;
|
2019-04-28 14:13:41 -07:00
|
|
|
|
|
|
|
if (l_diff > r_diff) {
|
|
|
|
finalkey = lkey;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
finalkey = rkey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (lkey) {
|
|
|
|
finalkey = lkey;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
finalkey = rkey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return finalkey;
|
|
|
|
}
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
static void seq_cache_recycle_linked(Scene *scene, SeqCacheKey *base)
|
|
|
|
{
|
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
if (!cache) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return;
|
|
|
|
}
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCacheKey *next = base->link_next;
|
|
|
|
|
|
|
|
while (base) {
|
|
|
|
SeqCacheKey *prev = base->link_prev;
|
|
|
|
BLI_ghash_remove(cache->hash, base, seq_cache_keyfree, seq_cache_valfree);
|
|
|
|
base = prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
base = next;
|
|
|
|
while (base) {
|
|
|
|
next = base->link_next;
|
|
|
|
BLI_ghash_remove(cache->hash, base, seq_cache_keyfree, seq_cache_valfree);
|
|
|
|
base = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-14 16:54:59 +02:00
|
|
|
static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene)
|
2019-04-28 14:13:41 -07:00
|
|
|
{
|
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
SeqCacheKey *finalkey = NULL;
|
2020-03-19 00:05:18 +01:00
|
|
|
/* Leftmost key. */
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCacheKey *lkey = NULL;
|
2020-03-19 00:05:18 +01:00
|
|
|
/* Rightmost key. */
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCacheKey *rkey = NULL;
|
|
|
|
SeqCacheKey *key = NULL;
|
|
|
|
|
|
|
|
GHashIterator gh_iter;
|
|
|
|
BLI_ghashIterator_init(&gh_iter, cache->hash);
|
|
|
|
int total_count = 0;
|
|
|
|
int cheap_count = 0;
|
|
|
|
|
|
|
|
while (!BLI_ghashIterator_done(&gh_iter)) {
|
|
|
|
key = BLI_ghashIterator_getKey(&gh_iter);
|
|
|
|
SeqCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
|
|
|
|
BLI_ghashIterator_step(&gh_iter);
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
/* This shouldn't happen, but better be safe than sorry. */
|
2019-04-28 14:13:41 -07:00
|
|
|
if (!item->ibuf) {
|
|
|
|
seq_cache_recycle_linked(scene, key);
|
2020-03-19 00:05:18 +01:00
|
|
|
/* Can not continue iterating after linked remove. */
|
2019-04-28 14:13:41 -07:00
|
|
|
BLI_ghashIterator_init(&gh_iter, cache->hash);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->is_temp_cache || key->link_next != NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
total_count++;
|
|
|
|
|
|
|
|
if (key->cost <= scene->ed->recycle_max_cost) {
|
|
|
|
cheap_count++;
|
|
|
|
if (lkey) {
|
2020-03-19 00:05:18 +01:00
|
|
|
if (seq_cache_frame_index_to_cfra(key->seq, key->nfra) <
|
|
|
|
seq_cache_frame_index_to_cfra(lkey->seq, lkey->nfra)) {
|
2019-04-28 14:13:41 -07:00
|
|
|
lkey = key;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lkey = key;
|
|
|
|
}
|
|
|
|
if (rkey) {
|
2020-03-19 00:05:18 +01:00
|
|
|
if (seq_cache_frame_index_to_cfra(key->seq, key->nfra) >
|
|
|
|
seq_cache_frame_index_to_cfra(rkey->seq, rkey->nfra)) {
|
2019-04-28 14:13:41 -07:00
|
|
|
rkey = key;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rkey = key;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
finalkey = seq_cache_choose_key(scene, lkey, rkey);
|
2019-09-13 17:21:54 -07:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
return finalkey;
|
|
|
|
}
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
/* Find only "base" keys.
|
|
|
|
* Sources(other types) for a frame must be freed all at once.
|
2019-04-28 14:13:41 -07:00
|
|
|
*/
|
2019-09-13 17:21:54 -07:00
|
|
|
bool BKE_sequencer_cache_recycle_item(Scene *scene)
|
2019-04-28 14:13:41 -07:00
|
|
|
{
|
2019-09-13 17:21:54 -07:00
|
|
|
size_t memory_total = seq_cache_get_mem_total();
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
if (!cache) {
|
|
|
|
return false;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
seq_cache_lock(scene);
|
|
|
|
|
|
|
|
while (cache->memory_used > memory_total) {
|
|
|
|
SeqCacheKey *finalkey = seq_cache_get_item_for_removal(scene);
|
2010-07-23 16:57:11 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
if (finalkey) {
|
|
|
|
seq_cache_recycle_linked(scene, finalkey);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
seq_cache_unlock(scene);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
seq_cache_unlock(scene);
|
|
|
|
return true;
|
2010-07-23 16:57:11 +00:00
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
static void seq_cache_set_temp_cache_linked(Scene *scene, SeqCacheKey *base)
|
2012-08-19 15:41:56 +00:00
|
|
|
{
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
if (!cache || !base) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCacheKey *next = base->link_next;
|
|
|
|
|
|
|
|
while (base) {
|
|
|
|
SeqCacheKey *prev = base->link_prev;
|
|
|
|
base->is_temp_cache = true;
|
|
|
|
base = prev;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
base = next;
|
|
|
|
while (base) {
|
|
|
|
next = base->link_next;
|
|
|
|
base->is_temp_cache = true;
|
|
|
|
base = next;
|
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
}
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
static void seq_disk_cache_create(Main *bmain, Scene *scene)
|
|
|
|
{
|
|
|
|
BLI_mutex_lock(&cache_create_lock);
|
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
|
|
|
|
if (cache == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cache->disk_cache != NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cache->disk_cache = MEM_callocN(sizeof(SeqDiskCache), "SeqDiskCache");
|
|
|
|
cache->disk_cache->bmain = bmain;
|
|
|
|
BLI_mutex_init(&cache->disk_cache->read_write_mutex);
|
|
|
|
seq_disk_cache_handle_versioning(cache->disk_cache);
|
|
|
|
seq_disk_cache_get_files(cache->disk_cache, seq_disk_cache_base_dir());
|
|
|
|
cache->disk_cache->timestamp = scene->ed->disk_cache_timestamp;
|
|
|
|
BLI_mutex_unlock(&cache_create_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seq_cache_create(Main *bmain, Scene *scene)
|
2012-08-19 15:41:56 +00:00
|
|
|
{
|
2019-04-28 14:13:41 -07:00
|
|
|
BLI_mutex_lock(&cache_create_lock);
|
|
|
|
if (scene->ed->cache == NULL) {
|
|
|
|
SeqCache *cache = MEM_callocN(sizeof(SeqCache), "SeqCache");
|
|
|
|
cache->keys_pool = BLI_mempool_create(sizeof(SeqCacheKey), 0, 64, BLI_MEMPOOL_NOP);
|
|
|
|
cache->items_pool = BLI_mempool_create(sizeof(SeqCacheItem), 0, 64, BLI_MEMPOOL_NOP);
|
|
|
|
cache->hash = BLI_ghash_new(seq_cache_hashhash, seq_cache_hashcmp, "SeqCache hash");
|
|
|
|
cache->last_key = NULL;
|
2020-03-19 00:05:18 +01:00
|
|
|
cache->bmain = bmain;
|
2019-04-28 14:13:41 -07:00
|
|
|
BLI_mutex_init(&cache->iterator_mutex);
|
|
|
|
scene->ed->cache = cache;
|
2020-03-19 00:05:18 +01:00
|
|
|
|
|
|
|
if (scene->ed->disk_cache_timestamp == 0) {
|
|
|
|
scene->ed->disk_cache_timestamp = time(NULL);
|
|
|
|
}
|
2019-04-28 14:13:41 -07:00
|
|
|
}
|
|
|
|
BLI_mutex_unlock(&cache_create_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ***************************** API ****************************** */
|
|
|
|
|
|
|
|
void BKE_sequencer_cache_free_temp_cache(Scene *scene, short id, int cfra)
|
|
|
|
{
|
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
if (!cache) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
seq_cache_lock(scene);
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
GHashIterator gh_iter;
|
|
|
|
BLI_ghashIterator_init(&gh_iter, cache->hash);
|
|
|
|
while (!BLI_ghashIterator_done(&gh_iter)) {
|
|
|
|
SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
|
|
|
|
BLI_ghashIterator_step(&gh_iter);
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
if (key->is_temp_cache && key->task_id == id &&
|
|
|
|
seq_cache_frame_index_to_cfra(key->seq, key->nfra) != cfra) {
|
2019-04-28 14:13:41 -07:00
|
|
|
BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
seq_cache_unlock(scene);
|
2012-08-19 15:41:56 +00:00
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
void BKE_sequencer_cache_destruct(Scene *scene)
|
2012-08-19 15:41:56 +00:00
|
|
|
{
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
if (!cache) {
|
|
|
|
return;
|
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
BLI_ghash_free(cache->hash, seq_cache_keyfree, seq_cache_valfree);
|
|
|
|
BLI_mempool_destroy(cache->keys_pool);
|
|
|
|
BLI_mempool_destroy(cache->items_pool);
|
|
|
|
BLI_mutex_end(&cache->iterator_mutex);
|
2020-03-19 00:05:18 +01:00
|
|
|
|
|
|
|
if (cache->disk_cache != NULL) {
|
|
|
|
BLI_freelistN(&cache->disk_cache->files);
|
|
|
|
BLI_mutex_end(&cache->disk_cache->read_write_mutex);
|
|
|
|
MEM_freeN(cache->disk_cache);
|
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
MEM_freeN(cache);
|
|
|
|
scene->ed->cache = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BKE_sequencer_cache_cleanup_all(Main *bmain)
|
|
|
|
{
|
|
|
|
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
|
|
|
|
BKE_sequencer_cache_cleanup(scene);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void BKE_sequencer_cache_cleanup(Scene *scene)
|
|
|
|
{
|
2019-09-13 17:21:54 -07:00
|
|
|
BKE_sequencer_prefetch_stop(scene);
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
if (!cache) {
|
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
seq_cache_lock(scene);
|
|
|
|
|
|
|
|
GHashIterator gh_iter;
|
|
|
|
BLI_ghashIterator_init(&gh_iter, cache->hash);
|
|
|
|
while (!BLI_ghashIterator_done(&gh_iter)) {
|
|
|
|
SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
|
|
|
|
|
|
|
|
BLI_ghashIterator_step(&gh_iter);
|
|
|
|
BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-28 14:13:41 -07:00
|
|
|
cache->last_key = NULL;
|
|
|
|
seq_cache_unlock(scene);
|
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-05-23 11:52:28 -07:00
|
|
|
void BKE_sequencer_cache_cleanup_sequence(Scene *scene,
|
|
|
|
Sequence *seq,
|
|
|
|
Sequence *seq_changed,
|
2020-04-12 22:42:31 +02:00
|
|
|
int invalidate_types,
|
|
|
|
bool force_seq_changed_range)
|
2019-04-28 14:13:41 -07:00
|
|
|
{
|
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
if (!cache) {
|
|
|
|
return;
|
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
if (seq_disk_cache_is_enabled(cache->bmain) && cache->disk_cache != NULL) {
|
|
|
|
seq_disk_cache_invalidate(scene, seq, seq_changed, invalidate_types);
|
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
seq_cache_lock(scene);
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-05-23 11:52:28 -07:00
|
|
|
int range_start = seq_changed->startdisp;
|
|
|
|
int range_end = seq_changed->enddisp;
|
|
|
|
|
2020-04-12 22:42:31 +02:00
|
|
|
if (!force_seq_changed_range) {
|
|
|
|
if (seq->startdisp > range_start) {
|
|
|
|
range_start = seq->startdisp;
|
|
|
|
}
|
2019-05-23 11:52:28 -07:00
|
|
|
|
2020-04-12 22:42:31 +02:00
|
|
|
if (seq->enddisp < range_end) {
|
|
|
|
range_end = seq->enddisp;
|
|
|
|
}
|
2019-05-23 11:52:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int invalidate_composite = invalidate_types & SEQ_CACHE_STORE_FINAL_OUT;
|
|
|
|
int invalidate_source = invalidate_types & (SEQ_CACHE_STORE_RAW | SEQ_CACHE_STORE_PREPROCESSED |
|
|
|
|
SEQ_CACHE_STORE_COMPOSITE);
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
GHashIterator gh_iter;
|
|
|
|
BLI_ghashIterator_init(&gh_iter, cache->hash);
|
|
|
|
while (!BLI_ghashIterator_done(&gh_iter)) {
|
|
|
|
SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
|
|
|
|
BLI_ghashIterator_step(&gh_iter);
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
int key_cfra = seq_cache_frame_index_to_cfra(key->seq, key->nfra);
|
2019-05-23 11:52:28 -07:00
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
/* Clean all final and composite in intersection of seq and seq_changed. */
|
2019-05-23 11:52:28 -07:00
|
|
|
if (key->type & invalidate_composite && key_cfra >= range_start && key_cfra <= range_end) {
|
|
|
|
if (key->link_next || key->link_prev) {
|
|
|
|
seq_cache_relink_keys(key->link_next, key->link_prev);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key->type & invalidate_source && key->seq == seq && key_cfra >= seq_changed->startdisp &&
|
|
|
|
key_cfra <= seq_changed->enddisp) {
|
2019-04-28 14:13:41 -07:00
|
|
|
if (key->link_next || key->link_prev) {
|
|
|
|
seq_cache_relink_keys(key->link_next, key->link_prev);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-28 14:13:41 -07:00
|
|
|
}
|
|
|
|
cache->last_key = NULL;
|
|
|
|
seq_cache_unlock(scene);
|
|
|
|
}
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
struct ImBuf *BKE_sequencer_cache_get(
|
|
|
|
const SeqRenderData *context, Sequence *seq, float cfra, int type, bool skip_disk_cache)
|
2019-04-28 14:13:41 -07:00
|
|
|
{
|
|
|
|
Scene *scene = context->scene;
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-09-13 17:21:54 -07:00
|
|
|
if (context->is_prefetch_render) {
|
|
|
|
context = BKE_sequencer_prefetch_get_original_context(context);
|
|
|
|
scene = context->scene;
|
|
|
|
seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
|
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
if (!scene->ed->cache) {
|
2020-03-19 00:05:18 +01:00
|
|
|
seq_cache_create(context->bmain, scene);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
seq_cache_lock(scene);
|
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
ImBuf *ibuf = NULL;
|
2020-03-19 00:05:18 +01:00
|
|
|
SeqCacheKey key;
|
2019-04-28 14:13:41 -07:00
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
/* Try RAM cache: */
|
2019-04-28 14:13:41 -07:00
|
|
|
if (cache && seq) {
|
|
|
|
key.seq = seq;
|
|
|
|
key.context = *context;
|
2020-03-19 00:05:18 +01:00
|
|
|
key.nfra = seq_cache_cfra_to_frame_index(seq, cfra);
|
2019-04-28 14:13:41 -07:00
|
|
|
key.type = type;
|
|
|
|
|
|
|
|
ibuf = seq_cache_get(cache, &key);
|
|
|
|
}
|
|
|
|
seq_cache_unlock(scene);
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
if (ibuf) {
|
|
|
|
return ibuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try disk cache: */
|
|
|
|
if (!skip_disk_cache && seq_disk_cache_is_enabled(context->bmain)) {
|
|
|
|
if (cache->disk_cache == NULL) {
|
|
|
|
seq_disk_cache_create(context->bmain, context->scene);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_mutex_lock(&cache->disk_cache->read_write_mutex);
|
|
|
|
ibuf = seq_disk_cache_read_file(cache->disk_cache, &key);
|
|
|
|
BLI_mutex_unlock(&cache->disk_cache->read_write_mutex);
|
|
|
|
if (ibuf) {
|
|
|
|
if (key.type == SEQ_CACHE_STORE_FINAL_OUT) {
|
|
|
|
BKE_sequencer_cache_put_if_possible(context, seq, cfra, type, ibuf, 0.0f, true);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BKE_sequencer_cache_put(context, seq, cfra, type, ibuf, 0.0f, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
return ibuf;
|
2012-08-19 15:41:56 +00:00
|
|
|
}
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context,
|
|
|
|
Sequence *seq,
|
|
|
|
float cfra,
|
|
|
|
int type,
|
|
|
|
ImBuf *ibuf,
|
|
|
|
float cost,
|
|
|
|
bool skip_disk_cache)
|
2012-08-19 15:41:56 +00:00
|
|
|
{
|
2019-04-28 14:13:41 -07:00
|
|
|
Scene *scene = context->scene;
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-09-13 17:21:54 -07:00
|
|
|
if (context->is_prefetch_render) {
|
|
|
|
context = BKE_sequencer_prefetch_get_original_context(context);
|
|
|
|
scene = context->scene;
|
|
|
|
seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (BKE_sequencer_cache_recycle_item(scene)) {
|
2020-03-19 00:05:18 +01:00
|
|
|
BKE_sequencer_cache_put(context, seq, cfra, type, ibuf, cost, skip_disk_cache);
|
2019-04-28 14:13:41 -07:00
|
|
|
return true;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else {
|
2019-04-28 14:13:41 -07:00
|
|
|
seq_cache_set_temp_cache_linked(scene, scene->ed->cache->last_key);
|
|
|
|
scene->ed->cache->last_key = NULL;
|
|
|
|
return false;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-04-28 14:13:41 -07:00
|
|
|
}
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
void BKE_sequencer_cache_put(const SeqRenderData *context,
|
|
|
|
Sequence *seq,
|
|
|
|
float cfra,
|
|
|
|
int type,
|
|
|
|
ImBuf *i,
|
|
|
|
float cost,
|
|
|
|
bool skip_disk_cache)
|
2019-04-28 14:13:41 -07:00
|
|
|
{
|
|
|
|
Scene *scene = context->scene;
|
2019-09-13 17:21:54 -07:00
|
|
|
|
|
|
|
if (context->is_prefetch_render) {
|
|
|
|
context = BKE_sequencer_prefetch_get_original_context(context);
|
|
|
|
scene = context->scene;
|
|
|
|
seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
|
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) {
|
|
|
|
return;
|
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
/* Prevent reinserting, it breaks cache key linking. */
|
|
|
|
ImBuf *test = BKE_sequencer_cache_get(context, seq, cfra, type, true);
|
2019-04-28 14:13:41 -07:00
|
|
|
if (test) {
|
|
|
|
IMB_freeImBuf(test);
|
|
|
|
return;
|
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
if (!scene->ed->cache) {
|
2020-03-19 00:05:18 +01:00
|
|
|
seq_cache_create(context->bmain, scene);
|
2019-04-28 14:13:41 -07:00
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
seq_cache_lock(scene);
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
int flag;
|
|
|
|
|
|
|
|
if (seq->cache_flag & SEQ_CACHE_OVERRIDE) {
|
|
|
|
flag = seq->cache_flag;
|
2020-03-19 00:05:18 +01:00
|
|
|
/* Final_out is invalid in context of sequence override. */
|
|
|
|
flag -= seq->cache_flag & SEQ_CACHE_STORE_FINAL_OUT;
|
|
|
|
/* If global setting is enabled however, use it. */
|
2019-04-28 14:13:41 -07:00
|
|
|
flag |= scene->ed->cache_flag & SEQ_CACHE_STORE_FINAL_OUT;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
flag = scene->ed->cache_flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cost > SEQ_CACHE_COST_MAX) {
|
|
|
|
cost = SEQ_CACHE_COST_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
SeqCacheKey *key;
|
|
|
|
key = BLI_mempool_alloc(cache->keys_pool);
|
|
|
|
key->cache_owner = cache;
|
|
|
|
key->seq = seq;
|
|
|
|
key->context = *context;
|
2020-03-19 00:05:18 +01:00
|
|
|
key->nfra = seq_cache_cfra_to_frame_index(seq, cfra);
|
2019-04-28 14:13:41 -07:00
|
|
|
key->type = type;
|
|
|
|
key->cost = cost;
|
|
|
|
key->link_prev = NULL;
|
|
|
|
key->link_next = NULL;
|
|
|
|
key->is_temp_cache = true;
|
2019-09-13 17:21:54 -07:00
|
|
|
key->task_id = context->task_id;
|
2019-04-28 14:13:41 -07:00
|
|
|
|
|
|
|
/* Item stored for later use */
|
|
|
|
if (flag & type) {
|
|
|
|
key->is_temp_cache = false;
|
|
|
|
key->link_prev = cache->last_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
SeqCacheKey *temp_last_key = cache->last_key;
|
|
|
|
seq_cache_put(cache, key, i);
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
/* Restore pointer to previous item as this one will be freed when stack is rendered. */
|
2019-04-28 14:13:41 -07:00
|
|
|
if (key->is_temp_cache) {
|
|
|
|
cache->last_key = temp_last_key;
|
|
|
|
}
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
/* Set last_key's reference to this key so we can look up chain backwards.
|
|
|
|
* Item is already put in cache, so cache->last_key points to current key.
|
2019-05-01 11:09:22 +10:00
|
|
|
*/
|
2019-04-28 14:13:41 -07:00
|
|
|
if (flag & type && temp_last_key) {
|
|
|
|
temp_last_key->link_next = cache->last_key;
|
|
|
|
}
|
|
|
|
|
2020-03-19 00:05:18 +01:00
|
|
|
/* Reset linking. */
|
2019-04-28 14:13:41 -07:00
|
|
|
if (key->type == SEQ_CACHE_STORE_FINAL_OUT) {
|
|
|
|
cache->last_key = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
seq_cache_unlock(scene);
|
2020-03-19 00:05:18 +01:00
|
|
|
|
|
|
|
if (!key->is_temp_cache && !skip_disk_cache) {
|
|
|
|
if (seq_disk_cache_is_enabled(context->bmain)) {
|
|
|
|
if (cache->disk_cache == NULL) {
|
|
|
|
seq_disk_cache_create(context->bmain, context->scene);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_mutex_lock(&cache->disk_cache->read_write_mutex);
|
|
|
|
seq_disk_cache_write_file(cache->disk_cache, key, i);
|
|
|
|
BLI_mutex_unlock(&cache->disk_cache->read_write_mutex);
|
|
|
|
seq_disk_cache_enforce_limits(cache->disk_cache);
|
|
|
|
}
|
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
}
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
void BKE_sequencer_cache_iterate(
|
|
|
|
struct Scene *scene,
|
|
|
|
void *userdata,
|
2020-03-25 00:23:06 +01:00
|
|
|
bool callback_init(void *userdata, size_t item_count),
|
|
|
|
bool callback_iter(void *userdata, struct Sequence *seq, int nfra, int cache_type, float cost))
|
2012-08-19 15:41:56 +00:00
|
|
|
{
|
2019-04-28 14:13:41 -07:00
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
if (!cache) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
seq_cache_lock(scene);
|
2020-03-25 00:23:06 +01:00
|
|
|
bool interrupt = callback_init(userdata, BLI_ghash_len(cache->hash));
|
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
GHashIterator gh_iter;
|
|
|
|
BLI_ghashIterator_init(&gh_iter, cache->hash);
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2019-04-28 14:13:41 -07:00
|
|
|
while (!BLI_ghashIterator_done(&gh_iter) && !interrupt) {
|
|
|
|
SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
|
|
|
|
BLI_ghashIterator_step(&gh_iter);
|
2012-08-19 15:41:56 +00:00
|
|
|
|
2020-03-25 00:23:06 +01:00
|
|
|
interrupt = callback_iter(userdata, key->seq, key->nfra, key->type, key->cost);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-04-28 14:13:41 -07:00
|
|
|
|
|
|
|
cache->last_key = NULL;
|
|
|
|
seq_cache_unlock(scene);
|
2012-08-19 15:41:56 +00:00
|
|
|
}
|
2019-09-13 17:21:54 -07:00
|
|
|
|
|
|
|
bool BKE_sequencer_cache_is_full(Scene *scene)
|
|
|
|
{
|
|
|
|
size_t memory_total = seq_cache_get_mem_total();
|
|
|
|
SeqCache *cache = seq_cache_get_from_scene(scene);
|
|
|
|
if (!cache) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return memory_total < cache->memory_used;
|
|
|
|
}
|