Depsgraph: Initial support of armatures for copy-on-write
authorSergey Sharybin <sergey.vfx@gmail.com>
Fri, 14 Jul 2017 12:56:54 +0000 (14:56 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Fri, 14 Jul 2017 13:06:50 +0000 (15:06 +0200)
This commit makes simple cases to work, for example:

- IK solver to an external object
- Object with Armature modifier, "parented" to the deforming armature
  (via animation).

More complicated setups (like agent rig) are crashing still.

source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
source/blender/depsgraph/intern/builder/deg_builder_nodes.h
source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc

index 1f8b3ebaa7432f72ee5379378f510b675958b86a..935b8c543ecbbb18aa14203b5a2d33cce0ca4eec 100644 (file)
@@ -445,39 +445,41 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Object *ob)
 void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
 {
        OperationDepsNode *op_node;
+       Scene *scene_cow = get_cow_datablock(scene);
+       Object *ob_cow = get_cow_datablock(ob);
 
        /* local transforms (from transform channels - loc/rot/scale + deltas) */
        op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
-                                    function_bind(BKE_object_eval_local_transform, _1, scene, ob),
+                                    function_bind(BKE_object_eval_local_transform,
+                                                  _1,
+                                                  scene_cow, ob_cow),
                                     DEG_OPCODE_TRANSFORM_LOCAL);
        op_node->set_as_entry();
 
        /* object parent */
-       if (ob->parent) {
+       if (ob->parent != NULL) {
                add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
-                                  function_bind(BKE_object_eval_parent, _1, scene, ob),
+                                  function_bind(BKE_object_eval_parent,
+                                                _1,
+                                                scene_cow, ob_cow),
                                   DEG_OPCODE_TRANSFORM_PARENT);
        }
 
        /* object constraints */
-       if (ob->constraints.first) {
+       if (ob->constraints.first != NULL) {
                build_object_constraints(scene, ob);
        }
 
-       /* Temporary uber-update node, which does everything.
-        * It is for the being we're porting old dependencies into the new system.
-        * We'll get rid of this node as soon as all the granular update functions
-        * are filled in.
-        *
-        * TODO(sergey): Get rid of this node.
-        */
+       /* Rest of transformation update. */
        add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
-                          function_bind(BKE_object_eval_uber_transform, _1, scene, ob),
+                          function_bind(BKE_object_eval_uber_transform,
+                                        _1,
+                                        scene_cow, ob_cow),
                           DEG_OPCODE_OBJECT_UBEREVAL);
 
        /* object transform is done */
        op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
-                                    function_bind(BKE_object_eval_done, _1, ob),
+                                    function_bind(BKE_object_eval_done, _1, ob_cow),
                                     DEG_OPCODE_TRANSFORM_FINAL);
        op_node->set_as_exit();
 }
@@ -503,7 +505,9 @@ void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob)
 {
        /* create node for constraint stack */
        add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
-                          function_bind(BKE_object_eval_constraints, _1, scene, ob),
+                          function_bind(BKE_object_eval_constraints, _1,
+                                        get_cow_datablock(scene),
+                                        get_cow_datablock(ob)),
                           DEG_OPCODE_TRANSFORM_CONSTRAINTS);
 }
 
@@ -514,23 +518,29 @@ void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob)
 void DepsgraphNodeBuilder::build_animdata(ID *id)
 {
        AnimData *adt = BKE_animdata_from_id(id);
-
-       if (adt == NULL)
+       if (adt == NULL) {
                return;
+       }
+       ID *id_cow = get_cow_id(id);
 
        /* animation */
        if (adt->action || adt->nla_tracks.first || adt->drivers.first) {
-               // XXX: Hook up specific update callbacks for special properties which may need it...
+               // XXX: Hook up specific update callbacks for special properties which
+               // may need it...
 
-               /* actions and NLA - as a single unit for now, as it gets complicated to schedule otherwise */
+               /* actions and NLA - as a single unit for now, as it gets complicated to
+                * schedule otherwise.
+                */
                if ((adt->action) || (adt->nla_tracks.first)) {
                        /* create the node */
                        add_operation_node(id, DEG_NODE_TYPE_ANIMATION,
-                                          function_bind(BKE_animsys_eval_animdata, _1, id),
+                                          function_bind(BKE_animsys_eval_animdata, _1, id_cow),
                                           DEG_OPCODE_ANIMATION, id->name);
 
-                       // TODO: for each channel affected, we might also want to add some support for running RNA update callbacks on them
-                       // (which will be needed for proper handling of drivers later)
+                       /* TODO: for each channel affected, we might also want to add some
+                        * support for running RNA update callbacks on them
+                        * (which will be needed for proper handling of drivers later)
+                        */
                }
 
                /* drivers */
@@ -549,6 +559,7 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
 OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
 {
        ChannelDriver *driver = fcu->driver;
+       ID *id_cow = get_cow_id(id);
 
        /* Create data node for this driver */
        /* TODO(sergey): Avoid creating same operation multiple times,
@@ -562,9 +573,10 @@ OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
                                                           fcu->array_index);
 
        if (driver_op == NULL) {
+               /* TODO(sergey): Shall we use COW of fcu itself here? */
                driver_op = add_operation_node(id,
                                               DEG_NODE_TYPE_PARAMETERS,
-                                              function_bind(BKE_animsys_eval_driver, _1, id, fcu),
+                                              function_bind(BKE_animsys_eval_driver, _1, id_cow, fcu),
                                               DEG_OPCODE_DRIVER,
                                               fcu->rna_path ? fcu->rna_path : "",
                                               fcu->array_index);
@@ -608,43 +620,49 @@ void DepsgraphNodeBuilder::build_world(World *world)
 void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
 {
        RigidBodyWorld *rbw = scene->rigidbody_world;
+       Scene *scene_cow = get_cow_datablock(scene);
 
        /**
         * Rigidbody Simulation Nodes
         * ==========================
         *
         * There are 3 nodes related to Rigidbody Simulation:
-        * 1) "Initialize/Rebuild World" - this is called sparingly, only when the simulation
-        *    needs to be rebuilt (mainly after file reload, or moving back to start frame)
-        * 2) "Do Simulation" - perform a simulation step - interleaved between the evaluation
-        *    steps for clusters of objects (i.e. between those affected and/or not affected by
-        *    the sim for instance)
+        * 1) "Initialize/Rebuild World" - this is called sparingly, only when the
+        *    simulation needs to be rebuilt (mainly after file reload, or moving
+        *    back to start frame)
+        * 2) "Do Simulation" - perform a simulation step - interleaved between the
+        *    evaluation steps for clusters of objects (i.e. between those affected
+        *    and/or not affected by the sim for instance).
         *
-        * 3) "Pull Results" - grab the specific transforms applied for a specific object -
-        *    performed as part of object's transform-stack building
+        * 3) "Pull Results" - grab the specific transforms applied for a specific
+        *    object - performed as part of object's transform-stack building.
         */
 
-       /* create nodes ------------------------------------------------------------------------ */
-       /* XXX: is this the right component, or do we want to use another one instead? */
+       /* Create nodes --------------------------------------------------------- */
+
+       /* XXX: is this the right component, or do we want to use another one
+        * instead?
+        */
 
        /* init/rebuild operation */
-       /*OperationDepsNode *init_node =*/ add_operation_node(&scene->id, DEG_NODE_TYPE_TRANSFORM,
-                                                             function_bind(BKE_rigidbody_rebuild_sim, _1, scene),
-                                                             DEG_OPCODE_RIGIDBODY_REBUILD);
+       /*OperationDepsNode *init_node =*/ add_operation_node(
+               &scene->id, DEG_NODE_TYPE_TRANSFORM,
+               function_bind(BKE_rigidbody_rebuild_sim, _1, scene_cow),
+               DEG_OPCODE_RIGIDBODY_REBUILD);
 
        /* do-sim operation */
        // XXX: what happens if we need to split into several groups?
-       OperationDepsNode *sim_node     = add_operation_node(&scene->id, DEG_NODE_TYPE_TRANSFORM,
-                                                            function_bind(BKE_rigidbody_eval_simulation, _1, scene),
-                                                            DEG_OPCODE_RIGIDBODY_SIM);
+       OperationDepsNode *sim_node = add_operation_node(
+               &scene->id, DEG_NODE_TYPE_TRANSFORM,
+               function_bind(BKE_rigidbody_eval_simulation, _1, scene_cow),
+               DEG_OPCODE_RIGIDBODY_SIM);
 
-       /* XXX: For now, the sim node is the only one that really matters here. If any other
-        * sims get added later, we may have to remove these hacks...
+       /* XXX: For now, the sim node is the only one that really matters here.
+        * If any other sims get added later, we may have to remove these hacks...
         */
        sim_node->owner->entry_operation = sim_node;
        sim_node->owner->exit_operation  = sim_node;
 
-
        /* objects - simulation participants */
        if (rbw->group) {
                LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) {
@@ -654,9 +672,13 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
                                continue;
 
                        /* 2) create operation for flushing results */
-                       /* object's transform component - where the rigidbody operation lives */
+                       /* object's transform component - where the rigidbody operation
+                        * lives. */
                        add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
-                                          function_bind(BKE_rigidbody_object_sync_transforms, _1, scene, ob),
+                                          function_bind(BKE_rigidbody_object_sync_transforms,
+                                                        _1,
+                                                        scene_cow,
+                                                        get_cow_datablock(ob)),
                                           DEG_OPCODE_TRANSFORM_RIGIDBODY);
                }
        }
@@ -683,6 +705,10 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
        ComponentDepsNode *psys_comp =
                add_component_node(&ob->id, DEG_NODE_TYPE_EVAL_PARTICLES);
 
+       /* TODO(sergey): Need to get COW of PSYS. */
+       Scene *scene_cow = get_cow_datablock(scene);
+       Object *ob_cow = get_cow_datablock(ob);
+
        /* particle systems */
        LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
                ParticleSettings *part = psys->part;
@@ -696,8 +722,8 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
                add_operation_node(psys_comp,
                                   function_bind(BKE_particle_system_eval,
                                                 _1,
-                                                scene,
-                                                ob,
+                                                scene_cow,
+                                                ob_cow,
                                                 psys),
                                   DEG_OPCODE_PSYS_EVAL,
                                   psys->name);
@@ -709,13 +735,16 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
 
 void DepsgraphNodeBuilder::build_cloth(Scene *scene, Object *object)
 {
+       Scene *scene_cow = get_cow_datablock(scene);
+       Object *object_cow = get_cow_datablock(object);
+
        ComponentDepsNode *cache_comp = add_component_node(&object->id,
                                                           DEG_NODE_TYPE_CACHE);
        add_operation_node(cache_comp,
                           function_bind(BKE_object_eval_cloth,
                                         _1,
-                                        scene,
-                                        object),
+                                        scene_cow,
+                                        object_cow),
                           DEG_OPCODE_PLACEHOLDER,
                           "Cloth Modifier");
 }
@@ -734,7 +763,10 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
 void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
 {
        ID *obdata = (ID *)ob->data;
+       ID *obdata_cow = get_cow_id(obdata);
        OperationDepsNode *op_node;
+       Scene *scene_cow = get_cow_datablock(scene);
+       Object *object_cow = get_cow_datablock(ob);
 
        /* TODO(sergey): This way using this object's properties as driver target
         * works fine.
@@ -759,8 +791,8 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
                                     DEG_NODE_TYPE_GEOMETRY,
                                     function_bind(BKE_object_eval_uber_data,
                                                   _1,
-                                                  (Scene *)get_cow_id(&scene->id),
-                                                  (Object *)get_cow_id(&ob->id)),
+                                                  scene_cow,
+                                                  object_cow),
                                     DEG_OPCODE_GEOMETRY_UBEREVAL);
        op_node->set_as_exit();
 
@@ -785,7 +817,8 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
                if (ob->type == OB_MESH) {
                        add_operation_node(&ob->id,
                                           DEG_NODE_TYPE_SHADING,
-                                          function_bind(BKE_object_eval_update_shading, _1, ob),
+                                          function_bind(BKE_object_eval_update_shading, _1,
+                                                        object_cow),
                                           DEG_OPCODE_SHADING);
                }
 
@@ -827,7 +860,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
                                                     DEG_NODE_TYPE_GEOMETRY,
                                                     function_bind(BKE_mesh_eval_geometry,
                                                                   _1,
-                                                                  (Mesh *)obdata),
+                                                                  (Mesh *)obdata_cow),
                                                     DEG_OPCODE_PLACEHOLDER,
                                                     "Geometry Eval");
                        op_node->set_as_entry();
@@ -846,7 +879,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
                                                             DEG_NODE_TYPE_GEOMETRY,
                                                             function_bind(BKE_mball_eval_geometry,
                                                                           _1,
-                                                                          (MetaBall *)obdata),
+                                                                          (MetaBall *)obdata_cow),
                                                             DEG_OPCODE_PLACEHOLDER,
                                                             "Geometry Eval");
                                op_node->set_as_entry();
@@ -864,7 +897,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
                                                     DEG_NODE_TYPE_GEOMETRY,
                                                     function_bind(BKE_curve_eval_geometry,
                                                                   _1,
-                                                                  (Curve *)obdata),
+                                                                  (Curve *)obdata_cow),
                                                                   DEG_OPCODE_PLACEHOLDER,
                                                                   "Geometry Eval");
                        op_node->set_as_entry();
@@ -875,7 +908,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
                                                   DEG_NODE_TYPE_GEOMETRY,
                                                   function_bind(BKE_curve_eval_path,
                                                                 _1,
-                                                                (Curve *)obdata),
+                                                                (Curve *)obdata_cow),
                                                   DEG_OPCODE_GEOMETRY_PATH,
                                                   "Path");
                        }
@@ -903,7 +936,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
                                                     DEG_NODE_TYPE_GEOMETRY,
                                                     function_bind(BKE_lattice_eval_geometry,
                                                                   _1,
-                                                                  (Lattice *)obdata),
+                                                                  (Lattice *)obdata_cow),
                                                                   DEG_OPCODE_PLACEHOLDER,
                                                                   "Geometry Eval");
                        op_node->set_as_entry();
index 54ad1bd5d8a7e4ded97b8feda258d8db6c0b60fe..81fbbb07bc883b5797084f80bf6e94361343ca6d 100644 (file)
@@ -75,6 +75,11 @@ struct DepsgraphNodeBuilder {
 
        ID *get_cow_id(const ID *id_orig) const;
 
+       template<typename T>
+       T *get_cow_datablock(const T *orig) const {
+               return (T *)get_cow_id(&orig->id);
+       }
+
        IDDepsNode *add_id_node(ID *id);
        TimeSourceDepsNode *add_time_source();
 
index 51b27912298b3aca39e6baf5294684a621300e60..69f02603f40963bca1b9dfb9261577dd86156545 100644 (file)
@@ -46,6 +46,7 @@ extern "C" {
 #include "DNA_armature_types.h"
 #include "DNA_constraint_types.h"
 #include "DNA_object_types.h"
+#include "DNA_scene_types.h"
 
 #include "BKE_action.h"
 #include "BKE_armature.h"
@@ -55,6 +56,7 @@ extern "C" {
 #include "DEG_depsgraph_build.h"
 
 #include "intern/builder/deg_builder.h"
+#include "intern/eval/deg_eval_copy_on_write.h"
 #include "intern/nodes/deg_node.h"
 #include "intern/nodes/deg_node_component.h"
 #include "intern/nodes/deg_node_operation.h"
@@ -64,16 +66,25 @@ extern "C" {
 
 namespace DEG {
 
-void DepsgraphNodeBuilder::build_pose_constraints(Scene *scene, Object *ob, bPoseChannel *pchan)
+void DepsgraphNodeBuilder::build_pose_constraints(Scene *scene,
+                                                  Object *ob,
+                                                  bPoseChannel *pchan)
 {
        /* create node for constraint stack */
        add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
-                          function_bind(BKE_pose_constraints_evaluate, _1, scene, ob, pchan),
+                          function_bind(BKE_pose_constraints_evaluate,
+                                        _1,
+                                        get_cow_datablock(scene),
+                                        get_cow_datablock(ob),
+                                        pchan),
                           DEG_OPCODE_BONE_CONSTRAINTS);
 }
 
 /* IK Solver Eval Steps */
-void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
+void DepsgraphNodeBuilder::build_ik_pose(Scene *scene,
+                                         Object *ob,
+                                         bPoseChannel *pchan,
+                                         bConstraint *con)
 {
        bKinematicConstraint *data = (bKinematicConstraint *)con->data;
 
@@ -88,12 +99,18 @@ void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel
 
        /* Operation node for evaluating/running IK Solver. */
        add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
-                          function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
+                          function_bind(BKE_pose_iktree_evaluate, _1,
+                                        get_cow_datablock(scene),
+                                        get_cow_datablock(ob),
+                                        rootchan),
                           DEG_OPCODE_POSE_IK_SOLVER);
 }
 
 /* Spline IK Eval Steps */
-void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
+void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene,
+                                               Object *ob,
+                                               bPoseChannel *pchan,
+                                               bConstraint *con)
 {
        bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
 
@@ -101,30 +118,55 @@ void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseCh
        bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
 
        /* Operation node for evaluating/running Spline IK Solver.
-        * Store the "root bone" of this chain in the solver, so it knows where to start.
+        * Store the "root bone" of this chain in the solver, so it knows where to
+        * start.
         */
        add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
-                          function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
+                          function_bind(BKE_pose_splineik_evaluate,
+                                        _1,
+                                        get_cow_datablock(scene),
+                                        get_cow_datablock(ob),
+                                        rootchan),
                           DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
 }
 
 /* Pose/Armature Bones Graph */
-void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
+void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *object)
 {
-       bArmature *arm = (bArmature *)ob->data;
+       bArmature *armature = (bArmature *)object->data;
+       const bool armature_tag = armature->id.tag;
+#ifdef WITH_COPY_ON_WRITE
+       /* NOTE: We need to expand both object and armature, so this way we can
+        * safely create object level pose.
+        */
+       Scene *scene_cow = get_cow_datablock(scene);
+       IDDepsNode *object_id_node = add_id_node(&object->id);
+       Object *object_cow = (Object *)deg_expand_copy_on_write_datablock(
+               m_graph, object_id_node);
+       IDDepsNode *armature_id_node = add_id_node(&armature->id);
+       bArmature *armature_cow = (bArmature *)deg_expand_copy_on_write_datablock(
+               m_graph, armature_id_node);
+#else
+       Scene *scene_cow = scene;
+       Object *object_cow = object;
+       bArmature *armature_cow = armature;
+#endif
        OperationDepsNode *op_node;
 
-       /* animation and/or drivers linking posebones to base-armature used to define them
+       /* Animation and/or drivers linking posebones to base-armature used to
+        * define them.
+        *
         * NOTE: AnimData here is really used to control animated deform properties,
-        *       which ideally should be able to be unique across different instances.
-        *       Eventually, we need some type of proxy/isolation mechanism in-between here
-        *       to ensure that we can use same rig multiple times in same scene...
+        *       which ideally should be able to be unique across different
+        *       instances. Eventually, we need some type of proxy/isolation
+        *       mechanism in-between here to ensure that we can use same rig
+        *       multiple times in same scene.
         */
-       if ((arm->id.tag & LIB_TAG_DOIT) == 0) {
-               build_animdata(&arm->id);
+       if ((armature_tag & LIB_TAG_DOIT) == 0) {
+               build_animdata(&armature->id);
 
                /* Make sure pose is up-to-date with armature updates. */
-               add_operation_node(&arm->id,
+               add_operation_node(&armature->id,
                                   DEG_NODE_TYPE_PARAMETERS,
                                   NULL,
                                   DEG_OPCODE_PLACEHOLDER,
@@ -132,22 +174,22 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
        }
 
        /* Rebuild pose if not up to date. */
-       if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
-               BKE_pose_rebuild(ob, arm);
+       if (object_cow->pose == NULL || (object->pose->flag & POSE_RECALC)) {
+               BKE_pose_rebuild(object_cow, armature_cow);
                /* XXX: Without this animation gets lost in certain circumstances
                 * after loading file. Need to investigate further since it does
                 * not happen with simple scenes..
                 */
-               if (ob->adt) {
-                       ob->adt->recalc |= ADT_RECALC_ANIM;
+               if (object_cow->adt) {
+                       object_cow->adt->recalc |= ADT_RECALC_ANIM;
                }
        }
 
        /* speed optimization for animation lookups */
-       if (ob->pose) {
-               BKE_pose_channels_hash_make(ob->pose);
-               if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
-                       BKE_pose_update_constraint_flags(ob->pose);
+       if (object_cow->pose != NULL) {
+               BKE_pose_channels_hash_make(object_cow->pose);
+               if (object_cow->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+                       BKE_pose_update_constraint_flags(object_cow->pose);
                }
        }
 
@@ -168,47 +210,59 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
         * - Used for representing each bone within the rig
         * - Acts to encapsulate the evaluation operations (base matrix + parenting,
         *   and constraint stack) so that they can be easily found.
-        * - Everything else which depends on bone-results hook up to the component only
-        *   so that we can redirect those to point at either the the post-IK/
+        * - Everything else which depends on bone-results hook up to the component
+        *   only so that we can redirect those to point at either the the post-IK/
         *   post-constraint/post-matrix steps, as needed.
         */
 
        /* pose eval context */
-       op_node = add_operation_node(&ob->id,
+       op_node = add_operation_node(&object->id,
                                     DEG_NODE_TYPE_EVAL_POSE,
-                                    function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose),
+                                    function_bind(BKE_pose_eval_init,
+                                                  _1,
+                                                  scene_cow,
+                                                  object_cow,
+                                                  object_cow->pose),
                                     DEG_OPCODE_POSE_INIT);
        op_node->set_as_entry();
 
-       op_node = add_operation_node(&ob->id,
+       op_node = add_operation_node(&object->id,
                                     DEG_NODE_TYPE_EVAL_POSE,
-                                    function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose),
+                                    function_bind(BKE_pose_eval_flush,
+                                                  _1,
+                                                  scene_cow,
+                                                  object_cow,
+                                                  object_cow->pose),
                                     DEG_OPCODE_POSE_DONE);
        op_node->set_as_exit();
 
        /* bones */
-       LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+       LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
                /* node for bone eval */
-               op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, NULL,
-                                            DEG_OPCODE_BONE_LOCAL);
+               op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE,
+                                            pchan->name, NULL, DEG_OPCODE_BONE_LOCAL);
                op_node->set_as_entry();
 
-               add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
-                                  function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan),
+               add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
+                                  function_bind(BKE_pose_eval_bone, _1,
+                                                scene_cow,
+                                                object_cow,
+                                                pchan),
                                   DEG_OPCODE_BONE_POSE_PARENT);
 
-               add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
-                                  NULL, /* NOTE: dedicated noop for easier relationship construction */
+               /* NOTE: Dedicated noop for easier relationship construction. */
+               add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
+                                  NULL,
                                   DEG_OPCODE_BONE_READY);
 
-               op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
+               op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
                                             function_bind(BKE_pose_bone_done, _1, pchan),
                                             DEG_OPCODE_BONE_DONE);
                op_node->set_as_exit();
 
                /* constraints */
                if (pchan->constraints.first != NULL) {
-                       build_pose_constraints(scene, ob, pchan);
+                       build_pose_constraints(scene, object, pchan);
                }
 
                /**
@@ -219,17 +273,18 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
                 *   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
-                * - Animated chain-lengths are a problem...
+                * - Care is needed to ensure that multi-headed trees work out the same
+                *   as in ik-tree building
+                * - Animated chain-lengths are a problem.
                 */
                LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) {
                        switch (con->type) {
                                case CONSTRAINT_TYPE_KINEMATIC:
-                                       build_ik_pose(scene, ob, pchan, con);
+                                       build_ik_pose(scene, object, pchan, con);
                                        break;
 
                                case CONSTRAINT_TYPE_SPLINEIK:
-                                       build_splineik_pose(scene, ob, pchan, con);
+                                       build_splineik_pose(scene, object, pchan, con);
                                        break;
 
                                default:
index e2c1ef5c220f387345f9ab97dcbe6f7c671f802a..663caf5d716f6880f0038533e6fc87091b380866 100644 (file)
@@ -308,11 +308,22 @@ int foreach_libblock_remap_callback(void *user_data,
 }
 
 /* Check whether given ID is expanded or still a shallow copy. */
-BLI_INLINE bool check_datablock_expanded(ID *id_cow)
+BLI_INLINE bool check_datablock_expanded(const ID *id_cow)
 {
        return (id_cow->name[0] != '\0');
 }
 
+/* Check whether datablock was already expanded during depsgraph
+ * construction.
+ */
+static bool check_datablock_expanded_at_construction(const ID *id_orig)
+{
+       const short id_type = GS(id_orig->name);
+       return (id_type == ID_SCE) ||
+              (id_type == ID_OB && ((Object *)id_orig)->type == OB_ARMATURE) ||
+              (id_type == ID_AR);
+}
+
 /* Do some special treatment of data transfer from original ID to it's
  * CoW complementary part.
  *
@@ -423,6 +434,7 @@ void update_copy_on_write_datablock(const Depsgraph *depsgraph,
                // - Active render engine.
                // - Something else?
        }
+       // TODO(sergey): Other ID types here.
 }
 
 /* This callback is used to validate that all nested ID datablocks are
@@ -549,7 +561,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
         * construction time. This datablocks must never change pointers of their
         * nested data since it is used for function bindings.
         */
-       if (GS(id_orig->name) == ID_SCE) {
+       if (check_datablock_expanded_at_construction(id_orig)) {
                BLI_assert(check_datablock_expanded(id_cow) == true);
                update_copy_on_write_datablock(depsgraph, id_orig, id_cow);
                return id_cow;