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.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user