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:
2018-11-07 15:04:08 +01:00
parent 4610ca599a
commit 7b271d5fc1
6 changed files with 98 additions and 52 deletions

View File

@@ -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,

View File

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

View File

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

View File

@@ -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. */

View File

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

View File

@@ -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,