Depsgraph: Only bind ID-data and indices to depsgraph callbacks
authorSergey Sharybin <sergey.vfx@gmail.com>
Tue, 3 Apr 2018 15:23:43 +0000 (17:23 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 4 Apr 2018 07:48:41 +0000 (09:48 +0200)
This is a part of copy-on-write sanitization, to avoid all the checks
which were attempting to keep sub-data pointers intact.

Point is: ID pointers never change for CoW datablocks, but nested
data pointers might change when updating existing copy.

Solution: Only bind ID data pointers and index of sub-data.
This will make CoW datablock 7update function was easier in 2.8.

In master we were only using pose channel pointers in callbacks,
this is exactly what this commit addresses. A linear lookup array
is created on pose evaluation init and is thrown away afterwards.

One thing we might consider doing is to keep indexed array of
poses, similar to chanhash.

Reviewers: campbellbarton

Reviewed By: campbellbarton

Subscribers: dfelinto

Differential Revision: https://developer.blender.org/D3124

source/blender/blenkernel/BKE_armature.h
source/blender/blenkernel/intern/armature_update.c
source/blender/blenloader/intern/readfile.c
source/blender/depsgraph/intern/builder/deg_builder_nodes.h
source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
source/blender/makesdna/DNA_action_types.h

index 60fb79d75d58ef98e2e0b6ef5d43e5da518ad7e3..f6de39c897e14fa5cf50401effd97186eb3d170a 100644 (file)
@@ -169,41 +169,39 @@ void BKE_splineik_execute_tree(struct Scene *scene, struct Object *ob, struct bP
 
 void BKE_pose_eval_init(struct EvaluationContext *eval_ctx,
                         struct Scene *scene,
-                        struct Object *ob,
-                        struct bPose *pose);
+                        struct Object *ob);
 
 void BKE_pose_eval_init_ik(struct EvaluationContext *eval_ctx,
                            struct Scene *scene,
-                           struct Object *ob,
-                           struct bPose *pose);
+                           struct Object *ob);
 
 void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx,
                         struct Scene *scene,
                         struct Object *ob,
-                        struct bPoseChannel *pchan);
+                        int pchan_index);
 
 void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx,
                                    struct Scene *scene,
                                    struct Object *ob,
-                                   struct bPoseChannel *pchan);
+                                   int pchan_index);
 
 void BKE_pose_bone_done(struct EvaluationContext *eval_ctx,
-                        struct bPoseChannel *pchan);
+                        struct Object *ob,
+                        int pchan_index);
 
 void BKE_pose_iktree_evaluate(struct EvaluationContext *eval_ctx,
                               struct Scene *scene,
                               struct Object *ob,
-                              struct bPoseChannel *rootchan);
+                              int rootchan_index);
 
 void BKE_pose_splineik_evaluate(struct EvaluationContext *eval_ctx,
                                 struct Scene *scene,
                                 struct Object *ob,
-                                struct bPoseChannel *rootchan);
+                                int rootchan_index);
 
 void BKE_pose_eval_flush(struct EvaluationContext *eval_ctx,
                          struct Scene *scene,
-                         struct Object *ob,
-                         struct bPose *pose);
+                         struct Object *ob);
 
 void BKE_pose_eval_proxy_copy(struct EvaluationContext *eval_ctx,
                               struct Object *ob);
index 56e9cce182521856ea438a1427e4d0027de4aa42..95a26814e372745bdc9f6d9948a40609d754f4cc 100644 (file)
@@ -553,10 +553,10 @@ void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_roo
 
 void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
                         Scene *UNUSED(scene),
-                        Object *ob,
-                        bPose *pose)
+                        Object *ob)
 {
-       bPoseChannel *pchan;
+       bPose *pose = ob->pose;
+       BLI_assert(pose != NULL);
 
        DEG_debug_print_eval(__func__, ob->id.name, ob);
 
@@ -569,16 +569,21 @@ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
        /* imat is needed for solvers. */
        invert_m4_m4(ob->imat, ob->obmat);
 
-       /* 1. clear flags */
-       for (pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+       const int num_channels = BLI_listbase_count(&pose->chanbase);
+       pose->chan_array = MEM_malloc_arrayN(
+               num_channels, sizeof(bPoseChannel*), "pose->chan_array");
+
+       /* clear flags */
+       int pchan_index = 0;
+       for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
                pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
+               pose->chan_array[pchan_index++] = pchan;
        }
 }
 
 void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
                            Scene *scene,
-                           Object *ob,
-                           bPose *UNUSED(pose))
+                           Object *ob)
 {
        DEG_debug_print_eval(__func__, ob->id.name, ob);
        BLI_assert(ob->type == OB_ARMATURE);
@@ -587,11 +592,11 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
        if (arm->flag & ARM_RESTPOS) {
                return;
        }
-       /* 2a. construct the IK tree (standard IK) */
+       /* construct the IK tree (standard IK) */
        BIK_initialize_tree(scene, ob, ctime);
-       /* 2b. construct the Spline IK trees
+       /* construct the Spline IK trees
         *  - this is not integrated as an IK plugin, since it should be able
-        *        to function in conjunction with standard IK
+        *    to function in conjunction with standard IK
         */
        BKE_pose_splineik_init_tree(scene, ob, ctime);
 }
@@ -599,8 +604,10 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
 void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
                         Scene *scene,
                         Object *ob,
-                        bPoseChannel *pchan)
+                        int pchan_index)
 {
+       BLI_assert(ob->pose != NULL);
+       bPoseChannel *pchan = ob->pose->chan_array[pchan_index];
        DEG_debug_print_eval_subdata(
                __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
        BLI_assert(ob->type == OB_ARMATURE);
@@ -635,8 +642,10 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
 void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
                                    Scene *scene,
                                    Object *ob,
-                                   bPoseChannel *pchan)
+                                   int pchan_index)
 {
+       BLI_assert(ob->pose != NULL);
+       bPoseChannel *pchan = ob->pose->chan_array[pchan_index];
        DEG_debug_print_eval_subdata(
                __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
        bArmature *arm = (bArmature *)ob->data;
@@ -655,8 +664,11 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
 }
 
 void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
-                        bPoseChannel *pchan)
+                        struct Object *ob,
+                        int pchan_index)
 {
+       BLI_assert(ob->pose != NULL);
+       bPoseChannel *pchan = ob->pose->chan_array[pchan_index];
        float imat[4][4];
        DEG_debug_print_eval(__func__, pchan->name, pchan);
        if (pchan->bone) {
@@ -668,8 +680,10 @@ void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
 void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
                               Scene *scene,
                               Object *ob,
-                              bPoseChannel *rootchan)
+                              int rootchan_index)
 {
+       BLI_assert(ob->pose != NULL);
+       bPoseChannel *rootchan = ob->pose->chan_array[rootchan_index];
        DEG_debug_print_eval_subdata(
                __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
        BLI_assert(ob->type == OB_ARMATURE);
@@ -684,9 +698,11 @@ void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
 void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
                                 Scene *scene,
                                 Object *ob,
-                                bPoseChannel *rootchan)
+                                int rootchan_index)
 
 {
+       BLI_assert(ob->pose != NULL);
+       bPoseChannel *rootchan = ob->pose->chan_array[rootchan_index];
        DEG_debug_print_eval_subdata(
                __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
        BLI_assert(ob->type == OB_ARMATURE);
@@ -700,17 +716,23 @@ void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
 
 void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
                          Scene *scene,
-                         Object *ob,
-                         bPose *UNUSED(pose))
+                         Object *ob)
 {
+       bPose *pose = ob->pose;
+       BLI_assert(pose != NULL);
+
        float ctime = BKE_scene_frame_get(scene); /* not accurate... */
        DEG_debug_print_eval(__func__, ob->id.name, ob);
        BLI_assert(ob->type == OB_ARMATURE);
 
-       /* 6. release the IK tree */
+       /* release the IK tree */
        BIK_release_tree(scene, ob, ctime);
 
        ob->recalc &= ~OB_RECALC_ALL;
+
+       BLI_assert(pose->chan_array != NULL);
+       MEM_freeN(pose->chan_array);
+       pose->chan_array = NULL;
 }
 
 void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
index 7b51ddcce920b785ff38db29979a3afedc26e92a..c35e49b801fe10a6f6e4a8026fed748c3b3ebe34 100644 (file)
@@ -5076,6 +5076,7 @@ static void direct_link_pose(FileData *fd, bPose *pose)
        link_list(fd, &pose->agroups);
 
        pose->chanhash = NULL;
+       pose->chan_array = NULL;
 
        for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
                pchan->bone = NULL;
index 9d47dc6bcedcd65c756ff997dd91fb8091b6e1b1..17d2a4ad5583514d17f4a99ec4050247d5fde3c6 100644 (file)
@@ -132,7 +132,7 @@ struct DepsgraphNodeBuilder {
        void build_object_data(Object *object);
        void build_object_transform(Object *object);
        void build_object_constraints(Object *object);
-       void build_pose_constraints(Object *object, bPoseChannel *pchan);
+       void build_pose_constraints(Object *object, bPoseChannel *pchan, int pchan_index);
        void build_rigidbody(Scene *scene);
        void build_particles(Object *object);
        void build_cloth(Object *object);
index 73bbbcfa0b3318d39d2e84fd157cea17835c7fe9..0c7c3d13d9390bb49cfcc42da6697ceee07524da 100644 (file)
@@ -64,16 +64,24 @@ extern "C" {
 
 namespace DEG {
 
-void DepsgraphNodeBuilder::build_pose_constraints(Object *object, bPoseChannel *pchan)
+void DepsgraphNodeBuilder::build_pose_constraints(Object *object,
+                                                  bPoseChannel *pchan,
+                                                  int pchan_index)
 {
        /* create node for constraint stack */
        add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
-                          function_bind(BKE_pose_constraints_evaluate, _1, scene_, object, pchan),
+                          function_bind(BKE_pose_constraints_evaluate,
+                                        _1,
+                                        scene_,
+                                        object,
+                                        pchan_index),
                           DEG_OPCODE_BONE_CONSTRAINTS);
 }
 
 /* IK Solver Eval Steps */
-void DepsgraphNodeBuilder::build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con)
+void DepsgraphNodeBuilder::build_ik_pose(Object *object,
+                                         bPoseChannel *pchan,
+                                         bConstraint *con)
 {
        bKinematicConstraint *data = (bKinematicConstraint *)con->data;
 
@@ -89,14 +97,21 @@ void DepsgraphNodeBuilder::build_ik_pose(Object *object, bPoseChannel *pchan, bC
                return;
        }
 
+       int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan);
        /* Operation node for evaluating/running IK Solver. */
        add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
-                          function_bind(BKE_pose_iktree_evaluate, _1, scene_, object, rootchan),
+                          function_bind(BKE_pose_iktree_evaluate,
+                                        _1,
+                                        scene_,
+                                        object,
+                                        rootchan_index),
                           DEG_OPCODE_POSE_IK_SOLVER);
 }
 
 /* Spline IK Eval Steps */
-void DepsgraphNodeBuilder::build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con)
+void DepsgraphNodeBuilder::build_splineik_pose(Object *object,
+                                               bPoseChannel *pchan,
+                                               bConstraint *con)
 {
        bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
 
@@ -106,8 +121,13 @@ void DepsgraphNodeBuilder::build_splineik_pose(Object *object, bPoseChannel *pch
        /* Operation node for evaluating/running Spline IK Solver.
         * Store the "root bone" of this chain in the solver, so it knows where to start.
         */
+       int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan);
        add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
-                          function_bind(BKE_pose_splineik_evaluate, _1, scene_, object, rootchan),
+                          function_bind(BKE_pose_splineik_evaluate,
+                                        _1,
+                                        scene_,
+                                        object,
+                                        rootchan_index),
                           DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
 }
 
@@ -178,22 +198,32 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
        /* pose eval context */
        op_node = add_operation_node(&object->id,
                                     DEG_NODE_TYPE_EVAL_POSE,
-                                    function_bind(BKE_pose_eval_init, _1, scene_, object, object->pose),
+                                    function_bind(BKE_pose_eval_init,
+                                                  _1,
+                                                  scene_,
+                                                  object),
                                     DEG_OPCODE_POSE_INIT);
        op_node->set_as_entry();
 
        op_node = add_operation_node(&object->id,
                                     DEG_NODE_TYPE_EVAL_POSE,
-                                    function_bind(BKE_pose_eval_init_ik, _1, scene_, object, object->pose),
+                                    function_bind(BKE_pose_eval_init_ik,
+                                                  _1,
+                                                  scene_,
+                                                  object),
                                     DEG_OPCODE_POSE_INIT_IK);
 
        op_node = add_operation_node(&object->id,
                                     DEG_NODE_TYPE_EVAL_POSE,
-                                    function_bind(BKE_pose_eval_flush, _1, scene_, object, object->pose),
+                                    function_bind(BKE_pose_eval_flush,
+                                                  _1,
+                                                  scene_,
+                                                  object),
                                     DEG_OPCODE_POSE_DONE);
        op_node->set_as_exit();
 
        /* bones */
+       int pchan_index = 0;
        LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
                /* Node for bone evaluation. */
                op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, NULL,
@@ -201,7 +231,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
                op_node->set_as_entry();
 
                add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
-                                  function_bind(BKE_pose_eval_bone, _1, scene_, object, pchan),
+                                  function_bind(BKE_pose_eval_bone, _1, scene_, object, pchan_index),
                                   DEG_OPCODE_BONE_POSE_PARENT);
 
                add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
@@ -209,7 +239,10 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
                                   DEG_OPCODE_BONE_READY);
 
                op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
-                                            function_bind(BKE_pose_bone_done, _1, pchan),
+                                            function_bind(BKE_pose_bone_done,
+                                                          _1,
+                                                          object,
+                                                          pchan_index),
                                             DEG_OPCODE_BONE_DONE);
                op_node->set_as_exit();
                /* Custom properties. */
@@ -222,7 +255,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
                }
                /* Constraints. */
                if (pchan->constraints.first != NULL) {
-                       build_pose_constraints(object, pchan);
+                       build_pose_constraints(object, pchan, pchan_index);
                }
                /**
                 * IK Solvers.
@@ -232,7 +265,8 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
                 *   base transforms of a bunch of bones is done)
                 *
                 * Unsolved Issues:
-                * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+                * - Care is needed to ensure that multi-headed trees work out the same
+                *   as in ik-tree building.
                 * - Animated chain-lengths are a problem...
                 */
                LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
@@ -249,6 +283,8 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
                                        break;
                        }
                }
+
+               pchan_index++;
        }
 }
 
index a7f3d27e9d2faba496229740f9f25a81e799ebef..1691038e13ccaf70b3b0af6b5f4cc21554e22dc1 100644 (file)
@@ -377,7 +377,12 @@ typedef enum eRotationModes {
 typedef struct bPose {
        ListBase chanbase;          /* list of pose channels, PoseBones in RNA */
        struct GHash *chanhash;     /* ghash for quicker string lookups */
-       
+
+       /* Flat array of pose channels. It references pointers from
+        * chanbase. Used for quick pose channel lookup from an index.
+        */
+       bPoseChannel **chan_array;
+
        short flag, pad;
        unsigned int proxy_layer;   /* proxy layer: copy from armature, gets synced */
        int pad1;