From 7ec6bca92fd0ee4a3b1dcdf90fdba1f9d0aec11a Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 18 Apr 2019 21:19:57 +0300 Subject: Fix T63332: backup and restore bPoseChannel_Runtime data during COW. --- source/blender/blenkernel/BKE_action.h | 6 +++- source/blender/blenkernel/intern/action.c | 20 ++++++++--- source/blender/blenkernel/intern/armature.c | 6 ++-- source/blender/blenkernel/intern/armature_update.c | 4 +-- source/blender/blenloader/intern/readfile.c | 2 +- .../intern/eval/deg_eval_copy_on_write.cc | 42 ++++++++++++++++++++++ 6 files changed, 67 insertions(+), 13 deletions(-) diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 08237be0a21..69f3070fcba 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -35,6 +35,7 @@ struct bActionGroup; struct bItasc; struct bPose; struct bPoseChannel; +struct bPoseChannel_Runtime; /* Kernel prototypes */ #ifdef __cplusplus @@ -132,7 +133,10 @@ void action_groups_clear_tempflags(struct bAction *act); void BKE_pose_channel_free(struct bPoseChannel *pchan); void BKE_pose_channel_free_ex(struct bPoseChannel *pchan, bool do_id_user); -void BKE_pose_channel_free_bbone_cache(struct bPoseChannel *pchan); +void BKE_pose_channel_runtime_reset(struct bPoseChannel_Runtime *runtime); +void BKE_pose_channel_runtime_free(struct bPoseChannel_Runtime *runtime); + +void BKE_pose_channel_free_bbone_cache(struct bPoseChannel_Runtime *runtime); void BKE_pose_channels_free(struct bPose *pose); void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_user); diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index a3b7df6b020..885ddc5b9c2 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -793,15 +793,25 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user) /* Cached data, for new draw manager rendering code. */ MEM_SAFE_FREE(pchan->draw_data); - /* Cached B-Bone shape data. */ - BKE_pose_channel_free_bbone_cache(pchan); + /* Cached B-Bone shape and other data. */ + BKE_pose_channel_runtime_free(&pchan->runtime); } -/** Deallocates runtime cache of a pose channel's B-Bone shape. */ -void BKE_pose_channel_free_bbone_cache(bPoseChannel *pchan) +/** Clears the runtime cache of a pose channel without free. */ +void BKE_pose_channel_runtime_reset(bPoseChannel_Runtime *runtime) { - bPoseChannel_Runtime *runtime = &pchan->runtime; + memset(runtime, 0, sizeof(*runtime)); +} +/** Deallocates runtime cache of a pose channel */ +void BKE_pose_channel_runtime_free(bPoseChannel_Runtime *runtime) +{ + BKE_pose_channel_free_bbone_cache(runtime); +} + +/** Deallocates runtime cache of a pose channel's B-Bone shape. */ +void BKE_pose_channel_free_bbone_cache(bPoseChannel_Runtime *runtime) +{ runtime->bbone_segments = 0; MEM_SAFE_FREE(runtime->bbone_rest_mats); MEM_SAFE_FREE(runtime->bbone_pose_mats); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 69721651a45..91c760223aa 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -948,9 +948,7 @@ static void allocate_bbone_cache(bPoseChannel *pchan, int segments) bPoseChannel_Runtime *runtime = &pchan->runtime; if (runtime->bbone_segments != segments) { - if (runtime->bbone_segments != 0) { - BKE_pose_channel_free_bbone_cache(pchan); - } + BKE_pose_channel_free_bbone_cache(runtime); runtime->bbone_segments = segments; runtime->bbone_rest_mats = MEM_malloc_arrayN( @@ -1020,7 +1018,7 @@ void BKE_pchan_bbone_segments_cache_copy(bPoseChannel *pchan, bPoseChannel *pcha int segments = runtime_from->bbone_segments; if (segments <= 1) { - BKE_pose_channel_free_bbone_cache(pchan); + BKE_pose_channel_free_bbone_cache(&pchan->runtime); } else { allocate_bbone_cache(pchan, segments); diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index e6e9b561e78..bf33b1c7c50 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -613,7 +613,7 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Objec /* Free B-Bone shape data cache if it's not a B-Bone. */ if (pchan->bone == NULL || pchan->bone->segments <= 1) { - BKE_pose_channel_free_bbone_cache(pchan); + BKE_pose_channel_free_bbone_cache(&pchan->runtime); } } @@ -723,7 +723,7 @@ void BKE_pose_bone_done(struct Depsgraph *depsgraph, struct Object *object, int copy_m4_m4(pchan_orig->constinv, pchan->constinv); BKE_pose_where_is_bone_tail(pchan_orig); if (pchan->bone == NULL || pchan->bone->segments <= 1) { - BKE_pose_channel_free_bbone_cache(pchan_orig); + BKE_pose_channel_free_bbone_cache(&pchan_orig->runtime); } } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 6acf0a76fa9..6e3c459ddda 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5502,7 +5502,7 @@ static void direct_link_pose(FileData *fd, bPose *pose) CLAMP(pchan->rotmode, ROT_MODE_MIN, ROT_MODE_MAX); pchan->draw_data = NULL; - memset(&pchan->runtime, 0, sizeof(pchan->runtime)); + BKE_pose_channel_runtime_reset(&pchan->runtime); } pose->ikdata = NULL; if (pose->ikparam != NULL) { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 01b712fcd87..d134bc1ee2e 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -841,6 +841,9 @@ class ModifierDataBackupID { /* Storage for backed up runtime modifier data. */ typedef map ModifierRuntimeDataBackup; +/* Storage for backed up pose channel runtime data. */ +typedef map PoseChannelRuntimeDataBackup; + struct ObjectRuntimeBackup { ObjectRuntimeBackup() : base_flag(0), base_local_view_bits(0) { @@ -853,16 +856,19 @@ struct ObjectRuntimeBackup { * pointers. */ void init_from_object(Object *object); void backup_modifier_runtime_data(Object *object); + void backup_pose_channel_runtime_data(Object *object); /* Restore all fields to the given object. */ void restore_to_object(Object *object); /* NOTE: Will free all runtime data which has not been restored. */ void restore_modifier_runtime_data(Object *object); + void restore_pose_channel_runtime_data(Object *object); Object_Runtime runtime; short base_flag; unsigned short base_local_view_bits; ModifierRuntimeDataBackup modifier_runtime_data; + PoseChannelRuntimeDataBackup pose_channel_runtime_data; }; void ObjectRuntimeBackup::init_from_object(Object *object) @@ -884,6 +890,8 @@ void ObjectRuntimeBackup::init_from_object(Object *object) base_local_view_bits = object->base_local_view_bits; /* Backup tuntime data of all modifiers. */ backup_modifier_runtime_data(object); + /* Backup runtime data of all pose channels. */ + backup_pose_channel_runtime_data(object); } inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier_data) @@ -905,6 +913,19 @@ void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object) } } +void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object) +{ + if (object->pose != NULL) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + /* This is NULL in Edit mode. */ + if (pchan->orig_pchan != NULL) { + pose_channel_runtime_data[pchan->orig_pchan] = pchan->runtime; + BKE_pose_channel_runtime_reset(&pchan->runtime); + } + } + } +} + void ObjectRuntimeBackup::restore_to_object(Object *object) { Mesh *mesh_orig = object->runtime.mesh_orig; @@ -941,6 +962,7 @@ void ObjectRuntimeBackup::restore_to_object(Object *object) /* Restore modifier's runtime data. * NOTE: Data of unused modifiers will be freed there. */ restore_modifier_runtime_data(object); + restore_pose_channel_runtime_data(object); } void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object) @@ -967,6 +989,26 @@ void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object) } } +void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object) +{ + if (object->pose != NULL) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + /* This is NULL in Edit mode. */ + if (pchan->orig_pchan != NULL) { + PoseChannelRuntimeDataBackup::iterator runtime_data_iterator = + pose_channel_runtime_data.find(pchan->orig_pchan); + if (runtime_data_iterator != pose_channel_runtime_data.end()) { + pchan->runtime = runtime_data_iterator->second; + pose_channel_runtime_data.erase(runtime_data_iterator); + } + } + } + } + for (PoseChannelRuntimeDataBackup::value_type &value : pose_channel_runtime_data) { + BKE_pose_channel_runtime_free(&value.second); + } +} + class RuntimeBackup { public: RuntimeBackup() : drawdata_ptr(NULL) -- cgit v1.2.3