Blender V5.0
cachefile.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2016 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstring>
10#include <optional>
11
12#include "DNA_cachefile_types.h"
13#include "DNA_object_types.h"
14#include "DNA_scene_types.h"
15
16#include "BLI_fileops.h"
17#include "BLI_ghash.h"
18#include "BLI_listbase.h"
19#include "BLI_mutex.hh"
20#include "BLI_path_utils.hh"
21#include "BLI_string.h"
22#include "BLI_utildefines.h"
23
24#include "BLT_translation.hh"
25
26#include "BKE_bpath.hh"
27#include "BKE_cachefile.hh"
28#include "BKE_idtype.hh"
29#include "BKE_lib_id.hh"
30#include "BKE_library.hh"
31#include "BKE_main.hh"
32#include "BKE_scene.hh"
33
35
36#include "RE_engine.h"
37
38#include "BLO_read_write.hh"
39
40#include "MEM_guardedalloc.h"
41
42#ifdef WITH_ALEMBIC
43# include "ABC_alembic.h"
44#endif
45
46#ifdef WITH_USD
47# include "usd.hh"
48#endif
49
50static void cachefile_handle_free(CacheFile *cache_file);
51
52static void cache_file_init_data(ID *id)
53{
54 CacheFile *cache_file = (CacheFile *)id;
55
57
58 cache_file->scale = 1.0f;
60 STRNCPY(cache_file->velocity_name, ".velocities");
61}
62
63static void cache_file_copy_data(Main * /*bmain*/,
64 std::optional<Library *> /*owner_library*/,
65 ID *id_dst,
66 const ID *id_src,
67 const int /*flag*/)
68{
69 CacheFile *cache_file_dst = (CacheFile *)id_dst;
70 const CacheFile *cache_file_src = (const CacheFile *)id_src;
71
72 cache_file_dst->handle = nullptr;
73 cache_file_dst->handle_readers = nullptr;
74 BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_src->object_paths);
75 BLI_duplicatelist(&cache_file_dst->layers, &cache_file_src->layers);
76}
77
78static void cache_file_free_data(ID *id)
79{
80 CacheFile *cache_file = (CacheFile *)id;
81 cachefile_handle_free(cache_file);
82 BLI_freelistN(&cache_file->object_paths);
83 BLI_freelistN(&cache_file->layers);
84}
85
86static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
87{
88 CacheFile *cache_file = (CacheFile *)id;
90 bpath_data, cache_file->filepath, sizeof(cache_file->filepath));
91}
92
93static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_address)
94{
95 CacheFile *cache_file = (CacheFile *)id;
96
97 /* Clean up, important in undo case to reduce false detection of changed datablocks. */
98 BLI_listbase_clear(&cache_file->object_paths);
99 cache_file->handle = nullptr;
100 memset(cache_file->handle_filepath, 0, sizeof(cache_file->handle_filepath));
101 cache_file->handle_readers = nullptr;
102
103 BLO_write_id_struct(writer, CacheFile, id_address, &cache_file->id);
104 BKE_id_blend_write(writer, &cache_file->id);
105
106 /* write layers */
107 LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) {
108 BLO_write_struct(writer, CacheFileLayer, layer);
109 }
110}
111
113{
114 CacheFile *cache_file = (CacheFile *)id;
115 BLI_listbase_clear(&cache_file->object_paths);
116 cache_file->handle = nullptr;
117 cache_file->handle_filepath[0] = '\0';
118 cache_file->handle_readers = nullptr;
119
120 /* relink layers */
121 BLO_read_struct_list(reader, CacheFileLayer, &cache_file->layers);
122}
123
125 /*id_code*/ CacheFile::id_type,
126 /*id_filter*/ FILTER_ID_CF,
127 /*dependencies_id_types*/ 0,
128 /*main_listbase_index*/ INDEX_ID_CF,
129 /*struct_size*/ sizeof(CacheFile),
130 /*name*/ "CacheFile",
131 /*name_plural*/ N_("cache_files"),
132 /*translation_context*/ BLT_I18NCONTEXT_ID_CACHEFILE,
134 /*asset_type_info*/ nullptr,
135
136 /*init_data*/ cache_file_init_data,
137 /*copy_data*/ cache_file_copy_data,
138 /*free_data*/ cache_file_free_data,
139 /*make_local*/ nullptr,
140 /*foreach_id*/ nullptr,
141 /*foreach_cache*/ nullptr,
142 /*foreach_path*/ cache_file_foreach_path,
143 /*foreach_working_space_color*/ nullptr,
144 /*owner_pointer_get*/ nullptr,
145
146 /*blend_write*/ cache_file_blend_write,
147 /*blend_read_data*/ cache_file_blend_read_data,
148 /*blend_read_after_liblink*/ nullptr,
149
150 /*blend_read_undo_preserve*/ nullptr,
151
152 /*lib_override_apply_post*/ nullptr,
153};
154
155#if defined(WITH_ALEMBIC) || defined(WITH_USD)
156/* TODO: make this per cache file to avoid global locks. */
157static blender::Mutex cache_mutex;
158#endif
159
161 CacheReader **reader,
162 Object *object,
163 const char *object_path)
164{
165#if defined(WITH_ALEMBIC) || defined(WITH_USD)
166
167 BLI_assert(cache_file->id.tag & ID_TAG_COPIED_ON_EVAL);
168
169 if (cache_file->handle == nullptr) {
170 return;
171 }
172
173 switch (cache_file->type) {
175# ifdef WITH_ALEMBIC
176 /* Open Alembic cache reader. */
178 cache_file->handle, *reader, object, object_path, cache_file->is_sequence);
179# endif
180 break;
182# ifdef WITH_USD
183 /* Open USD cache reader. */
185 cache_file->handle, *reader, object, object_path);
186# endif
187 break;
189 break;
190 }
191
192 /* Multiple modifiers and constraints can call this function concurrently. */
193 std::lock_guard lock(cache_mutex);
194 if (*reader) {
195 /* Register in set so we can free it when the cache file changes. */
196 if (cache_file->handle_readers == nullptr) {
197 cache_file->handle_readers = BLI_gset_ptr_new("CacheFile.handle_readers");
198 }
199 BLI_gset_reinsert(cache_file->handle_readers, reader, nullptr);
200 }
201 else if (cache_file->handle_readers) {
202 /* Remove in case CacheReader_open_alembic_object free the existing reader. */
203 BLI_gset_remove(cache_file->handle_readers, reader, nullptr);
204 }
205#else
206 UNUSED_VARS(cache_file, reader, object, object_path);
207#endif
208}
209
211{
212#if defined(WITH_ALEMBIC) || defined(WITH_USD)
213 /* Multiple modifiers and constraints can call this function concurrently, and
214 * cachefile_handle_free() can also be called at the same time. */
215 std::lock_guard lock(cache_mutex);
216 if (*reader != nullptr) {
217 if (cache_file) {
218 BLI_assert(cache_file->id.tag & ID_TAG_COPIED_ON_EVAL);
219
220 switch (cache_file->type) {
222# ifdef WITH_ALEMBIC
223 ABC_CacheReader_free(*reader);
224# endif
225 break;
227# ifdef WITH_USD
229# endif
230 break;
232 break;
233 }
234 }
235
236 *reader = nullptr;
237
238 if (cache_file && cache_file->handle_readers) {
239 BLI_gset_remove(cache_file->handle_readers, reader, nullptr);
240 }
241 }
242#else
243 UNUSED_VARS(cache_file, reader);
244#endif
245}
246
247static void cachefile_handle_free(CacheFile *cache_file)
248{
249#if defined(WITH_ALEMBIC) || defined(WITH_USD)
250
251 /* Free readers in all modifiers and constraints that use the handle, before
252 * we free the handle itself. */
253 {
254 std::lock_guard lock(cache_mutex);
255 if (cache_file->handle_readers) {
256 GSetIterator gs_iter;
257 GSET_ITER (gs_iter, cache_file->handle_readers) {
258 CacheReader **reader = static_cast<CacheReader **>(BLI_gsetIterator_getKey(&gs_iter));
259 if (*reader != nullptr) {
260 switch (cache_file->type) {
262# ifdef WITH_ALEMBIC
263 ABC_CacheReader_free(*reader);
264# endif
265 break;
267# ifdef WITH_USD
269# endif
270 break;
272 break;
273 }
274
275 *reader = nullptr;
276 }
277 }
278
279 BLI_gset_free(cache_file->handle_readers, nullptr);
280 cache_file->handle_readers = nullptr;
281 }
282 }
283
284 /* Free handle. */
285 if (cache_file->handle) {
286
287 switch (cache_file->type) {
289# ifdef WITH_ALEMBIC
290 ABC_free_handle(cache_file->handle);
291# endif
292 break;
294# ifdef WITH_USD
296# endif
297 break;
299 break;
300 }
301
302 cache_file->handle = nullptr;
303 }
304
305 cache_file->handle_filepath[0] = '\0';
306#else
307 UNUSED_VARS(cache_file);
308#endif
309}
310
311void *BKE_cachefile_add(Main *bmain, const char *name)
312{
313 CacheFile *cache_file = BKE_id_new<CacheFile>(bmain, name);
314
315 return cache_file;
316}
317
318void BKE_cachefile_reload(Depsgraph *depsgraph, CacheFile *cache_file)
319{
320 /* To force reload, free the handle and tag depsgraph to load it again. */
321 CacheFile *cache_file_eval = DEG_get_evaluated(depsgraph, cache_file);
322 if (cache_file_eval) {
323 cachefile_handle_free(cache_file_eval);
324 }
325
327}
328
329void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file)
330{
331 BLI_assert(cache_file->id.tag & ID_TAG_COPIED_ON_EVAL);
332
333 /* Compute filepath. */
334 char filepath[FILE_MAX];
335 if (!BKE_cachefile_filepath_get(bmain, depsgraph, cache_file, filepath)) {
336 return;
337 }
338
339 /* Test if filepath change or if we can keep the existing handle. */
340 if (STREQ(cache_file->handle_filepath, filepath)) {
341 return;
342 }
343
344 cachefile_handle_free(cache_file);
345 BLI_freelistN(&cache_file->object_paths);
346
347#ifdef WITH_ALEMBIC
348 if (BLI_path_extension_check_glob(filepath, "*.abc")) {
349 cache_file->type = CACHEFILE_TYPE_ALEMBIC;
350 cache_file->handle = ABC_create_handle(
351 bmain,
352 filepath,
353 static_cast<const CacheFileLayer *>(cache_file->layers.first),
354 &cache_file->object_paths);
355 STRNCPY(cache_file->handle_filepath, filepath);
356 }
357#endif
358#ifdef WITH_USD
359 if (BLI_path_extension_check_glob(filepath, "*.usd;*.usda;*.usdc;*.usdz")) {
360 cache_file->type = CACHEFILE_TYPE_USD;
362 bmain, filepath, &cache_file->object_paths);
363 STRNCPY(cache_file->handle_filepath, filepath);
364 }
365#endif
366
368 /* Flush object paths back to original data-block for UI. */
369 CacheFile *cache_file_orig = DEG_get_original(cache_file);
370 BLI_freelistN(&cache_file_orig->object_paths);
371 BLI_duplicatelist(&cache_file_orig->object_paths, &cache_file->object_paths);
372 }
373}
374
376 const Depsgraph *depsgraph,
377 const CacheFile *cache_file,
378 char r_filepath[FILE_MAX])
379{
380 BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
381 BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
382
383 int fframe;
384 int frame_len;
385
386 if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
388 const float ctime = BKE_scene_ctime_get(scene);
389 const double fps = double(scene->r.frs_sec) / double(scene->r.frs_sec_base);
390 const int frame = int(BKE_cachefile_time_offset(cache_file, double(ctime), fps));
391
392 char ext[32];
393 BLI_path_frame_strip(r_filepath, ext, sizeof(ext));
394 BLI_path_frame(r_filepath, FILE_MAX, frame, frame_len);
395 BLI_path_extension_ensure(r_filepath, FILE_MAX, ext);
396
397 /* TODO(kevin): store sequence range? */
398 return BLI_exists(r_filepath);
399 }
400
401 return true;
402}
403
404double BKE_cachefile_time_offset(const CacheFile *cache_file, const double time, const double fps)
405{
406 const double time_offset = double(cache_file->frame_offset) / fps;
407 const double frame = (cache_file->override_frame ? double(cache_file->frame) : time);
408 return cache_file->is_sequence ? frame : frame / fps - time_offset;
409}
410
411double BKE_cachefile_frame_offset(const CacheFile *cache_file, const double time)
412{
413 const double time_offset = double(cache_file->frame_offset);
414 const double frame = cache_file->override_frame ? double(cache_file->frame) : time;
415 return cache_file->is_sequence ? frame : frame - time_offset;
416}
417
418CacheFileLayer *BKE_cachefile_add_layer(CacheFile *cache_file, const char filepath[1024])
419{
420 LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) {
421 if (STREQ(layer->filepath, filepath)) {
422 return nullptr;
423 }
424 }
425
426 const int num_layers = BLI_listbase_count(&cache_file->layers);
427
428 CacheFileLayer *layer = MEM_callocN<CacheFileLayer>("CacheFileLayer");
429 STRNCPY(layer->filepath, filepath);
430
431 BLI_addtail(&cache_file->layers, layer);
432
433 cache_file->active_layer = char(num_layers + 1);
434
435 return layer;
436}
437
439{
440 return static_cast<CacheFileLayer *>(
441 BLI_findlink(&cache_file->layers, cache_file->active_layer - 1));
442}
443
445{
446 cache_file->active_layer = 0;
447 BLI_remlink(&cache_file->layers, layer);
448 MEM_freeN(layer);
449}
void ABC_CacheReader_free(struct CacheReader *reader)
void ABC_free_handle(struct CacheArchiveHandle *handle)
struct CacheReader * CacheReader_open_alembic_object(struct CacheArchiveHandle *handle, struct CacheReader *reader, struct Object *object, const char *object_path, bool is_sequence)
struct CacheArchiveHandle * ABC_create_handle(const struct Main *bmain, const char *filepath, const struct CacheFileLayer *layers, struct ListBase *object_paths)
bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path, size_t path_maxncpy)
Definition bpath.cc:125
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:47
IDTypeInfo IDType_ID_CF
Definition cachefile.cc:124
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1514
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2631
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2370
#define BLI_assert(a)
Definition BLI_assert.h:46
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:360
GSet * BLI_gset_ptr_new(const char *info)
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition BLI_ghash.h:455
bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.cc:989
#define GSET_ITER(gs_iter_, gset_)
Definition BLI_ghash.h:468
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.cc:999
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void void void void void void BLI_duplicatelist(ListBase *dst, const ListBase *src) ATTR_NONNULL(1
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool void BLI_path_frame_strip(char *path, char *r_ext, size_t ext_maxncpy) ATTR_NONNULL(1
#define FILE_MAX
bool BLI_path_frame_get(const char *path, int *r_frame, int *r_digits_len) ATTR_NONNULL(1
bool BLI_path_extension_ensure(char *path, size_t path_maxncpy, const char *ext) ATTR_NONNULL(1
bool BLI_path_frame(char *path, size_t path_maxncpy, int frame, int digits) ATTR_NONNULL(1)
bool BLI_path_extension_check_glob(const char *path, const char *ext_fnmatch) ATTR_NONNULL(1
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define UNUSED_VARS(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define STREQ(a, b)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLT_I18NCONTEXT_ID_CACHEFILE
void DEG_id_tag_update(ID *id, unsigned int flags)
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:323
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
T * DEG_get_original(T *id)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_TAG_COPIED_ON_EVAL
Definition DNA_ID.h:997
#define FILTER_ID_CF
Definition DNA_ID.h:1225
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:685
@ INDEX_ID_CF
Definition DNA_ID.h:1317
@ CACHEFILE_VELOCITY_UNIT_SECOND
@ CACHE_FILE_TYPE_INVALID
@ CACHEFILE_TYPE_ALEMBIC
@ CACHEFILE_TYPE_USD
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
static float frame_len(const Frame *frame)
Definition MOD_skin.cc:384
volatile int lock
BPy_StructRNA * depsgraph
double BKE_cachefile_time_offset(const CacheFile *cache_file, const double time, const double fps)
Definition cachefile.cc:404
static void cachefile_handle_free(CacheFile *cache_file)
Definition cachefile.cc:247
void BKE_cachefile_reader_free(CacheFile *cache_file, CacheReader **reader)
Definition cachefile.cc:210
static void cache_file_free_data(ID *id)
Definition cachefile.cc:78
static void cache_file_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *id_src, const int)
Definition cachefile.cc:63
void BKE_cachefile_remove_layer(CacheFile *cache_file, CacheFileLayer *layer)
Definition cachefile.cc:444
CacheFileLayer * BKE_cachefile_get_active_layer(CacheFile *cache_file)
Definition cachefile.cc:438
static void cache_file_init_data(ID *id)
Definition cachefile.cc:52
static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_address)
Definition cachefile.cc:93
CacheFileLayer * BKE_cachefile_add_layer(CacheFile *cache_file, const char filepath[1024])
Definition cachefile.cc:418
static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
Definition cachefile.cc:86
void * BKE_cachefile_add(Main *bmain, const char *name)
Definition cachefile.cc:311
static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
Definition cachefile.cc:112
double BKE_cachefile_frame_offset(const CacheFile *cache_file, const double time)
Definition cachefile.cc:411
bool BKE_cachefile_filepath_get(const Main *bmain, const Depsgraph *depsgraph, const CacheFile *cache_file, char r_filepath[FILE_MAX])
Definition cachefile.cc:375
void BKE_cachefile_reload(Depsgraph *depsgraph, CacheFile *cache_file)
Definition cachefile.cc:318
void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file)
Definition cachefile.cc:329
void BKE_cachefile_reader_open(CacheFile *cache_file, CacheReader **reader, Object *object, const char *object_path)
Definition cachefile.cc:160
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
CacheArchiveHandle * USD_create_handle(Main *, const char *filepath, ListBase *object_paths)
CacheReader * CacheReader_open_usd_object(CacheArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path)
void USD_free_handle(CacheArchiveHandle *handle)
void USD_CacheReader_free(CacheReader *reader)
std::mutex Mutex
Definition BLI_mutex.hh:47
const char * name
struct CacheArchiveHandle * handle
ListBase object_paths
char handle_filepath[1024]
struct GSet * handle_readers
char filepath[1024]
char velocity_name[64]
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
void * first
struct RenderData r
#define N_(msgid)