diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-11-07 17:04:08 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-11-07 17:06:39 +0300 |
commit | 7b271d5fc11ada5d5dbd066f0e4523c33933ef51 (patch) | |
tree | 83c73fea29ec392656b6b898d09e873d76c3a0cc /source | |
parent | 4610ca599a778a33b958d196a7782cebd5758072 (diff) |
Depsgraph: Ensure dependency cycle does not clear runtime memory
If there was a dependency cycle involved, it was possible that pchan
array will be freed before all bones are evaluated. Now clear is
done in a dedicated node, which is never a part of dependency cycle.
Diffstat (limited to 'source')
6 files changed, 98 insertions, 52 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 6937fdcac59..23a9afbda31 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -253,16 +253,15 @@ void BKE_pose_splineik_evaluate( struct Object *ob, int rootchan_index); -void BKE_pose_eval_flush( +void BKE_pose_eval_cleanup( struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); -void BKE_pose_eval_proxy_pose_init(struct Depsgraph *depsgraph, - struct Object *object); - -void BKE_pose_eval_proxy_pose_done(struct Depsgraph *depsgraph, - struct Object *object); +void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph, + struct Object *object); +void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph, + struct Object *object); void BKE_pose_eval_proxy_copy_bone( struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index c7c69a74202..2d9e2a0d84b 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -577,6 +577,7 @@ BLI_INLINE bPoseChannel *pose_pchan_get_indexed(Object *ob, int pchan_index) { bPose *pose = ob->pose; BLI_assert(pose != NULL); + BLI_assert(pose->chan_array != NULL); BLI_assert(pchan_index >= 0); BLI_assert(pchan_index < MEM_allocN_len(pose->chan_array) / sizeof(bPoseChannel *)); return pose->chan_array[pchan_index]; @@ -745,9 +746,9 @@ void BKE_pose_splineik_evaluate(struct Depsgraph *depsgraph, BKE_splineik_execute_tree(depsgraph, scene, ob, rootchan, ctime); } -void BKE_pose_eval_flush(struct Depsgraph *depsgraph, - Scene *scene, - Object *ob) +void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph, + Scene *scene, + Object *ob) { bPose *pose = ob->pose; BLI_assert(pose != NULL); @@ -764,7 +765,7 @@ void BKE_pose_eval_flush(struct Depsgraph *depsgraph, pose->chan_array = NULL; } -void BKE_pose_eval_proxy_pose_init(struct Depsgraph *depsgraph, Object *object) +void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph, Object *object) { BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); @@ -772,7 +773,7 @@ void BKE_pose_eval_proxy_pose_init(struct Depsgraph *depsgraph, Object *object) pose_pchan_index_create(object->pose); } -void BKE_pose_eval_proxy_pose_done(struct Depsgraph *depsgraph, Object *object) +void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph, Object *object) { BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 202b3951417..88e5ca9346c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -220,12 +220,17 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) object_cow), DEG_OPCODE_POSE_INIT_IK); + add_operation_node(&object->id, + DEG_NODE_TYPE_EVAL_POSE, + function_bind(BKE_pose_eval_cleanup, + _1, + scene_cow, + object_cow), + DEG_OPCODE_POSE_CLEANUP); + op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, - function_bind(BKE_pose_eval_flush, - _1, - scene_cow, - object_cow), + NULL, DEG_OPCODE_POSE_DONE); op_node->set_as_exit(); /* Bones. */ @@ -323,7 +328,7 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) } op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, - function_bind(BKE_pose_eval_proxy_pose_init, + function_bind(BKE_pose_eval_proxy_init, _1, object_cow), DEG_OPCODE_POSE_INIT); @@ -368,9 +373,13 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) } op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, - function_bind(BKE_pose_eval_proxy_pose_done, + function_bind(BKE_pose_eval_proxy_cleanup, _1, object_cow), + DEG_OPCODE_POSE_CLEANUP); + op_node = add_operation_node(&object->id, + DEG_NODE_TYPE_EVAL_POSE, + NULL, DEG_OPCODE_POSE_DONE); op_node->set_as_exit(); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index 90df53d438f..331b476be2c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -221,8 +221,8 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object, parchan = parchan->parent; } - OperationKey flush_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(solver_key, flush_key, "PoseEval Result-Bone Link"); + OperationKey done_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + add_relation(solver_key, done_key, "PoseEval Result-Bone Link"); } /* Spline IK Eval Steps */ @@ -294,8 +294,8 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object, if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */ } - OperationKey flush_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(solver_key, flush_key, "PoseEval Result-Bone Link"); + OperationKey done_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + add_relation(solver_key, done_key, "PoseEval Result-Bone Link"); } /* Pose/Armature Bones Graph */ @@ -306,20 +306,28 @@ void DepsgraphRelationBuilder::build_rig(Object *object) // TODO: selection status? /* Attach links between pose operations. */ ComponentKey local_transform(&object->id, DEG_NODE_TYPE_TRANSFORM); - OperationKey init_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); - OperationKey init_ik_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK); - OperationKey flush_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(local_transform, init_key, "Local Transform -> Pose Init"); - add_relation(init_key, init_ik_key, "Pose Init -> Pose Init IK"); - add_relation(init_ik_key, flush_key, "Pose Init IK -> Pose Cleanup"); + OperationKey pose_init_key( + &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); + OperationKey pose_init_ik_key( + &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK); + OperationKey pose_cleanup_key( + &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_CLEANUP); + OperationKey pose_done_key( + &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + add_relation( + local_transform, pose_init_key, "Local Transform -> Pose Init"); + add_relation(pose_init_key, pose_init_ik_key, "Pose Init -> Pose Init IK"); + add_relation( + pose_init_ik_key, pose_done_key, "Pose Init IK -> Pose Cleanup"); /* Make sure pose is up-to-date with armature updates. */ build_armature(armature); OperationKey armature_key(&armature->id, DEG_NODE_TYPE_PARAMETERS, DEG_OPCODE_PLACEHOLDER, "Armature Eval"); - add_relation(armature_key, init_key, "Data dependency"); - /* IK Solvers... + add_relation(armature_key, pose_init_key, "Data dependency"); + /* IK Solvers. + * * - These require separate processing steps are pose-level * to be executed between chains of bones (i.e. once the * base transforms of a bunch of bones is done) @@ -377,15 +385,27 @@ void DepsgraphRelationBuilder::build_rig(Object *object) } /* Links between operations for each bone. */ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - OperationKey bone_local_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); - OperationKey bone_pose_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT); - OperationKey bone_ready_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); - OperationKey bone_done_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); + OperationKey bone_local_key(&object->id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_LOCAL); + OperationKey bone_pose_key(&object->id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_POSE_PARENT); + OperationKey bone_ready_key(&object->id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_READY); + OperationKey bone_done_key(&object->id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_DONE); pchan->flag &= ~POSE_DONE; /* Pose init to bone local. */ - add_relation(init_key, bone_local_key, "PoseEval Source-Bone Link"); + add_relation(pose_init_key, bone_local_key, "Pose Init - Bone Local"); /* Local to pose parenting operation. */ - add_relation(bone_local_key, bone_pose_key, "Bone Local - PoseSpace Link"); + add_relation(bone_local_key, bone_pose_key, "Bone Local - Bone Pose"); /* Parent relation. */ if (pchan->parent != NULL) { eDepsOperation_Code parent_key_opcode; @@ -400,7 +420,10 @@ void DepsgraphRelationBuilder::build_rig(Object *object) parent_key_opcode = DEG_OPCODE_BONE_DONE; } - OperationKey parent_key(&object->id, DEG_NODE_TYPE_BONE, pchan->parent->name, parent_key_opcode); + OperationKey parent_key(&object->id, + DEG_NODE_TYPE_BONE, + pchan->parent->name, + parent_key_opcode); add_relation(parent_key, bone_pose_key, "Parent Bone -> Child Bone"); } /* Build constraints. */ @@ -409,34 +432,40 @@ void DepsgraphRelationBuilder::build_rig(Object *object) BuilderWalkUserData data; data.builder = this; BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data); - - /* constraints stack and constraint dependencies */ - build_constraints(&object->id, DEG_NODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map); - - /* pose -> constraints */ - OperationKey constraints_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS); + /* Constraints stack and constraint dependencies. */ + build_constraints(&object->id, + DEG_NODE_TYPE_BONE, + pchan->name, + &pchan->constraints, + &root_map); + /* Pose -> constraints. */ + OperationKey constraints_key(&object->id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_CONSTRAINTS); add_relation(bone_pose_key, constraints_key, "Constraints Stack"); - - /* constraints -> ready */ - // TODO: when constraint stack is exploded, this step should occur before the first IK solver - add_relation(constraints_key, bone_ready_key, "Constraints -> Ready"); + /* Constraints -> ready/ */ + /* TODO(sergey): When constraint stack is exploded, this step should + * occur before the first IK solver. + */ + add_relation( + constraints_key, bone_ready_key, "Constraints -> Ready"); } else { - /* pose -> ready */ + /* Pose -> Ready */ add_relation(bone_pose_key, bone_ready_key, "Pose -> Ready"); } - - /* bone ready -> done + /* Bone ready -> Bone done. * NOTE: For bones without IK, this is all that's needed. * For IK chains however, an additional rel is created from IK * to done, with transitive reduction removing this one.. */ add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); - /* assume that all bones must be done for the pose to be ready * (for deformers) */ - add_relation(bone_done_key, flush_key, "PoseEval Result-Bone Link"); + add_relation(bone_done_key, pose_done_key, "PoseEval Result-Bone Link"); + add_relation(bone_done_key, pose_cleanup_key, "Cleanup dependency"); /* Custom shape. */ if (pchan->custom != NULL) { build_object(NULL, pchan->custom); @@ -455,6 +484,9 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object) OperationKey pose_done_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + OperationKey pose_cleanup_key(&object->id, + DEG_NODE_TYPE_EVAL_POSE, + DEG_OPCODE_POSE_CLEANUP); LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { OperationKey bone_local_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, @@ -474,6 +506,8 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object) add_relation(pose_init_key, bone_local_key, "Pose Init -> Bone Local"); add_relation(bone_local_key, bone_ready_key, "Local -> Ready"); add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); + add_relation( + bone_done_key, pose_cleanup_key, "Bone Done -> Pose Cleanup"); add_relation(bone_done_key, pose_done_key, "Bone Done -> Pose Done"); /* Make sure bone in the proxy is not done before it's FROM is done. */ diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc index 1a0b1e64279..ae1f8db51eb 100644 --- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc +++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc @@ -147,6 +147,7 @@ const char *operationCodeAsString(eDepsOperation_Code opcode) /* Pose. */ STRINGIFY_OPCODE(POSE_INIT); STRINGIFY_OPCODE(POSE_INIT_IK); + STRINGIFY_OPCODE(POSE_CLEANUP); STRINGIFY_OPCODE(POSE_DONE); STRINGIFY_OPCODE(POSE_IK_SOLVER); STRINGIFY_OPCODE(POSE_SPLINE_IK_SOLVER); diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h index f5892f49955..ef64fe8c5fe 100644 --- a/source/blender/depsgraph/intern/depsgraph_types.h +++ b/source/blender/depsgraph/intern/depsgraph_types.h @@ -223,7 +223,9 @@ typedef enum eDepsOperation_Code { DEG_OPCODE_POSE_INIT, /* Initialize IK solver related pose stuff. */ DEG_OPCODE_POSE_INIT_IK, - /* Free IK Trees + Compute Deform Matrices */ + /* Pose is evaluated, and runtime data can be freed. */ + DEG_OPCODE_POSE_CLEANUP, + /* Pose has been fully evaluated and ready to be used by others. */ DEG_OPCODE_POSE_DONE, /* IK/Spline Solvers */ DEG_OPCODE_POSE_IK_SOLVER, |