Alembic: integrate cache file into the dependency graph

* The cache file datablock is now evaluated as part of the dependency graph,
  creating/freeing the Alembic file handle matching the current frame.
  Modifiers and constraints depend on this evaluation.
* Cache file handles and readers now only exist on COW datablocks, never the
  original ones.
* Object data paths are flushed back to the original for the user interface.
* The cache file keeps a list of all readers associated with its handle, and
  automatically frees them when the handle is freed. This kind of sharing of
  data across datablocks is weak but we have no better mechanism for it.

Fix T62720: Alembic sequences not working and crashing

Differential Revision: https://developer.blender.org/D4774
This commit is contained in:
Brecht Van Lommel 2019-04-04 15:07:37 +02:00
parent a72a831570
commit 89826e0a0d
Notes: blender-bot 2023-02-14 09:02:41 +01:00
Referenced by issue #62720, Importing Alembic Mesh Causes Blender To Crash As Well As Alembic Sequences/Playback of Alembic sequences does not work
Referenced by issue #61710, Render crashes every 400 to 700 frames
18 changed files with 235 additions and 258 deletions

View File

@ -364,9 +364,6 @@ void AbcObjectReader::addCacheModifier()
id_us_plus(&mcmd->cache_file->id);
BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
mcmd->reader = reinterpret_cast<CacheReader *>(this);
this->incref();
}
chrono_t AbcObjectReader::minTime() const

View File

@ -627,6 +627,7 @@ struct ImportJobData {
char filename[1024];
ImportSettings settings;
ArchiveReader *archive;
std::vector<AbcObjectReader *> readers;
short *stop;
@ -672,9 +673,9 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
cache_file->is_sequence = data->settings.is_sequence;
cache_file->scale = data->settings.scale;
cache_file->handle = handle_from_archive(archive);
BLI_strncpy(cache_file->filepath, data->filename, 1024);
STRNCPY(cache_file->filepath, data->filename);
data->archive = archive;
data->settings.cache_file = cache_file;
*data->do_update = true;
@ -855,6 +856,7 @@ static void import_endjob(void *user_data)
static void import_freejob(void *user_data)
{
ImportJobData *data = static_cast<ImportJobData *>(user_data);
delete data->archive;
delete data;
}
@ -886,6 +888,7 @@ bool ABC_import(bContext *C,
job->settings.validate_meshes = validate_meshes;
job->error_code = ABC_NO_ERROR;
job->was_cancelled = false;
job->archive = NULL;
G.is_break = false;

View File

@ -29,8 +29,10 @@ extern "C" {
#endif
struct CacheFile;
struct CacheReader;
struct Depsgraph;
struct Main;
struct Object;
struct Scene;
void BKE_cachefiles_init(void);
@ -52,24 +54,27 @@ void BKE_cachefile_make_local(struct Main *bmain,
struct CacheFile *cache_file,
const bool lib_local);
void BKE_cachefile_reload(const struct Main *bmain, struct CacheFile *cache_file);
void BKE_cachefile_reload(struct Depsgraph *depsgraph, struct CacheFile *cache_file);
void BKE_cachefile_ensure_handle(const struct Main *bmain, struct CacheFile *cache_file);
void BKE_cachefile_update_frame(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
const float ctime,
const float fps);
void BKE_cachefile_eval(struct Main *bmain,
struct Depsgraph *depsgraph,
struct CacheFile *cache_file);
bool BKE_cachefile_filepath_get(const struct Main *bmain,
const struct Depsgraph *depsgrah,
const struct CacheFile *cache_file,
float frame,
char r_filename[1024]);
float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps);
float BKE_cachefile_time_offset(const struct CacheFile *cache_file,
const float time,
const float fps);
void BKE_cachefile_clean(struct Main *bmain, struct CacheFile *cache_file);
/* Modifiers and constraints open and free readers through these. */
void BKE_cachefile_reader_open(struct CacheFile *cache_file,
struct CacheReader **reader,
struct Object *object,
const char *object_path);
void BKE_cachefile_reader_free(struct CacheFile *cache_file, struct CacheReader **reader);
#ifdef __cplusplus
}

View File

@ -21,18 +21,21 @@
* \ingroup bke
*/
#include <string.h>
#include "DNA_anim_types.h"
#include "DNA_cachefile_types.h"
#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
#include "BLI_fileops.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BKE_animsys.h"
#include "BKE_cachefile.h"
@ -41,10 +44,13 @@
#include "BKE_modifier.h"
#include "BKE_scene.h"
#include "DEG_depsgraph_query.h"
#ifdef WITH_ALEMBIC
# include "ABC_alembic.h"
#endif
/* TODO: make this per cache file to avoid global locks. */
static SpinLock spin;
void BKE_cachefiles_init(void)
@ -57,6 +63,94 @@ void BKE_cachefiles_exit(void)
BLI_spin_end(&spin);
}
void BKE_cachefile_reader_open(CacheFile *cache_file,
struct CacheReader **reader,
Object *object,
const char *object_path)
{
#ifdef WITH_ALEMBIC
BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
if (cache_file->handle == NULL) {
return;
}
/* Open Alembic cache reader. */
*reader = CacheReader_open_alembic_object(cache_file->handle, *reader, object, object_path);
/* Multiple modifiers and constraints can call this function concurrently. */
BLI_spin_lock(&spin);
if (*reader) {
/* Register in set so we can free it when the cache file changes. */
if (cache_file->handle_readers == NULL) {
cache_file->handle_readers = BLI_gset_ptr_new("CacheFile.handle_readers");
}
BLI_gset_reinsert(cache_file->handle_readers, reader, NULL);
}
else if (cache_file->handle_readers) {
/* Remove in case CacheReader_open_alembic_object free the existing reader. */
BLI_gset_remove(cache_file->handle_readers, reader, NULL);
}
BLI_spin_unlock(&spin);
#else
UNUSED_VARS(reader, object, object_path);
#endif
}
void BKE_cachefile_reader_free(CacheFile *cache_file, struct CacheReader **reader)
{
#ifdef WITH_ALEMBIC
BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
if (*reader != NULL) {
CacheReader_free(*reader);
*reader = NULL;
/* Multiple modifiers and constraints can call this function concurrently. */
BLI_spin_lock(&spin);
if (cache_file->handle_readers) {
BLI_gset_remove(cache_file->handle_readers, reader, NULL);
}
BLI_spin_unlock(&spin);
}
#else
UNUSED_VARS(cache_file, reader);
#endif
}
static void cachefile_handle_free(CacheFile *cache_file)
{
#ifdef WITH_ALEMBIC
/* Free readers in all modifiers and constraints that use the handle, before
* we free the handle itself. */
BLI_spin_lock(&spin);
if (cache_file->handle_readers) {
GSetIterator gs_iter;
GSET_ITER (gs_iter, cache_file->handle_readers) {
struct CacheReader **reader = BLI_gsetIterator_getKey(&gs_iter);
if (*reader != NULL) {
CacheReader_free(*reader);
*reader = NULL;
}
}
BLI_gset_free(cache_file->handle_readers, NULL);
cache_file->handle_readers = NULL;
}
BLI_spin_unlock(&spin);
/* Free handle. */
if (cache_file->handle) {
ABC_free_handle(cache_file->handle);
cache_file->handle = NULL;
}
cache_file->handle_filepath[0] = '\0';
#else
UNUSED_VARS(cache_file);
#endif
}
void *BKE_cachefile_add(Main *bmain, const char *name)
{
CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name, 0);
@ -68,37 +162,23 @@ void *BKE_cachefile_add(Main *bmain, const char *name)
void BKE_cachefile_init(CacheFile *cache_file)
{
cache_file->handle = NULL;
cache_file->filepath[0] = '\0';
cache_file->override_frame = false;
cache_file->frame = 0.0f;
cache_file->is_sequence = false;
cache_file->scale = 1.0f;
cache_file->handle_mutex = BLI_mutex_alloc();
BLI_listbase_clear(&cache_file->object_paths);
cache_file->handle = NULL;
cache_file->handle_filepath[0] = '\0';
cache_file->handle_readers = NULL;
}
/** Free (or release) any data used by this cachefile (does not free the cachefile itself). */
void BKE_cachefile_free(CacheFile *cache_file)
{
BKE_animdata_free((ID *)cache_file, false);
if (cache_file->id.tag & LIB_TAG_NO_MAIN) {
/* CoW/no-main copies reuse the existing ArchiveReader and mutex */
return;
}
if (cache_file->handle) {
#ifdef WITH_ALEMBIC
ABC_free_handle(cache_file->handle);
#endif
cache_file->handle = NULL;
}
if (cache_file->handle_mutex) {
BLI_mutex_free(cache_file->handle_mutex);
cache_file->handle_mutex = NULL;
}
cachefile_handle_free(cache_file);
BLI_freelistN(&cache_file->object_paths);
}
@ -117,13 +197,8 @@ void BKE_cachefile_copy_data(Main *UNUSED(bmain),
const CacheFile *UNUSED(cache_file_src),
const int UNUSED(flag))
{
if (cache_file_dst->id.tag & LIB_TAG_NO_MAIN) {
/* CoW/no-main copies reuse the existing ArchiveReader and mutex */
return;
}
cache_file_dst->handle = NULL;
cache_file_dst->handle_mutex = NULL;
cache_file_dst->handle_readers = NULL;
BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_dst->object_paths);
}
@ -139,72 +214,51 @@ void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib
BKE_id_make_local_generic(bmain, &cache_file->id, true, lib_local);
}
void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file)
void BKE_cachefile_reload(Depsgraph *depsgraph, CacheFile *cache_file)
{
/* To force reload, free the handle and tag depsgraph to load it again. */
CacheFile *cache_file_eval = (CacheFile *)DEG_get_evaluated_id(depsgraph, &cache_file->id);
if (cache_file_eval) {
cachefile_handle_free(cache_file_eval);
}
DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE);
}
void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file)
{
BLI_assert(cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE);
/* Compute filepath. */
char filepath[FILE_MAX];
BLI_strncpy(filepath, cache_file->filepath, sizeof(filepath));
BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &cache_file->id));
#ifdef WITH_ALEMBIC
if (cache_file->handle) {
ABC_free_handle(cache_file->handle);
if (!BKE_cachefile_filepath_get(bmain, depsgraph, cache_file, filepath)) {
return;
}
/* Test if filepath change or if we can keep the existing handle. */
if (STREQ(cache_file->handle_filepath, filepath)) {
return;
}
cachefile_handle_free(cache_file);
BLI_freelistN(&cache_file->object_paths);
#ifdef WITH_ALEMBIC
cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX);
#endif
}
void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
{
BLI_spin_lock(&spin);
if (cache_file->handle_mutex == NULL) {
cache_file->handle_mutex = BLI_mutex_alloc();
}
BLI_spin_unlock(&spin);
BLI_mutex_lock(cache_file->handle_mutex);
if (cache_file->handle == NULL) {
/* Assigning to a CoW copy is a bad idea; assign to the original instead. */
BLI_assert((cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
BKE_cachefile_reload(bmain, cache_file);
}
BLI_mutex_unlock(cache_file->handle_mutex);
}
void BKE_cachefile_update_frame(
Main *bmain, struct Depsgraph *depsgraph, Scene *scene, const float ctime, const float fps)
{
CacheFile *cache_file;
char filename[FILE_MAX];
for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
/* TODO: dependency graph should be updated to do drivers on cachefile.
* Execute drivers only, as animation has already been done. */
BKE_animsys_evaluate_animdata(
depsgraph, scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
if (!cache_file->is_sequence) {
continue;
}
const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
BKE_cachefile_clean(bmain, cache_file);
#ifdef WITH_ALEMBIC
ABC_free_handle(cache_file->handle);
cache_file->handle = ABC_create_handle(filename, NULL);
#endif
}
if (DEG_is_active(depsgraph)) {
/* Flush object paths back to original datablock for UI. */
CacheFile *cache_file_orig = (CacheFile *)DEG_get_original_id(&cache_file->id);
BLI_freelistN(&cache_file_orig->object_paths);
BLI_duplicatelist(&cache_file_orig->object_paths, &cache_file->object_paths);
}
}
bool BKE_cachefile_filepath_get(const Main *bmain,
const Depsgraph *depsgraph,
const CacheFile *cache_file,
float frame,
char r_filepath[FILE_MAX])
{
BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
@ -214,6 +268,11 @@ bool BKE_cachefile_filepath_get(const Main *bmain,
int frame_len;
if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
Scene *scene = DEG_get_evaluated_scene(depsgraph);
const float ctime = BKE_scene_frame_get(scene);
const float fps = (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base);
const float frame = BKE_cachefile_time_offset(cache_file, ctime, fps);
char ext[32];
BLI_path_frame_strip(r_filepath, ext);
BLI_path_frame(r_filepath, frame, frame_len);
@ -226,47 +285,9 @@ bool BKE_cachefile_filepath_get(const Main *bmain,
return true;
}
float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const float fps)
float BKE_cachefile_time_offset(const CacheFile *cache_file, const float time, const float fps)
{
const float time_offset = cache_file->frame_offset / fps;
const float frame = (cache_file->override_frame ? cache_file->frame : time);
return cache_file->is_sequence ? frame : frame / fps - time_offset;
}
/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */
void BKE_cachefile_clean(struct Main *bmain, CacheFile *cache_file)
{
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
if (md) {
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
if (cache_file == mcmd->cache_file) {
#ifdef WITH_ALEMBIC
if (mcmd->reader != NULL) {
CacheReader_free(mcmd->reader);
}
#endif
mcmd->reader = NULL;
}
}
for (bConstraint *con = ob->constraints.first; con; con = con->next) {
if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
continue;
}
bTransformCacheConstraint *data = con->data;
if (cache_file == data->cache_file) {
#ifdef WITH_ALEMBIC
if (data->reader != NULL) {
CacheReader_free(data->reader);
}
#endif
data->reader = NULL;
}
}
}
}

View File

@ -4835,13 +4835,9 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa
const float frame = DEG_get_ctime(cob->depsgraph);
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
/* Must always load ABC handle on original. */
CacheFile *cache_file_orig = (CacheFile *)DEG_get_original_id(&cache_file->id);
BKE_cachefile_ensure_handle(G.main, cache_file_orig);
if (!data->reader) {
data->reader = CacheReader_open_alembic_object(
cache_file_orig->handle, data->reader, cob->ob, data->object_path);
if (!data->reader || !STREQ(data->reader_object_path, data->object_path)) {
STRNCPY(data->reader_object_path, data->object_path);
BKE_cachefile_reader_open(cache_file, &data->reader, cob->ob, data->object_path);
}
ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale);
@ -4859,12 +4855,8 @@ static void transformcache_copy(bConstraint *con, bConstraint *srccon)
BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path));
dst->cache_file = src->cache_file;
#ifdef WITH_ALEMBIC
if (dst->reader) {
CacheReader_incref(dst->reader);
}
#endif
dst->reader = NULL;
dst->reader_object_path[0] = '\0';
}
static void transformcache_free(bConstraint *con)
@ -4872,10 +4864,8 @@ static void transformcache_free(bConstraint *con)
bTransformCacheConstraint *data = con->data;
if (data->reader) {
#ifdef WITH_ALEMBIC
CacheReader_free(data->reader);
#endif
data->reader = NULL;
BKE_cachefile_reader_free(data->cache_file, &data->reader);
data->reader_object_path[0] = '\0';
}
}

View File

@ -1565,15 +1565,6 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
BKE_image_editors_update_frame(bmain, scene->r.cfra);
BKE_sound_set_cfra(scene->r.cfra);
DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
/* Update animated cache files for modifiers.
*
* TODO(sergey): Make this a depsgraph node?
*/
BKE_cachefile_update_frame(bmain,
depsgraph,
scene,
ctime,
(((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base));
#ifdef POSE_ANIMATION_WORKAROUND
scene_armature_depsgraph_workaround(bmain, depsgraph);
#endif

View File

@ -3305,7 +3305,8 @@ static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
{
BLI_listbase_clear(&cache_file->object_paths);
cache_file->handle = NULL;
cache_file->handle_mutex = NULL;
cache_file->handle_filepath[0] = '\0';
cache_file->handle_readers = NULL;
/* relink animdata */
cache_file->adt = newdataadr(fd, cache_file->adt);
@ -3739,6 +3740,7 @@ static void direct_link_constraints(FileData *fd, ListBase *lb)
case CONSTRAINT_TYPE_TRANSFORM_CACHE: {
bTransformCacheConstraint *data = con->data;
data->reader = NULL;
data->reader_object_path[0] = '\0';
}
}
}
@ -5745,6 +5747,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
else if (md->type == eModifierType_MeshSequenceCache) {
MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
msmcd->reader = NULL;
msmcd->reader_object_path[0] = '\0';
}
else if (md->type == eModifierType_SurfaceDeform) {
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;

View File

@ -65,6 +65,7 @@ extern "C" {
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_animsys.h"
#include "BKE_cachefile.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
@ -1469,11 +1470,16 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
return;
}
ID *cache_file_id = &cache_file->id;
add_id_node(cache_file_id);
CacheFile *cache_file_cow = get_cow_datablock(cache_file);
/* Animation, */
build_animdata(cache_file_id);
build_parameters(cache_file_id);
/* Cache evaluation itself. */
add_operation_node(cache_file_id, NodeType::CACHE, OperationCode::FILE_CACHE_UPDATE);
add_operation_node(cache_file_id,
NodeType::CACHE,
OperationCode::FILE_CACHE_UPDATE,
function_bind(BKE_cachefile_eval, bmain_, _1, cache_file_cow));
}
void DepsgraphNodeBuilder::build_mask(Mask *mask)

View File

@ -2222,6 +2222,14 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file)
ComponentKey datablock_key(&cache_file->id, NodeType::CACHE);
add_relation(animation_key, datablock_key, "Datablock Animation");
}
/* Cache file updates */
if (cache_file->is_sequence) {
OperationKey cache_update_key(
&cache_file->id, NodeType::CACHE, OperationCode::FILE_CACHE_UPDATE);
TimeSourceKey time_src_key;
add_relation(time_src_key, cache_update_key, "TimeSrc -> Cache File Eval");
}
}
void DepsgraphRelationBuilder::build_mask(Mask *mask)
@ -2329,7 +2337,8 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
continue;
}
int rel_flag = (RELATION_FLAG_NO_FLUSH | RELATION_FLAG_GODMODE);
if (id_type == ID_ME && comp_node->type == NodeType::GEOMETRY) {
if ((id_type == ID_ME && comp_node->type == NodeType::GEOMETRY) ||
(id_type == ID_CF && comp_node->type == NodeType::CACHE)) {
rel_flag &= ~RELATION_FLAG_NO_FLUSH;
}
/* Notes on exceptions:

View File

@ -6711,17 +6711,18 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
uiItemR(row, &fileptr, "override_frame", 0, "Override Frame", ICON_NONE);
row = uiLayoutRow(layout, false);
uiLayoutSetEnabled(row, RNA_boolean_get(&fileptr, "override_frame"));
uiLayoutSetActive(row, RNA_boolean_get(&fileptr, "override_frame"));
uiItemR(row, &fileptr, "frame", 0, "Frame", ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemR(row, &fileptr, "frame_offset", 0, "Frame Offset", ICON_NONE);
uiLayoutSetActive(row, !RNA_boolean_get(&fileptr, "is_sequence"));
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
row = uiLayoutRow(layout, false);
uiLayoutSetEnabled(row, (sbuts->mainb == BCONTEXT_CONSTRAINT));
uiLayoutSetActive(row, (sbuts->mainb == BCONTEXT_CONSTRAINT));
uiItemR(row, &fileptr, "scale", 0, "Scale", ICON_NONE);
/* TODO: unused for now, so no need to expose. */

View File

@ -38,6 +38,8 @@
#include "RNA_access.h"
#include "DEG_depsgraph.h"
#include "UI_interface.h"
#include "WM_api.h"
@ -93,7 +95,7 @@ static int cachefile_open_exec(bContext *C, wmOperator *op)
CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filename), 0);
BLI_strncpy(cache_file->filepath, filename, FILE_MAX);
BKE_cachefile_reload(bmain, cache_file);
DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE);
/* Will be set when running invoke, not exec directly. */
if (op->customdata != NULL) {
@ -137,7 +139,7 @@ void CACHEFILE_OT_open(wmOperatorType *ot)
/* ***************************** Reload Operator **************************** */
static int cachefile_reload_exec(bContext *C, wmOperator *op)
static int cachefile_reload_exec(bContext *C, wmOperator *UNUSED(op))
{
CacheFile *cache_file = CTX_data_edit_cachefile(C);
@ -145,14 +147,10 @@ static int cachefile_reload_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
Main *bmain = CTX_data_main(C);
BLI_freelistN(&cache_file->object_paths);
BKE_cachefile_reload(bmain, cache_file);
Depsgraph *depsgraph = CTX_data_depsgraph(C);
BKE_cachefile_reload(depsgraph, cache_file);
return OPERATOR_FINISHED;
UNUSED_VARS(op);
}
void CACHEFILE_OT_reload(wmOperatorType *ot)

View File

@ -30,10 +30,12 @@
extern "C" {
#endif
struct GSet;
/* CacheFile::flag */
enum {
CACHEFILE_DS_EXPAND = (1 << 0),
CACHEFILE_DIRTY = (1 << 1),
CACHEFILE_UNUSED_0 = (1 << 1),
};
/* CacheFile::draw_flag */
@ -53,9 +55,6 @@ typedef struct CacheFile {
ID id;
struct AnimData *adt;
struct AbcArchiveHandle *handle;
void *handle_mutex;
/** Paths of the objects inside of the Alembic archive referenced by this CacheFile. */
ListBase object_paths;
@ -78,6 +77,11 @@ typedef struct CacheFile {
short draw_flag;
char _pad[4];
/* Runtime */
struct AbcArchiveHandle *handle;
char handle_filepath[1024];
struct GSet *handle_readers;
} CacheFile;
#ifdef __cplusplus

View File

@ -593,9 +593,12 @@ typedef struct bObjectSolverConstraint {
/* Transform matrix cache constraint */
typedef struct bTransformCacheConstraint {
struct CacheFile *cache_file;
struct CacheReader *reader;
/** FILE_MAX. */
char object_path[1024];
/* Runtime. */
struct CacheReader *reader;
char reader_object_path[1024];
} bTransformCacheConstraint;
/* ------------------------------------------ */

View File

@ -1852,12 +1852,15 @@ typedef struct MeshSeqCacheModifierData {
ModifierData modifier;
struct CacheFile *cache_file;
struct CacheReader *reader;
/** 1024 = FILE_MAX. */
char object_path[1024];
char read_flag;
char _pad[7];
/* Runtime. */
struct CacheReader *reader;
char reader_object_path[1024];
} MeshSeqCacheModifierData;
/* MeshSeqCacheModifierData.read_flag */

View File

@ -45,29 +45,12 @@
# include "../../../alembic/ABC_alembic.h"
# endif
static void rna_CacheFile_update(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_CacheFile_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
CacheFile *cache_file = (CacheFile *)ptr->data;
DEG_id_tag_update(&cache_file->id, 0);
DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
UNUSED_VARS(bmain, scene);
}
static void rna_CacheFile_update_handle(Main *bmain, Scene *scene, PointerRNA *ptr)
{
CacheFile *cache_file = ptr->data;
if ((cache_file->flag & CACHEFILE_DIRTY) != 0) {
BKE_cachefile_clean(bmain, cache_file);
BLI_freelistN(&cache_file->object_paths);
cache_file->flag &= ~CACHEFILE_DIRTY;
}
BKE_cachefile_reload(bmain, cache_file);
rna_CacheFile_update(bmain, scene, ptr);
}
static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@ -76,20 +59,6 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P
rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL);
}
static void rna_CacheFile_filename_set(PointerRNA *ptr, const char *value)
{
CacheFile *cache_file = ptr->data;
if (STREQ(cache_file->filepath, value)) {
return;
}
/* Different file is opened, close all readers. */
cache_file->flag |= CACHEFILE_DIRTY;
BLI_strncpy(cache_file->filepath, value, sizeof(cache_file->filepath));
}
#else
/* cachefile.object_paths */
@ -122,9 +91,8 @@ static void rna_def_cachefile(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_FILE);
PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CacheFile_filename_set");
RNA_def_property_ui_text(prop, "File Path", "Path to external displacements file");
RNA_def_property_update(prop, 0, "rna_CacheFile_update_handle");
RNA_def_property_update(prop, 0, "rna_CacheFile_update");
prop = RNA_def_property(srna, "is_sequence", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(

View File

@ -729,22 +729,6 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v
}
}
static void rna_Constraint_transformCache_object_path_update(Main *bmain,
Scene *scene,
PointerRNA *ptr)
{
# ifdef WITH_ALEMBIC
bConstraint *con = (bConstraint *)ptr->data;
bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data;
Object *ob = (Object *)ptr->id.data;
data->reader = CacheReader_open_alembic_object(
data->cache_file->handle, data->reader, ob, data->object_path);
# endif
rna_Constraint_update(bmain, scene, ptr);
}
#else
static const EnumPropertyItem constraint_distance_items[] = {
@ -2902,7 +2886,7 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna)
prop,
"Object Path",
"Path to the object in the Alembic archive used to lookup the transform matrix");
RNA_def_property_update(prop, 0, "rna_Constraint_transformCache_object_path_update");
RNA_def_property_update(prop, 0, "rna_Constraint_update");
}
/* base struct for constraints */

View File

@ -1300,19 +1300,6 @@ static bool rna_SurfaceDeformModifier_is_bound_get(PointerRNA *ptr)
return (((SurfaceDeformModifierData *)ptr->data)->verts != NULL);
}
static void rna_MeshSequenceCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
# ifdef WITH_ALEMBIC
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)ptr->data;
Object *ob = (Object *)ptr->id.data;
mcmd->reader = CacheReader_open_alembic_object(
mcmd->cache_file->handle, mcmd->reader, ob, mcmd->object_path);
# endif
rna_Modifier_update(bmain, scene, ptr);
}
static bool rna_ParticleInstanceModifier_particle_system_poll(PointerRNA *ptr,
const PointerRNA value)
{
@ -5107,7 +5094,7 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
prop,
"Object Path",
"Path to the object in the Alembic archive used to lookup geometric data");
RNA_def_property_update(prop, 0, "rna_MeshSequenceCache_object_path_update");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
static const EnumPropertyItem read_flag_items[] = {
{MOD_MESHSEQ_READ_VERT, "VERT", 0, "Vertex", ""},

View File

@ -18,6 +18,11 @@
* \ingroup modifiers
*/
#include <string.h>
#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "DNA_cachefile_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@ -47,6 +52,9 @@ static void initData(ModifierData *md)
mcmd->cache_file = NULL;
mcmd->object_path[0] = '\0';
mcmd->read_flag = MOD_MESHSEQ_READ_ALL;
mcmd->reader = NULL;
mcmd->reader_object_path[0] = '\0';
}
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
@ -59,6 +67,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
modifier_copyData_generic(md, target, flag);
tmcmd->reader = NULL;
tmcmd->reader_object_path[0] = '\0';
}
static void freeData(ModifierData *md)
@ -66,10 +75,8 @@ static void freeData(ModifierData *md)
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
if (mcmd->reader) {
#ifdef WITH_ALEMBIC
CacheReader_free(mcmd->reader);
#endif
mcmd->reader = NULL;
mcmd->reader_object_path[0] = '\0';
BKE_cachefile_reader_free(mcmd->cache_file, &mcmd->reader);
}
}
@ -93,17 +100,14 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
Mesh *org_mesh = mesh;
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
CacheFile *cache_file = mcmd->cache_file;
const float frame = DEG_get_ctime(ctx->depsgraph);
const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS);
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
const char *err_str = NULL;
CacheFile *cache_file = (CacheFile *)DEG_get_original_id(&mcmd->cache_file->id);
BKE_cachefile_ensure_handle(G.main, cache_file);
if (!mcmd->reader) {
mcmd->reader = CacheReader_open_alembic_object(
cache_file->handle, NULL, ctx->object, mcmd->object_path);
if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) {
STRNCPY(mcmd->reader_object_path, mcmd->object_path);
BKE_cachefile_reader_open(cache_file, &mcmd->reader, ctx->object, mcmd->object_path);
if (!mcmd->reader) {
modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath);
return mesh;