Blender V4.3
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
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_path_utils.hh"
20#include "BLI_string.h"
21#include "BLI_threads.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_main.hh"
31#include "BKE_scene.hh"
32
34
35#include "RE_engine.h"
36
37#include "BLO_read_write.hh"
38
39#include "MEM_guardedalloc.h"
40
41#ifdef WITH_ALEMBIC
42# include "ABC_alembic.h"
43#endif
44
45#ifdef WITH_USD
46# include "usd.hh"
47#endif
48
49static void cachefile_handle_free(CacheFile *cache_file);
50
51static void cache_file_init_data(ID *id)
52{
53 CacheFile *cache_file = (CacheFile *)id;
54
56
57 cache_file->scale = 1.0f;
59 STRNCPY(cache_file->velocity_name, ".velocities");
60}
61
62static void cache_file_copy_data(Main * /*bmain*/,
63 std::optional<Library *> /*owner_library*/,
64 ID *id_dst,
65 const ID *id_src,
66 const int /*flag*/)
67{
68 CacheFile *cache_file_dst = (CacheFile *)id_dst;
69 const CacheFile *cache_file_src = (const CacheFile *)id_src;
70
71 cache_file_dst->handle = nullptr;
72 cache_file_dst->handle_readers = nullptr;
73 BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_src->object_paths);
74 BLI_duplicatelist(&cache_file_dst->layers, &cache_file_src->layers);
75}
76
77static void cache_file_free_data(ID *id)
78{
79 CacheFile *cache_file = (CacheFile *)id;
80 cachefile_handle_free(cache_file);
81 BLI_freelistN(&cache_file->object_paths);
82 BLI_freelistN(&cache_file->layers);
83}
84
85static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
86{
87 CacheFile *cache_file = (CacheFile *)id;
89 bpath_data, cache_file->filepath, sizeof(cache_file->filepath));
90}
91
92static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_address)
93{
94 CacheFile *cache_file = (CacheFile *)id;
95
96 /* Clean up, important in undo case to reduce false detection of changed datablocks. */
97 BLI_listbase_clear(&cache_file->object_paths);
98 cache_file->handle = nullptr;
99 memset(cache_file->handle_filepath, 0, sizeof(cache_file->handle_filepath));
100 cache_file->handle_readers = nullptr;
101
102 BLO_write_id_struct(writer, CacheFile, id_address, &cache_file->id);
103 BKE_id_blend_write(writer, &cache_file->id);
104
105 /* write layers */
106 LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) {
107 BLO_write_struct(writer, CacheFileLayer, layer);
108 }
109}
110
112{
113 CacheFile *cache_file = (CacheFile *)id;
114 BLI_listbase_clear(&cache_file->object_paths);
115 cache_file->handle = nullptr;
116 cache_file->handle_filepath[0] = '\0';
117 cache_file->handle_readers = nullptr;
118
119 /* relink layers */
120 BLO_read_struct_list(reader, CacheFileLayer, &cache_file->layers);
121}
122
124 /*id_code*/ ID_CF,
125 /*id_filter*/ FILTER_ID_CF,
126 /*dependencies_id_types*/ 0,
127 /*main_listbase_index*/ INDEX_ID_CF,
128 /*struct_size*/ sizeof(CacheFile),
129 /*name*/ "CacheFile",
130 /*name_plural*/ N_("cache_files"),
131 /*translation_context*/ BLT_I18NCONTEXT_ID_CACHEFILE,
133 /*asset_type_info*/ nullptr,
134
135 /*init_data*/ cache_file_init_data,
136 /*copy_data*/ cache_file_copy_data,
137 /*free_data*/ cache_file_free_data,
138 /*make_local*/ nullptr,
139 /*foreach_id*/ nullptr,
140 /*foreach_cache*/ nullptr,
141 /*foreach_path*/ cache_file_foreach_path,
142 /*owner_pointer_get*/ nullptr,
143
144 /*blend_write*/ cache_file_blend_write,
145 /*blend_read_data*/ cache_file_blend_read_data,
146 /*blend_read_after_liblink*/ nullptr,
147
148 /*blend_read_undo_preserve*/ nullptr,
149
150 /*lib_override_apply_post*/ nullptr,
151};
152
153/* TODO: make this per cache file to avoid global locks. */
155
157{
159}
160
162{
164}
165
167 CacheReader **reader,
168 Object *object,
169 const char *object_path)
170{
171#if defined(WITH_ALEMBIC) || defined(WITH_USD)
172
173 BLI_assert(cache_file->id.tag & ID_TAG_COPIED_ON_EVAL);
174
175 if (cache_file->handle == nullptr) {
176 return;
177 }
178
179 switch (cache_file->type) {
181# ifdef WITH_ALEMBIC
182 /* Open Alembic cache reader. */
184 cache_file->handle, *reader, object, object_path, cache_file->is_sequence);
185# endif
186 break;
188# ifdef WITH_USD
189 /* Open USD cache reader. */
191 cache_file->handle, *reader, object, object_path);
192# endif
193 break;
195 break;
196 }
197
198 /* Multiple modifiers and constraints can call this function concurrently. */
200 if (*reader) {
201 /* Register in set so we can free it when the cache file changes. */
202 if (cache_file->handle_readers == nullptr) {
203 cache_file->handle_readers = BLI_gset_ptr_new("CacheFile.handle_readers");
204 }
205 BLI_gset_reinsert(cache_file->handle_readers, reader, nullptr);
206 }
207 else if (cache_file->handle_readers) {
208 /* Remove in case CacheReader_open_alembic_object free the existing reader. */
209 BLI_gset_remove(cache_file->handle_readers, reader, nullptr);
210 }
212#else
213 UNUSED_VARS(cache_file, reader, object, object_path);
214#endif
215}
216
218{
219#if defined(WITH_ALEMBIC) || defined(WITH_USD)
220 /* Multiple modifiers and constraints can call this function concurrently, and
221 * cachefile_handle_free() can also be called at the same time. */
223 if (*reader != nullptr) {
224 if (cache_file) {
225 BLI_assert(cache_file->id.tag & ID_TAG_COPIED_ON_EVAL);
226
227 switch (cache_file->type) {
229# ifdef WITH_ALEMBIC
230 ABC_CacheReader_free(*reader);
231# endif
232 break;
234# ifdef WITH_USD
236# endif
237 break;
239 break;
240 }
241 }
242
243 *reader = nullptr;
244
245 if (cache_file && cache_file->handle_readers) {
246 BLI_gset_remove(cache_file->handle_readers, reader, nullptr);
247 }
248 }
250#else
251 UNUSED_VARS(cache_file, reader);
252#endif
253}
254
255static void cachefile_handle_free(CacheFile *cache_file)
256{
257#if defined(WITH_ALEMBIC) || defined(WITH_USD)
258
259 /* Free readers in all modifiers and constraints that use the handle, before
260 * we free the handle itself. */
262 if (cache_file->handle_readers) {
263 GSetIterator gs_iter;
264 GSET_ITER (gs_iter, cache_file->handle_readers) {
265 CacheReader **reader = static_cast<CacheReader **>(BLI_gsetIterator_getKey(&gs_iter));
266 if (*reader != nullptr) {
267 switch (cache_file->type) {
269# ifdef WITH_ALEMBIC
270 ABC_CacheReader_free(*reader);
271# endif
272 break;
274# ifdef WITH_USD
276# endif
277 break;
279 break;
280 }
281
282 *reader = nullptr;
283 }
284 }
285
286 BLI_gset_free(cache_file->handle_readers, nullptr);
287 cache_file->handle_readers = nullptr;
288 }
290
291 /* Free handle. */
292 if (cache_file->handle) {
293
294 switch (cache_file->type) {
296# ifdef WITH_ALEMBIC
297 ABC_free_handle(cache_file->handle);
298# endif
299 break;
301# ifdef WITH_USD
303# endif
304 break;
306 break;
307 }
308
309 cache_file->handle = nullptr;
310 }
311
312 cache_file->handle_filepath[0] = '\0';
313#else
314 UNUSED_VARS(cache_file);
315#endif
316}
317
318void *BKE_cachefile_add(Main *bmain, const char *name)
319{
320 CacheFile *cache_file = static_cast<CacheFile *>(BKE_id_new(bmain, ID_CF, name));
321
322 return cache_file;
323}
324
325void BKE_cachefile_reload(Depsgraph *depsgraph, CacheFile *cache_file)
326{
327 /* To force reload, free the handle and tag depsgraph to load it again. */
328 CacheFile *cache_file_eval = (CacheFile *)DEG_get_evaluated_id(depsgraph, &cache_file->id);
329 if (cache_file_eval) {
330 cachefile_handle_free(cache_file_eval);
331 }
332
334}
335
336void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file)
337{
338 BLI_assert(cache_file->id.tag & ID_TAG_COPIED_ON_EVAL);
339
340 /* Compute filepath. */
341 char filepath[FILE_MAX];
342 if (!BKE_cachefile_filepath_get(bmain, depsgraph, cache_file, filepath)) {
343 return;
344 }
345
346 /* Test if filepath change or if we can keep the existing handle. */
347 if (STREQ(cache_file->handle_filepath, filepath)) {
348 return;
349 }
350
351 cachefile_handle_free(cache_file);
352 BLI_freelistN(&cache_file->object_paths);
353
354#ifdef WITH_ALEMBIC
355 if (BLI_path_extension_check_glob(filepath, "*abc")) {
356 cache_file->type = CACHEFILE_TYPE_ALEMBIC;
357 cache_file->handle = ABC_create_handle(
358 bmain,
359 filepath,
360 static_cast<const CacheFileLayer *>(cache_file->layers.first),
361 &cache_file->object_paths);
362 STRNCPY(cache_file->handle_filepath, filepath);
363 }
364#endif
365#ifdef WITH_USD
366 if (BLI_path_extension_check_glob(filepath, "*.usd;*.usda;*.usdc;*.usdz")) {
367 cache_file->type = CACHEFILE_TYPE_USD;
369 bmain, filepath, &cache_file->object_paths);
370 STRNCPY(cache_file->handle_filepath, filepath);
371 }
372#endif
373
375 /* Flush object paths back to original data-block for UI. */
376 CacheFile *cache_file_orig = (CacheFile *)DEG_get_original_id(&cache_file->id);
377 BLI_freelistN(&cache_file_orig->object_paths);
378 BLI_duplicatelist(&cache_file_orig->object_paths, &cache_file->object_paths);
379 }
380}
381
383 const Depsgraph *depsgraph,
384 const CacheFile *cache_file,
385 char r_filepath[FILE_MAX])
386{
387 BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
388 BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
389
390 int fframe;
391 int frame_len;
392
393 if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
395 const float ctime = BKE_scene_ctime_get(scene);
396 const double fps = double(scene->r.frs_sec) / double(scene->r.frs_sec_base);
397 const int frame = int(BKE_cachefile_time_offset(cache_file, double(ctime), fps));
398
399 char ext[32];
400 BLI_path_frame_strip(r_filepath, ext, sizeof(ext));
401 BLI_path_frame(r_filepath, FILE_MAX, frame, frame_len);
402 BLI_path_extension_ensure(r_filepath, FILE_MAX, ext);
403
404 /* TODO(kevin): store sequence range? */
405 return BLI_exists(r_filepath);
406 }
407
408 return true;
409}
410
411double BKE_cachefile_time_offset(const CacheFile *cache_file, const double time, const double fps)
412{
413 const double time_offset = double(cache_file->frame_offset) / fps;
414 const double frame = (cache_file->override_frame ? double(cache_file->frame) : time);
415 return cache_file->is_sequence ? frame : frame / fps - time_offset;
416}
417
419{
420 RenderEngineType *render_engine_type = RE_engines_find(scene->r.engine);
421
422 if (cache_file->type != CACHEFILE_TYPE_ALEMBIC ||
423 !RE_engine_supports_alembic_procedural(render_engine_type, scene))
424 {
425 return false;
426 }
427
428 return cache_file->use_render_procedural;
429}
430
431CacheFileLayer *BKE_cachefile_add_layer(CacheFile *cache_file, const char filepath[1024])
432{
433 LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) {
434 if (STREQ(layer->filepath, filepath)) {
435 return nullptr;
436 }
437 }
438
439 const int num_layers = BLI_listbase_count(&cache_file->layers);
440
441 CacheFileLayer *layer = static_cast<CacheFileLayer *>(
442 MEM_callocN(sizeof(CacheFileLayer), "CacheFileLayer"));
443 STRNCPY(layer->filepath, filepath);
444
445 BLI_addtail(&cache_file->layers, layer);
446
447 cache_file->active_layer = char(num_layers + 1);
448
449 return layer;
450}
451
453{
454 return static_cast<CacheFileLayer *>(
455 BLI_findlink(&cache_file->layers, cache_file->active_layer - 1));
456}
457
459{
460 cache_file->active_layer = 0;
461 BLI_remlink(&cache_file->layers, layer);
462 MEM_freeN(layer);
463}
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:123
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:39
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1482
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2560
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2317
#define BLI_assert(a)
Definition BLI_assert.h:50
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
GSet * BLI_gset_ptr_new(const char *info)
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition BLI_ghash.h:459
bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:989
#define GSET_ITER(gs_iter_, gset_)
Definition BLI_ghash.h:472
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:999
#define LISTBASE_FOREACH(type, var, list)
void void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT 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
#define STRNCPY(dst, src)
Definition BLI_string.h:593
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
pthread_spinlock_t SpinLock
void BLI_spin_init(SpinLock *spin)
Definition threads.cc:391
void BLI_spin_unlock(SpinLock *spin)
Definition threads.cc:430
void BLI_spin_lock(SpinLock *spin)
Definition threads.cc:405
void BLI_spin_end(SpinLock *spin)
Definition threads.cc:445
#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
typedef double(DMatrix)[4][4]
void DEG_id_tag_update(ID *id, unsigned int flags)
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:318
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
ID * DEG_get_original_id(ID *id)
ID * DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
#define FILTER_ID_CF
Definition DNA_ID.h:1192
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:647
@ ID_TAG_COPIED_ON_EVAL
Definition DNA_ID.h:964
@ INDEX_ID_CF
Definition DNA_ID.h:1285
@ ID_CF
@ CACHEFILE_VELOCITY_UNIT_SECOND
struct CacheFile CacheFile
@ 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
bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file, Scene *scene)
Definition cachefile.cc:418
double BKE_cachefile_time_offset(const CacheFile *cache_file, const double time, const double fps)
Definition cachefile.cc:411
static void cachefile_handle_free(CacheFile *cache_file)
Definition cachefile.cc:255
void BKE_cachefile_reader_free(CacheFile *cache_file, CacheReader **reader)
Definition cachefile.cc:217
static void cache_file_free_data(ID *id)
Definition cachefile.cc:77
static void cache_file_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *id_src, const int)
Definition cachefile.cc:62
void BKE_cachefiles_init()
Definition cachefile.cc:156
void BKE_cachefile_remove_layer(CacheFile *cache_file, CacheFileLayer *layer)
Definition cachefile.cc:458
CacheFileLayer * BKE_cachefile_get_active_layer(CacheFile *cache_file)
Definition cachefile.cc:452
static void cache_file_init_data(ID *id)
Definition cachefile.cc:51
static SpinLock spin
Definition cachefile.cc:154
static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_address)
Definition cachefile.cc:92
CacheFileLayer * BKE_cachefile_add_layer(CacheFile *cache_file, const char filepath[1024])
Definition cachefile.cc:431
static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
Definition cachefile.cc:85
void * BKE_cachefile_add(Main *bmain, const char *name)
Definition cachefile.cc:318
void BKE_cachefiles_exit()
Definition cachefile.cc:161
static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
Definition cachefile.cc:111
bool BKE_cachefile_filepath_get(const Main *bmain, const Depsgraph *depsgraph, const CacheFile *cache_file, char r_filepath[FILE_MAX])
Definition cachefile.cc:382
void BKE_cachefile_reload(Depsgraph *depsgraph, CacheFile *cache_file)
Definition cachefile.cc:325
void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file)
Definition cachefile.cc:336
void BKE_cachefile_reader_open(CacheFile *cache_file, CacheReader **reader, Object *object, const char *object_path)
Definition cachefile.cc:166
IDTypeInfo IDType_ID_CF
Definition cachefile.cc:123
double time
const Depsgraph * depsgraph
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
bool RE_engine_supports_alembic_procedural(const RenderEngineType *render_type, Scene *scene)
RenderEngineType * RE_engines_find(const char *idname)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
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)
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:413
int tag
Definition DNA_ID.h:434
void * first
#define N_(msgid)