Fix T63332: backup and restore bPoseChannel_Runtime data during COW.

This commit is contained in:
2019-04-18 21:19:57 +03:00
parent 64bcdd65bf
commit 7ec6bca92f
6 changed files with 67 additions and 13 deletions

View File

@@ -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);

View File

@@ -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);
}
/** Clears the runtime cache of a pose channel without free. */
void BKE_pose_channel_runtime_reset(bPoseChannel_Runtime *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 *pchan)
void BKE_pose_channel_free_bbone_cache(bPoseChannel_Runtime *runtime)
{
bPoseChannel_Runtime *runtime = &pchan->runtime;
runtime->bbone_segments = 0;
MEM_SAFE_FREE(runtime->bbone_rest_mats);
MEM_SAFE_FREE(runtime->bbone_pose_mats);

View File

@@ -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);

View File

@@ -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);
}
}
}

View File

@@ -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) {

View File

@@ -841,6 +841,9 @@ class ModifierDataBackupID {
/* Storage for backed up runtime modifier data. */
typedef map<ModifierDataBackupID, void *> ModifierRuntimeDataBackup;
/* Storage for backed up pose channel runtime data. */
typedef map<bPoseChannel *, bPoseChannel_Runtime> 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)