Blender V4.5
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 /*owner_pointer_get*/ nullptr,
144
145 /*blend_write*/ cache_file_blend_write,
146 /*blend_read_data*/ cache_file_blend_read_data,
147 /*blend_read_after_liblink*/ nullptr,
148
149 /*blend_read_undo_preserve*/ nullptr,
150
151 /*lib_override_apply_post*/ nullptr,
152};
153
154/* TODO: make this per cache file to avoid global locks. */
156
158 CacheReader **reader,
159 Object *object,
160 const char *object_path)
161{
162#if defined(WITH_ALEMBIC) || defined(WITH_USD)
163
164 BLI_assert(cache_file->id.tag & ID_TAG_COPIED_ON_EVAL);
165
166 if (cache_file->handle == nullptr) {
167 return;
168 }
169
170 switch (cache_file->type) {
172# ifdef WITH_ALEMBIC
173 /* Open Alembic cache reader. */
175 cache_file->handle, *reader, object, object_path, cache_file->is_sequence);
176# endif
177 break;
179# ifdef WITH_USD
180 /* Open USD cache reader. */
182 cache_file->handle, *reader, object, object_path);
183# endif
184 break;
186 break;
187 }
188
189 /* Multiple modifiers and constraints can call this function concurrently. */
190 std::lock_guard lock(cache_mutex);
191 if (*reader) {
192 /* Register in set so we can free it when the cache file changes. */
193 if (cache_file->handle_readers == nullptr) {
194 cache_file->handle_readers = BLI_gset_ptr_new("CacheFile.handle_readers");
195 }
196 BLI_gset_reinsert(cache_file->handle_readers, reader, nullptr);
197 }
198 else if (cache_file->handle_readers) {
199 /* Remove in case CacheReader_open_alembic_object free the existing reader. */
200 BLI_gset_remove(cache_file->handle_readers, reader, nullptr);
201 }
202#else
203 UNUSED_VARS(cache_file, reader, object, object_path);
204#endif
205}
206
208{
209#if defined(WITH_ALEMBIC) || defined(WITH_USD)
210 /* Multiple modifiers and constraints can call this function concurrently, and
211 * cachefile_handle_free() can also be called at the same time. */
212 std::lock_guard lock(cache_mutex);
213 if (*reader != nullptr) {
214 if (cache_file) {
215 BLI_assert(cache_file->id.tag & ID_TAG_COPIED_ON_EVAL);
216
217 switch (cache_file->type) {
219# ifdef WITH_ALEMBIC
220 ABC_CacheReader_free(*reader);
221# endif
222 break;
224# ifdef WITH_USD
226# endif
227 break;
229 break;
230 }
231 }
232
233 *reader = nullptr;
234
235 if (cache_file && cache_file->handle_readers) {
236 BLI_gset_remove(cache_file->handle_readers, reader, nullptr);
237 }
238 }
239#else
240 UNUSED_VARS(cache_file, reader);
241#endif
242}
243
244static void cachefile_handle_free(CacheFile *cache_file)
245{
246#if defined(WITH_ALEMBIC) || defined(WITH_USD)
247
248 /* Free readers in all modifiers and constraints that use the handle, before
249 * we free the handle itself. */
250 {
251 std::lock_guard lock(cache_mutex);
252 if (cache_file->handle_readers) {
253 GSetIterator gs_iter;
254 GSET_ITER (gs_iter, cache_file->handle_readers) {
255 CacheReader **reader = static_cast<CacheReader **>(BLI_gsetIterator_getKey(&gs_iter));
256 if (*reader != nullptr) {
257 switch (cache_file->type) {
259# ifdef WITH_ALEMBIC
260 ABC_CacheReader_free(*reader);
261# endif
262 break;
264# ifdef WITH_USD
266# endif
267 break;
269 break;
270 }
271
272 *reader = nullptr;
273 }
274 }
275
276 BLI_gset_free(cache_file->handle_readers, nullptr);
277 cache_file->handle_readers = nullptr;
278 }
279 }
280
281 /* Free handle. */
282 if (cache_file->handle) {
283
284 switch (cache_file->type) {
286# ifdef WITH_ALEMBIC
287 ABC_free_handle(cache_file->handle);
288# endif
289 break;
291# ifdef WITH_USD
293# endif
294 break;
296 break;
297 }
298
299 cache_file->handle = nullptr;
300 }
301
302 cache_file->handle_filepath[0] = '\0';
303#else
304 UNUSED_VARS(cache_file);
305#endif
306}
307
308void *BKE_cachefile_add(Main *bmain, const char *name)
309{
310 CacheFile *cache_file = BKE_id_new<CacheFile>(bmain, name);
311
312 return cache_file;
313}
314
315void BKE_cachefile_reload(Depsgraph *depsgraph, CacheFile *cache_file)
316{
317 /* To force reload, free the handle and tag depsgraph to load it again. */
318 CacheFile *cache_file_eval = DEG_get_evaluated(depsgraph, cache_file);
319 if (cache_file_eval) {
320 cachefile_handle_free(cache_file_eval);
321 }
322
324}
325
326void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file)
327{
328 BLI_assert(cache_file->id.tag & ID_TAG_COPIED_ON_EVAL);
329
330 /* Compute filepath. */
331 char filepath[FILE_MAX];
332 if (!BKE_cachefile_filepath_get(bmain, depsgraph, cache_file, filepath)) {
333 return;
334 }
335
336 /* Test if filepath change or if we can keep the existing handle. */
337 if (STREQ(cache_file->handle_filepath, filepath)) {
338 return;
339 }
340
341 cachefile_handle_free(cache_file);
342 BLI_freelistN(&cache_file->object_paths);
343
344#ifdef WITH_ALEMBIC
345 if (BLI_path_extension_check_glob(filepath, "*.abc")) {
346 cache_file->type = CACHEFILE_TYPE_ALEMBIC;
347 cache_file->handle = ABC_create_handle(
348 bmain,
349 filepath,
350 static_cast<const CacheFileLayer *>(cache_file->layers.first),
351 &cache_file->object_paths);
352 STRNCPY(cache_file->handle_filepath, filepath);
353 }
354#endif
355#ifdef WITH_USD
356 if (BLI_path_extension_check_glob(filepath, "*.usd;*.usda;*.usdc;*.usdz")) {
357 cache_file->type = CACHEFILE_TYPE_USD;
359 bmain, filepath, &cache_file->object_paths);
360 STRNCPY(cache_file->handle_filepath, filepath);
361 }
362#endif
363
365 /* Flush object paths back to original data-block for UI. */
366 CacheFile *cache_file_orig = DEG_get_original(cache_file);
367 BLI_freelistN(&cache_file_orig->object_paths);
368 BLI_duplicatelist(&cache_file_orig->object_paths, &cache_file->object_paths);
369 }
370}
371
373 const Depsgraph *depsgraph,
374 const CacheFile *cache_file,
375 char r_filepath[FILE_MAX])
376{
377 BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
378 BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
379
380 int fframe;
381 int frame_len;
382
383 if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
385 const float ctime = BKE_scene_ctime_get(scene);
386 const double fps = double(scene->r.frs_sec) / double(scene->r.frs_sec_base);
387 const int frame = int(BKE_cachefile_time_offset(cache_file, double(ctime), fps));
388
389 char ext[32];
390 BLI_path_frame_strip(r_filepath, ext, sizeof(ext));
391 BLI_path_frame(r_filepath, FILE_MAX, frame, frame_len);
392 BLI_path_extension_ensure(r_filepath, FILE_MAX, ext);
393
394 /* TODO(kevin): store sequence range? */
395 return BLI_exists(r_filepath);
396 }
397
398 return true;
399}
400
401double BKE_cachefile_time_offset(const CacheFile *cache_file, const double time, const double fps)
402{
403 const double time_offset = double(cache_file->frame_offset) / fps;
404 const double frame = (cache_file->override_frame ? double(cache_file->frame) : time);
405 return cache_file->is_sequence ? frame : frame / fps - time_offset;
406}
407
408double BKE_cachefile_frame_offset(const CacheFile *cache_file, const double time)
409{
410 const double time_offset = double(cache_file->frame_offset);
411 const double frame = cache_file->override_frame ? double(cache_file->frame) : time;
412 return cache_file->is_sequence ? frame : frame - time_offset;
413}
414
416{
417 RenderEngineType *render_engine_type = RE_engines_find(scene->r.engine);
418
419 if (cache_file->type != CACHEFILE_TYPE_ALEMBIC ||
420 !RE_engine_supports_alembic_procedural(render_engine_type, scene))
421 {
422 return false;
423 }
424
425 return cache_file->use_render_procedural;
426}
427
428CacheFileLayer *BKE_cachefile_add_layer(CacheFile *cache_file, const char filepath[1024])
429{
430 LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) {
431 if (STREQ(layer->filepath, filepath)) {
432 return nullptr;
433 }
434 }
435
436 const int num_layers = BLI_listbase_count(&cache_file->layers);
437
438 CacheFileLayer *layer = MEM_callocN<CacheFileLayer>("CacheFileLayer");
439 STRNCPY(layer->filepath, filepath);
440
441 BLI_addtail(&cache_file->layers, layer);
442
443 cache_file->active_layer = char(num_layers + 1);
444
445 return layer;
446}
447
449{
450 return static_cast<CacheFileLayer *>(
451 BLI_findlink(&cache_file->layers, cache_file->active_layer - 1));
452}
453
455{
456 cache_file->active_layer = 0;
457 BLI_remlink(&cache_file->layers, layer);
458 MEM_freeN(layer);
459}
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:44
IDTypeInfo IDType_ID_CF
Definition cachefile.cc:124
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1495
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2611
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2367
#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:373
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:688
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_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ INDEX_ID_CF
Definition DNA_ID.h:1226
@ ID_TAG_COPIED_ON_EVAL
Definition DNA_ID.h:905
@ 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
bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file, Scene *scene)
Definition cachefile.cc:415
double BKE_cachefile_time_offset(const CacheFile *cache_file, const double time, const double fps)
Definition cachefile.cc:401
static void cachefile_handle_free(CacheFile *cache_file)
Definition cachefile.cc:244
static blender::Mutex cache_mutex
Definition cachefile.cc:155
void BKE_cachefile_reader_free(CacheFile *cache_file, CacheReader **reader)
Definition cachefile.cc:207
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:454
CacheFileLayer * BKE_cachefile_get_active_layer(CacheFile *cache_file)
Definition cachefile.cc:448
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:428
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:308
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:408
bool BKE_cachefile_filepath_get(const Main *bmain, const Depsgraph *depsgraph, const CacheFile *cache_file, char r_filepath[FILE_MAX])
Definition cachefile.cc:372
void BKE_cachefile_reload(Depsgraph *depsgraph, CacheFile *cache_file)
Definition cachefile.cc:315
void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file)
Definition cachefile.cc:326
void BKE_cachefile_reader_open(CacheFile *cache_file, CacheReader **reader, Object *object, const char *object_path)
Definition cachefile.cc:157
#define FILTER_ID_CF
#define ID_BLEND_PATH(_bmain, _id)
bool RE_engine_supports_alembic_procedural(const RenderEngineType *render_type, Scene *scene)
RenderEngineType * RE_engines_find(const char *idname)
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
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:404
int tag
Definition DNA_ID.h:424
void * first
char engine[32]
struct RenderData r
#define N_(msgid)