Merge branch 'master' into blender2.8
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 5 Apr 2018 16:25:05 +0000 (18:25 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 5 Apr 2018 16:25:05 +0000 (18:25 +0200)
1  2 
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

index 565218d8be009dececbfede8c18c3ee01045b934,7b2914303cec179888a65b3ff6d868d7b9d00d78..eff6b34fee6f88deb540da20fafdf75539b34630
@@@ -62,7 -62,6 +62,7 @@@ extern "C" 
  #include "DNA_node_types.h"
  #include "DNA_particle_types.h"
  #include "DNA_object_types.h"
 +#include "DNA_lightprobe_types.h"
  #include "DNA_rigidbody_types.h"
  #include "DNA_scene_types.h"
  #include "DNA_texture_types.h"
@@@ -73,6 -72,7 +73,6 @@@
  #include "BKE_animsys.h"
  #include "BKE_constraint.h"
  #include "BKE_curve.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_effect.h"
  #include "BKE_fcurve.h"
  #include "BKE_idcode.h"
@@@ -90,7 -90,6 +90,7 @@@
  #include "BKE_node.h"
  #include "BKE_object.h"
  #include "BKE_particle.h"
 +#include "BKE_pointcache.h"
  #include "BKE_rigidbody.h"
  #include "BKE_sound.h"
  #include "BKE_tracking.h"
  #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_id.h"
  
  namespace DEG {
  
- struct BuilderWalkUserData {
-       DepsgraphNodeBuilder *builder;
- };
- static void modifier_walk(void *user_data,
-                           struct Object * /*object*/,
-                           struct ID **idpoin,
-                           int /*cb_flag*/)
- {
-       BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
-       ID *id = *idpoin;
-       if (id == NULL) {
-               return;
-       }
-       switch (GS(id->name)) {
-               case ID_OB:
-                       data->builder->build_object(NULL,
-                                                   (Object *)id,
-                                                   DEG_ID_LINKED_INDIRECTLY);
-                       break;
-               case ID_TE:
-                       data->builder->build_texture((Tex *)id);
-                       break;
-               default:
-                       /* pass */
-                       break;
-       }
- }
- void constraint_walk(bConstraint * /*con*/,
-                      ID **idpoin,
-                      bool /*is_reference*/,
-                      void *user_data)
- {
-       BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
-       if (*idpoin) {
-               ID *id = *idpoin;
-               if (GS(id->name) == ID_OB) {
-                       data->builder->build_object(NULL,
-                                                   (Object *)id,
-                                                   DEG_ID_LINKED_INDIRECTLY);
-               }
-       }
- }
 +namespace {
 +
 +void free_copy_on_write_datablock(void *id_v)
 +{
 +      ID *id = (ID *)id_v;
 +      deg_free_copy_on_write_datablock(id);
 +      MEM_freeN(id);
 +}
 +
 +}  /* namespace */
 +
  /* ************ */
  /* Node Builder */
  
  DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph)
      : bmain_(bmain),
        graph_(graph),
 -      scene_(NULL)
 +      scene_(NULL),
 +      cow_id_hash_(NULL)
  {
  }
  
  DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
  {
 +      if (cow_id_hash_ != NULL) {
 +              BLI_ghash_free(cow_id_hash_, NULL, free_copy_on_write_datablock);
 +      }
  }
  
  IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id)
  {
 -      return graph_->add_id_node(id, id->name);
 +      if (!DEG_depsgraph_use_copy_on_write()) {
 +              return graph_->add_id_node(id);
 +      }
 +      IDDepsNode *id_node = NULL;
 +      ID *id_cow = (ID *)BLI_ghash_lookup(cow_id_hash_, id);
 +      if (id_cow != NULL) {
 +              /* TODO(sergey): Is it possible to lookup and pop element from GHash
 +               * at the same time?
 +               */
 +              BLI_ghash_remove(cow_id_hash_, id, NULL, NULL);
 +      }
 +      id_node = graph_->add_id_node(id, id_cow);
 +      /* Currently all ID nodes are supposed to have copy-on-write logic.
 +       *
 +       * NOTE: Zero number of components indicates that ID node was just created.
 +       */
 +      if (BLI_ghash_len(id_node->components) == 0) {
 +              ComponentDepsNode *comp_cow =
 +                      id_node->add_component(DEG_NODE_TYPE_COPY_ON_WRITE);
 +              OperationDepsNode *op_cow = comp_cow->add_operation(
 +                      function_bind(deg_evaluate_copy_on_write, _1, graph_, id_node),
 +                      DEG_OPCODE_COPY_ON_WRITE,
 +                      "", -1);
 +              graph_->operations.push_back(op_cow);
 +      }
 +      return id_node;
 +}
 +
 +IDDepsNode *DepsgraphNodeBuilder::find_id_node(ID *id)
 +{
 +      return graph_->find_id_node(id);
  }
  
  TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source()
@@@ -351,145 -259,51 +306,145 @@@ OperationDepsNode *DepsgraphNodeBuilder
        return find_operation_node(id, comp_type, "", opcode, name, name_tag);
  }
  
 +ID *DepsgraphNodeBuilder::get_cow_id(const ID *id_orig) const
 +{
 +      return graph_->get_cow_id(id_orig);
 +}
 +
 +ID *DepsgraphNodeBuilder::ensure_cow_id(ID *id_orig)
 +{
 +      if (id_orig->tag & LIB_TAG_COPY_ON_WRITE) {
 +              /* ID is already remapped to copy-on-write. */
 +              return id_orig;
 +      }
 +      IDDepsNode *id_node = add_id_node(id_orig);
 +      return id_node->id_cow;
 +}
 +
 +ID *DepsgraphNodeBuilder::expand_cow_id(IDDepsNode *id_node)
 +{
 +      return deg_expand_copy_on_write_datablock(graph_, id_node, this, true);
 +}
 +
 +ID *DepsgraphNodeBuilder::expand_cow_id(ID *id_orig)
 +{
 +      IDDepsNode *id_node = add_id_node(id_orig);
 +      return expand_cow_id(id_node);
 +}
 +
  /* **** Build functions for entity nodes **** */
  
  void DepsgraphNodeBuilder::begin_build() {
 +      if (DEG_depsgraph_use_copy_on_write()) {
 +              /* Store existing copy-on-write versions of datablock, so we can re-use
 +               * them for new ID nodes.
 +               */
 +              cow_id_hash_ = BLI_ghash_ptr_new("Depsgraph id hash");
 +              foreach (IDDepsNode *id_node, graph_->id_nodes) {
 +                      if (deg_copy_on_write_is_expanded(id_node->id_cow)) {
 +                              if (id_node->id_orig == id_node->id_cow) {
 +                                      continue;
 +                              }
 +                              BLI_ghash_insert(cow_id_hash_,
 +                                               id_node->id_orig,
 +                                               id_node->id_cow);
 +                              id_node->id_cow = NULL;
 +                      }
 +              }
 +      }
 +
 +      GSET_FOREACH_BEGIN(OperationDepsNode *, op_node, graph_->entry_tags)
 +      {
 +              ComponentDepsNode *comp_node = op_node->owner;
 +              IDDepsNode *id_node = comp_node->owner;
 +
 +              SavedEntryTag entry_tag;
 +              entry_tag.id = id_node->id_orig;
 +              entry_tag.component_type = comp_node->type;
 +              entry_tag.opcode = op_node->opcode;
 +              saved_entry_tags_.push_back(entry_tag);
 +      };
 +      GSET_FOREACH_END();
 +
 +      /* Make sure graph has no nodes left from previous state. */
 +      graph_->clear_all_nodes();
 +      graph_->operations.clear();
 +      BLI_gset_clear(graph_->entry_tags, NULL);
 +}
 +
 +void DepsgraphNodeBuilder::end_build()
 +{
 +      foreach (const SavedEntryTag& entry_tag, saved_entry_tags_) {
 +              IDDepsNode *id_node = find_id_node(entry_tag.id);
 +              if (id_node == NULL) {
 +                      continue;
 +              }
 +              ComponentDepsNode *comp_node =
 +                      id_node->find_component(entry_tag.component_type);
 +              if (comp_node == NULL) {
 +                      continue;
 +              }
 +              OperationDepsNode *op_node = comp_node->find_operation(entry_tag.opcode);
 +              if (op_node == NULL) {
 +                      continue;
 +              }
 +              op_node->tag_update(graph_);
 +      }
  }
  
 -void DepsgraphNodeBuilder::build_group(Base *base, Group *group)
 +void DepsgraphNodeBuilder::build_group(Group *group)
  {
        if (built_map_.checkIsBuiltAndTag(group)) {
                return;
        }
 -      LISTBASE_FOREACH (GroupObject *, go, &group->gobject) {
 -              build_object(base, go->ob);
 +      /* Build group objects. */
 +      LISTBASE_FOREACH (Base *, base, &group->view_layer->object_bases) {
 +              build_object(NULL, base->object, DEG_ID_LINKED_INDIRECTLY);
        }
 +      /* Operation to evaluate the whole view layer.
 +       *
 +       * NOTE: We re-use DONE opcode even though the function does everything.
 +       * This way we wouldn't need to worry about possible relations from DONE,
 +       * regardless whether it's a group or scene or something else.
 +       */
 +      add_id_node(&group->id);
 +      Group *group_cow = get_cow_datablock(group);
 +      add_operation_node(&group->id,
 +                         DEG_NODE_TYPE_LAYER_COLLECTIONS,
 +                         function_bind(BKE_group_eval_view_layers,
 +                                       _1,
 +                                       group_cow),
 +                         DEG_OPCODE_VIEW_LAYER_DONE);
  }
  
 -void DepsgraphNodeBuilder::build_object(Base *base, Object *object)
 +void DepsgraphNodeBuilder::build_object(Base *base,
 +                                        Object *object,
 +                                        eDepsNode_LinkedState_Type linked_state)
  {
        const bool has_object = built_map_.checkIsBuiltAndTag(object);
 -      IDDepsNode *id_node = (has_object)
 -              ? graph_->find_id_node(&object->id)
 -              : add_id_node(&object->id);
 -      /* Update node layers.
 -       * Do it for both new and existing ID nodes. This is so because several
 -       * bases might be sharing same object.
 -       */
 -      if (base != NULL) {
 -              id_node->layers |= base->lay;
 -      }
 -      if (object->type == OB_CAMERA) {
 -              /* Camera should always be updated, it used directly by viewport.
 -               *
 -               * TODO(sergey): Make it only for active scene camera.
 -               */
 -              id_node->layers |= (unsigned int)(-1);
 -      }
        /* Skip rest of components if the ID node was already there. */
        if (has_object) {
 +              IDDepsNode *id_node = find_id_node(&object->id);
 +              /* We need to build some extra stuff if object becomes linked
 +               * directly.
 +               */
 +              if (id_node->linked_state == DEG_ID_LINKED_INDIRECTLY) {
 +                      build_object_flags(base, object, linked_state);
 +              }
 +              id_node->linked_state = max(id_node->linked_state, linked_state);
                return;
        }
 +      /* Create ID node for object and begin init. */
 +      IDDepsNode *id_node = add_id_node(&object->id);
 +      id_node->linked_state = linked_state;
        object->customdata_mask = 0;
 +      /* Various flags, flushing from bases/collections. */
 +      build_object_flags(base, object, linked_state);
        /* Transform. */
        build_object_transform(object);
        /* Parent. */
        if (object->parent != NULL) {
 -              build_object(NULL, object->parent);
 +              build_object(NULL, object->parent, DEG_ID_LINKED_INDIRECTLY);
        }
        /* Modifiers. */
        if (object->modifiers.first != NULL) {
        /* Object that this is a proxy for. */
        if (object->proxy) {
                object->proxy->proxy_from = object;
 -              build_object(base, object->proxy);
 +              build_object(NULL, object->proxy, DEG_ID_LINKED_INDIRECTLY);
        }
        /* Object dupligroup. */
        if (object->dup_group != NULL) {
 -              build_group(base, object->dup_group);
 +              build_group(object->dup_group);
        }
  }
  
 +void DepsgraphNodeBuilder::build_object_flags(
 +        Base *base,
 +        Object *object,
 +        eDepsNode_LinkedState_Type linked_state)
 +{
 +      if (base == NULL) {
 +              return;
 +      }
 +      /* TODO(sergey): Is this really best component to be used? */
 +      Object *object_cow = get_cow_datablock(object);
 +      const bool is_from_set = (linked_state == DEG_ID_LINKED_VIA_SET);
 +      add_operation_node(&object->id,
 +                         DEG_NODE_TYPE_LAYER_COLLECTIONS,
 +                         function_bind(BKE_object_eval_flush_base_flags,
 +                                       _1, object_cow, base, is_from_set),
 +                         DEG_OPCODE_OBJECT_BASE_FLAGS);
 +}
 +
  void DepsgraphNodeBuilder::build_object_data(Object *object)
  {
        if (object->data == NULL) {
                return;
        }
        IDDepsNode *id_node = graph_->find_id_node(&object->id);
 -      /* type-specific data... */
 +      /* type-specific data. */
        switch (object->type) {
 -              case OB_MESH:     /* Geometry */
 +              case OB_MESH:
                case OB_CURVE:
                case OB_FONT:
                case OB_SURF:
                case OB_CAMERA:
                        build_camera(object);
                        break;
 +              case OB_LIGHTPROBE:
 +                      build_lightprobe(object);
 +                      break;
                default:
                {
                        ID *obdata = (ID *)object->data;
  void DepsgraphNodeBuilder::build_object_transform(Object *object)
  {
        OperationDepsNode *op_node;
 +      Scene *scene_cow = get_cow_datablock(scene_);
 +      Object *ob_cow = get_cow_datablock(object);
  
        /* local transforms (from transform channels - loc/rot/scale + deltas) */
        op_node = add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
 -                                   function_bind(BKE_object_eval_local_transform, _1, object),
 +                                   function_bind(BKE_object_eval_local_transform,
 +                                                 _1,
 +                                                 ob_cow),
                                     DEG_OPCODE_TRANSFORM_LOCAL);
        op_node->set_as_entry();
  
        /* object parent */
 -      if (object->parent) {
 +      if (object->parent != NULL) {
                add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
 -                                 function_bind(BKE_object_eval_parent, _1, scene_, object),
 +                                 function_bind(BKE_object_eval_parent,
 +                                               _1,
 +                                               scene_cow,
 +                                               ob_cow),
                                   DEG_OPCODE_TRANSFORM_PARENT);
        }
  
        /* object constraints */
 -      if (object->constraints.first) {
 +      if (object->constraints.first != NULL) {
                build_object_constraints(object);
        }
  
 -      /* 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(&object->id, DEG_NODE_TYPE_TRANSFORM,
 -                         function_bind(BKE_object_eval_uber_transform, _1, object),
 +                         function_bind(BKE_object_eval_uber_transform,
 +                                       _1,
 +                                       ob_cow),
                           DEG_OPCODE_TRANSFORM_OBJECT_UBEREVAL);
  
        /* object transform is done */
        op_node = add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
 -                                   function_bind(BKE_object_eval_done, _1, object),
 +                                   function_bind(BKE_object_eval_done,
 +                                                 _1,
 +                                                 ob_cow),
                                     DEG_OPCODE_TRANSFORM_FINAL);
        op_node->set_as_exit();
  }
@@@ -673,10 -461,7 +628,10 @@@ void DepsgraphNodeBuilder::build_object
  {
        /* create node for constraint stack */
        add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
 -                         function_bind(BKE_object_eval_constraints, _1, scene_, object),
 +                         function_bind(BKE_object_eval_constraints,
 +                                       _1,
 +                                       get_cow_datablock(scene_),
 +                                       get_cow_datablock(object)),
                           DEG_OPCODE_TRANSFORM_CONSTRAINTS);
  }
  
  void DepsgraphNodeBuilder::build_animdata(ID *id)
  {
        AnimData *adt = BKE_animdata_from_id(id);
 -
 -      if (adt == NULL)
 +      if (adt == NULL) {
                return;
 +      }
  
        /* animation */
        if (adt->action || adt->nla_tracks.first || adt->drivers.first) {
 -              // XXX: Hook up specific update callbacks for special properties which may need it...
 +              (void) add_id_node(id);
 +              ID *id_cow = get_cow_id(id);
  
 -              /* actions and NLA - as a single unit for now, as it gets complicated to schedule otherwise */
 +              // 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.
 +               */
                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),
 -                                         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)
 +                                         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)
 +                       */
                }
  
                /* drivers */
   */
  void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve)
  {
 +      ID *id_cow = get_cow_id(id);
 +
        /* Create data node for this driver */
 +      /* TODO(sergey): Shall we use COW of fcu itself here? */
        ensure_operation_node(id,
                              DEG_NODE_TYPE_PARAMETERS,
 -                            function_bind(BKE_animsys_eval_driver, _1, id, fcurve),
 +                            function_bind(BKE_animsys_eval_driver, _1, id_cow, fcurve),
                              DEG_OPCODE_DRIVER,
                              fcurve->rna_path ? fcurve->rna_path : "",
                              fcurve->array_index);
@@@ -789,19 -560,17 +744,19 @@@ void DepsgraphNodeBuilder::build_world(
        if (built_map_.checkIsBuiltAndTag(world)) {
                return;
        }
 -      ID *world_id = &world->id;
 -      build_animdata(world_id);
 +      /* Animation. */
 +      build_animdata(&world->id);
        /* world itself */
 -      add_operation_node(world_id,
 -                         DEG_NODE_TYPE_PARAMETERS,
 -                         NULL,
 -                         DEG_OPCODE_PARAMETERS_EVAL);
 +      add_operation_node(&world->id,
 +                         DEG_NODE_TYPE_SHADING,
 +                         function_bind(BKE_world_eval,
 +                                       _1,
 +                                       get_cow_datablock(world)),
 +                         DEG_OPCODE_WORLD_UPDATE);
        /* textures */
        build_texture_stack(world->mtex);
        /* world's nodetree */
 -      if (world->nodetree) {
 +      if (world->nodetree != NULL) {
                build_nodetree(world->nodetree);
        }
  }
  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) {
 -              LISTBASE_FOREACH (GroupObject *, go, &rbw->group->gobject) {
 -                      Object *object = go->ob;
 +              LISTBASE_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) {
 +                      Object *object = base->object;
  
                        if (!object || (object->type != OB_MESH))
                                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(&object->id, DEG_NODE_TYPE_TRANSFORM,
 -                                         function_bind(BKE_rigidbody_object_sync_transforms, _1, scene, object),
 +                                         function_bind(
 +                                                 BKE_rigidbody_object_sync_transforms,
 +                                                 _1,
 +                                                 scene_cow,
 +                                                 get_cow_datablock(object)),
                                           DEG_OPCODE_RIGIDBODY_TRANSFORM_COPY);
                }
        }
@@@ -894,26 -652,20 +849,26 @@@ void DepsgraphNodeBuilder::build_partic
        /* Component for all particle systems. */
        ComponentDepsNode *psys_comp =
                add_component_node(&object->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(object);
 +
        add_operation_node(psys_comp,
                           function_bind(BKE_particle_system_eval_init,
                                         _1,
 -                                       scene_,
 -                                       object),
 +                                       scene_cow,
 +                                       ob_cow),
                           DEG_OPCODE_PARTICLE_SYSTEM_EVAL_INIT);
        /* Build all particle systems. */
        LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
                ParticleSettings *part = psys->part;
 -              /* Particle settings. */
 -              // XXX: what if this is used more than once!
 -              build_animdata(&part->id);
 -              /* This particle system evaluation. */
 -              // TODO: for now, this will just be a placeholder "ubereval" node
 +              /* Build particle settings operations.
 +               *
 +               * NOTE: The call itself ensures settings are only build once.
 +               */
 +              build_particle_settings(part);
 +              /* Particle system evaluation. */
                add_operation_node(psys_comp,
                                   NULL,
                                   DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
                switch (part->ren_as) {
                        case PART_DRAW_OB:
                                if (part->dup_ob != NULL) {
 -                                      build_object(NULL, part->dup_ob);
 +                                      build_object(NULL,
 +                                                   part->dup_ob,
 +                                                   DEG_ID_LINKED_INDIRECTLY);
                                }
                                break;
                        case PART_DRAW_GR:
                                if (part->dup_group != NULL) {
 -                                      build_group(NULL, part->dup_group);
 +                                      build_group(part->dup_group);
                                }
                                break;
                }
        }
  
 -      /* pointcache */
 -      // TODO...
 +      /* TODO(sergey): Do we need a point cache operations here? */
 +      add_operation_node(&object->id,
 +                         DEG_NODE_TYPE_CACHE,
 +                         function_bind(BKE_ptcache_object_reset,
 +                                       scene_cow,
 +                                       ob_cow,
 +                                       PTCACHE_RESET_DEPSGRAPH),
 +                         DEG_OPCODE_POINT_CACHE_RESET);
 +}
 +
 +void DepsgraphNodeBuilder::build_particle_settings(ParticleSettings *part) {
 +      if (built_map_.checkIsBuiltAndTag(part)) {
 +              return;
 +      }
 +      /* Animation data. */
 +      build_animdata(&part->id);
 +      /* Parameters change. */
 +      add_operation_node(&part->id,
 +                         DEG_NODE_TYPE_PARAMETERS,
 +                         NULL,
 +                         DEG_OPCODE_PARTICLE_SETTINGS_EVAL);
  }
  
  void DepsgraphNodeBuilder::build_cloth(Object *object)
  {
 +      Scene *scene_cow = get_cow_datablock(scene_);
 +      Object *object_cow = get_cow_datablock(object);
        add_operation_node(&object->id,
                           DEG_NODE_TYPE_CACHE,
                           function_bind(BKE_object_eval_cloth,
                                         _1,
 -                                       scene_,
 -                                       object),
 +                                       scene_cow,
 +                                       object_cow),
                           DEG_OPCODE_GEOMETRY_CLOTH_MODIFIER);
  }
  
@@@ -985,9 -714,8 +940,9 @@@ void DepsgraphNodeBuilder::build_shapek
  // XXX: what happens if the datablock is shared!
  void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
  {
 -      ID *obdata = (ID *)object->data;
        OperationDepsNode *op_node;
 +      Scene *scene_cow = get_cow_datablock(scene_);
 +      Object *object_cow = get_cow_datablock(object);
  
        /* Temporary uber-update node, which does everything.
         * It is for the being we're porting old dependencies into the new system.
                                     DEG_NODE_TYPE_GEOMETRY,
                                     function_bind(BKE_object_eval_uber_data,
                                                   _1,
 -                                                 scene_,
 -                                                 object),
 +                                                 scene_cow,
 +                                                 object_cow),
                                     DEG_OPCODE_GEOMETRY_UBEREVAL);
        op_node->set_as_exit();
  
        }
  
        /* materials */
 -      for (int a = 1; a <= object->totcol; a++) {
 -              Material *ma = give_current_material(object, a);
 -              if (ma != NULL) {
 -                      build_material(ma);
 +      if (object->totcol != 0) {
 +              if (object->type == OB_MESH) {
 +                      add_operation_node(&object->id,
 +                                         DEG_NODE_TYPE_SHADING,
 +                                         function_bind(BKE_object_eval_update_shading,
 +                                                       _1,
 +                                                       object_cow),
 +                                         DEG_OPCODE_SHADING);
 +              }
 +
 +              for (int a = 1; a <= object->totcol; a++) {
 +                      Material *ma = give_current_material(object, a);
 +                      if (ma != NULL) {
 +                              build_material(ma);
 +                      }
                }
        }
  
                // add geometry collider relations
        }
  
 +      ID *obdata = (ID *)object->data;
        if (built_map_.checkIsBuiltAndTag(obdata)) {
                return;
        }
 +      /* Make sure we've got an ID node before requesting CoW pointer. */
 +      (void) add_id_node((ID *)obdata);
 +      ID *obdata_cow = get_cow_id(obdata);
  
        /* ShapeKeys */
        Key *key = BKE_key_from_object(object);
                                                     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();
                                /* metaball evaluation operations */
                                op_node = add_operation_node(obdata,
                                                             DEG_NODE_TYPE_GEOMETRY,
 -                                                           function_bind(BKE_mball_eval_geometry,
 -                                                                         _1,
 -                                                                         (MetaBall *)obdata),
 +                                                           function_bind(
 +                                                                   BKE_mball_eval_geometry,
 +                                                                   _1,
 +                                                                   (MetaBall *)obdata_cow),
                                                             DEG_OPCODE_PLACEHOLDER,
                                                             "Geometry Eval");
                        }
                                                     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();
 -
                        /* Make sure objects used for bevel.taper are in the graph.
                         * NOTE: This objects might be not linked to the scene.
                         */
                        Curve *cu = (Curve *)obdata;
                        if (cu->bevobj != NULL) {
 -                              build_object(NULL, cu->bevobj);
 +                              build_object(NULL, cu->bevobj, DEG_ID_LINKED_INDIRECTLY);
                        }
                        if (cu->taperobj != NULL) {
 -                              build_object(NULL, cu->taperobj);
 +                              build_object(NULL, cu->taperobj, DEG_ID_LINKED_INDIRECTLY);
                        }
                        if (object->type == OB_FONT && cu->textoncurve != NULL) {
 -                              build_object(NULL, cu->textoncurve);
 +                              build_object(NULL, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY);
                        }
                        break;
                }
                                                     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();
                           DEG_NODE_TYPE_PARAMETERS,
                           NULL,
                           DEG_OPCODE_PARAMETERS_EVAL);
 +
 +      /* Batch cache. */
 +      add_operation_node(obdata,
 +                         DEG_NODE_TYPE_BATCH_CACHE,
 +                         function_bind(BKE_object_data_select_update,
 +                                       _1,
 +                                       obdata_cow),
 +                         DEG_OPCODE_GEOMETRY_SELECT_UPDATE);
  }
  
  /* Cameras */
  void DepsgraphNodeBuilder::build_camera(Object *object)
  {
 +      /* Object data. */
        /* TODO: Link scene-camera links in somehow... */
        Camera *camera = (Camera *)object->data;
        if (built_map_.checkIsBuiltAndTag(camera)) {
                           DEG_NODE_TYPE_PARAMETERS,
                           NULL,
                           DEG_OPCODE_PARAMETERS_EVAL);
 -      if (camera->dof_ob != NULL) {
 -              /* TODO(sergey): For now parametrs are on object level. */
 -              add_operation_node(&object->id, DEG_NODE_TYPE_PARAMETERS, NULL,
 -                                 DEG_OPCODE_PLACEHOLDER, "Camera DOF");
 -      }
  }
  
  /* Lamps */
  void DepsgraphNodeBuilder::build_lamp(Object *object)
  {
 +      /* Object data. */
        Lamp *lamp = (Lamp *)object->data;
        if (built_map_.checkIsBuiltAndTag(lamp)) {
                return;
        }
        build_animdata(&lamp->id);
 -      /* TODO(sergey): Is it really how we're supposed to work with drivers? */
        add_operation_node(&lamp->id,
                           DEG_NODE_TYPE_PARAMETERS,
                           NULL,
@@@ -1216,26 -925,16 +1171,26 @@@ void DepsgraphNodeBuilder::build_nodetr
        if (built_map_.checkIsBuiltAndTag(ntree)) {
                return;
        }
 -
        /* nodetree itself */
 -      OperationDepsNode *op_node;
 +      add_id_node(&ntree->id);
 +      bNodeTree *ntree_cow = get_cow_datablock(ntree);
 +      /* Animation, */
        build_animdata(&ntree->id);
 -      /* Parameters for drivers. */
 -      op_node = add_operation_node(&ntree->id,
 -                                   DEG_NODE_TYPE_PARAMETERS,
 -                                   NULL,
 -                                   DEG_OPCODE_PARAMETERS_EVAL);
 -      op_node->set_as_exit();
 +      /* Shading update. */
 +      add_operation_node(&ntree->id,
 +                         DEG_NODE_TYPE_SHADING,
 +                         NULL,
 +                         DEG_OPCODE_MATERIAL_UPDATE);
 +      /* NOTE: We really pass original and CoW node trees here, this is how the
 +       * callback works. Ideally we need to find a better way for that.
 +       */
 +      add_operation_node(&ntree->id,
 +                         DEG_NODE_TYPE_SHADING_PARAMETERS,
 +                         function_bind(BKE_nodetree_shading_params_eval,
 +                                       _1,
 +                                       ntree_cow,
 +                                       ntree),
 +                         DEG_OPCODE_MATERIAL_UPDATE);
        /* nodetree's nodes... */
        LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
                ID *id = bnode->id;
                        build_image((Image *)id);
                }
                else if (id_type == ID_OB) {
 -                      build_object(NULL, (Object *)id);
 +                      build_object(NULL, (Object *)id, DEG_ID_LINKED_INDIRECTLY);
                }
                else if (id_type == ID_SCE) {
                        /* Scenes are used by compositor trees, and handled by render
@@@ -1281,33 -980,27 +1236,33 @@@ void DepsgraphNodeBuilder::build_materi
        if (built_map_.checkIsBuiltAndTag(material)) {
                return;
        }
 -      add_operation_node(&material->id, DEG_NODE_TYPE_SHADING, NULL,
 -                         DEG_OPCODE_PLACEHOLDER, "Material Update");
 -
 -      /* material animation */
 +      /* Material itself. */
 +      add_id_node(&material->id);
 +      Material *material_cow = get_cow_datablock(material);
 +      /* Shading update. */
 +      add_operation_node(&material->id,
 +                         DEG_NODE_TYPE_SHADING,
 +                         function_bind(BKE_material_eval,
 +                                       _1,
 +                                       material_cow),
 +                         DEG_OPCODE_MATERIAL_UPDATE);
 +      /* Material animation. */
        build_animdata(&material->id);
 -      /* textures */
 +      /* Textures. */
        build_texture_stack(material->mtex);
 -      /* material's nodetree */
 +      /* Material's nodetree. */
        build_nodetree(material->nodetree);
  }
  
  /* Texture-stack attached to some shading datablock */
  void DepsgraphNodeBuilder::build_texture_stack(MTex **texture_stack)
  {
 -      int i;
 -
        /* for now assume that all texture-stacks have same number of max items */
 -      for (i = 0; i < MAX_MTEX; i++) {
 +      for (int i = 0; i < MAX_MTEX; i++) {
                MTex *mtex = texture_stack[i];
 -              if (mtex && mtex->tex)
 +              if (mtex && mtex->tex) {
                        build_texture(mtex->tex);
 +              }
        }
  }
  
@@@ -1353,9 -1046,7 +1308,9 @@@ void DepsgraphNodeBuilder::build_compos
        // XXX: component type undefined!
        //graph->get_node(&scene->id, NULL, DEG_NODE_TYPE_COMPOSITING, NULL);
  
 -      /* for now, nodetrees are just parameters; compositing occurs in internals of renderer... */
 +      /* for now, nodetrees are just parameters; compositing occurs in internals
 +       * of renderer...
 +       */
        add_component_node(&scene->id, DEG_NODE_TYPE_PARAMETERS);
        build_nodetree(scene->nodetree);
  }
@@@ -1387,53 -1078,75 +1342,102 @@@ void DepsgraphNodeBuilder::build_cachef
  void DepsgraphNodeBuilder::build_mask(Mask *mask)
  {
        ID *mask_id = &mask->id;
 +      Mask *mask_cow = get_cow_datablock(mask);
        /* F-Curve based animation. */
        build_animdata(mask_id);
        /* Animation based on mask's shapes. */
        add_operation_node(mask_id,
                           DEG_NODE_TYPE_ANIMATION,
 -                         function_bind(BKE_mask_eval_animation, _1, mask),
 +                         function_bind(BKE_mask_eval_animation, _1, mask_cow),
                           DEG_OPCODE_MASK_ANIMATION);
        /* Final mask evaluation. */
        add_operation_node(mask_id,
                           DEG_NODE_TYPE_PARAMETERS,
 -                         function_bind(BKE_mask_eval_update, _1, mask),
 +                         function_bind(BKE_mask_eval_update, _1, mask_cow),
                           DEG_OPCODE_MASK_EVAL);
  }
  
 -void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) {
 +void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip)
 +{
        ID *clip_id = &clip->id;
 +      MovieClip *clip_cow = get_cow_datablock(clip);
        /* Animation. */
        build_animdata(clip_id);
        /* Movie clip evaluation. */
        add_operation_node(clip_id,
                           DEG_NODE_TYPE_PARAMETERS,
 -                         function_bind(BKE_movieclip_eval_update, _1, clip),
 +                         function_bind(BKE_movieclip_eval_update, _1, clip_cow),
                           DEG_OPCODE_MOVIECLIP_EVAL);
  }
  
 -                      data->builder->build_object(NULL, (Object *)id);
 +void DepsgraphNodeBuilder::build_lightprobe(Object *object)
 +{
 +      LightProbe *probe = (LightProbe *)object->data;
 +      if (built_map_.checkIsBuiltAndTag(probe)) {
 +              return;
 +      }
 +      /* Placeholder so we can add relations and tag ID node for update. */
 +      add_operation_node(&probe->id,
 +                         DEG_NODE_TYPE_PARAMETERS,
 +                         NULL,
 +                         DEG_OPCODE_PLACEHOLDER,
 +                         "LightProbe Eval");
 +      add_operation_node(&object->id,
 +                         DEG_NODE_TYPE_PARAMETERS,
 +                         NULL,
 +                         DEG_OPCODE_PLACEHOLDER,
 +                         "LightProbe Eval");
 +
 +      build_animdata(&probe->id);
 +}
 +
+ /* **** ID traversal callbacks functions **** */
+ void DepsgraphNodeBuilder::modifier_walk(void *user_data,
+                                          struct Object * /*object*/,
+                                          struct ID **idpoin,
+                                          int /*cb_flag*/)
+ {
+       BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+       ID *id = *idpoin;
+       if (id == NULL) {
+               return;
+       }
+       switch (GS(id->name)) {
+               case ID_OB:
 -                      data->builder->build_object(NULL, (Object *)id);
++                      data->builder->build_object(NULL,
++                                                  (Object *)id,
++                                                  DEG_ID_LINKED_INDIRECTLY);
+                       break;
+               case ID_TE:
+                       data->builder->build_texture((Tex *)id);
+                       break;
+               default:
+                       /* pass */
+                       break;
+       }
+ }
+ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/,
+                                            ID **idpoin,
+                                            bool /*is_reference*/,
+                                            void *user_data)
+ {
+       BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
+       ID *id = *idpoin;
+       if (id == NULL) {
+               return;
+       }
+       switch (GS(id->name)) {
+               case ID_OB:
 -
++                      data->builder->build_object(NULL,
++                                                  (Object *)id,
++                                                  DEG_ID_LINKED_INDIRECTLY);
+                       break;
+               default:
+                       /* pass */
+                       break;
+       }
+ }
  }  // namespace DEG
index 8dfbc4fa37ca04a0ead0a18687b07f0cd328a63e,d64aee11536af550f1955cb6d67f3f6a472f8196..fd72ae527b84a027d913dd70863ebb16b46f174c
@@@ -33,8 -33,6 +33,8 @@@
  #include "intern/builder/deg_builder_map.h"
  #include "intern/depsgraph_types.h"
  
 +#include "DEG_depsgraph.h"  /* used for DEG_depsgraph_use_copy_on_write() */
 +
  struct Base;
  struct CacheFile;
  struct bGPdata;
@@@ -45,7 -43,6 +45,7 @@@ struct Image
  struct FCurve;
  struct Group;
  struct Key;
 +struct LayerCollection;
  struct Main;
  struct Material;
  struct Mask;
@@@ -53,8 -50,6 +53,8 @@@ struct MTex
  struct MovieClip;
  struct bNodeTree;
  struct Object;
 +struct ParticleSettings;
 +struct Probe;
  struct bPoseChannel;
  struct bConstraint;
  struct Scene;
@@@ -76,45 -71,9 +76,45 @@@ struct DepsgraphNodeBuilder 
        DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
        ~DepsgraphNodeBuilder();
  
 +      /* For given original ID get ID which is created by CoW system. */
 +      ID *get_cow_id(const ID *id_orig) const;
 +      /* Similar to above, but for the cases when there is no ID node we create
 +       * one.
 +       */
 +      ID *ensure_cow_id(ID *id_orig);
 +
 +      /* Helper wrapper function which wraps get_cow_id with a needed type cast. */
 +      template<typename T>
 +      T *get_cow_datablock(const T *orig) const {
 +              return (T *)get_cow_id(&orig->id);
 +      }
 +
 +      /* Get fully expanded (ready for use) copy-on-write datablock for the given
 +       * original datablock.
 +       */
 +      ID *expand_cow_id(IDDepsNode *id_node);
 +      ID *expand_cow_id(ID *id_orig);
 +      template<typename T>
 +      T *expand_cow_datablock(T *orig) {
 +              return (T *)expand_cow_id(&orig->id);
 +      }
 +
 +      /* For a given COW datablock get corresponding original one. */
 +      template<typename T>
 +      T *get_orig_datablock(const T *cow) const {
 +              if (DEG_depsgraph_use_copy_on_write()) {
 +                      return (T *)cow->id.orig_id;
 +              }
 +              else {
 +                      return (T *)cow;
 +              }
 +      }
 +
        void begin_build();
 +      void end_build();
  
        IDDepsNode *add_id_node(ID *id);
 +      IDDepsNode *find_id_node(ID *id);
        TimeSourceDepsNode *add_time_source();
  
        ComponentDepsNode *add_component_node(ID *id,
                                               const char *name = "",
                                               int name_tag = -1);
  
 -      void build_scene(Scene *scene);
 -      void build_group(Base *base, Group *group);
 -      void build_object(Base *base, Object *object);
 +      void build_view_layer(Scene *scene,
 +                             ViewLayer *view_layer,
 +                             eDepsNode_LinkedState_Type linked_state);
 +      void build_group(Group *group);
 +      void build_object(Base *base,
 +                        Object *object,
 +                        eDepsNode_LinkedState_Type linked_state);
 +      void build_object_flags(Base *base,
 +                              Object *object,
 +                              eDepsNode_LinkedState_Type linked_state);
        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, int pchan_index);
        void build_rigidbody(Scene *scene);
        void build_particles(Object *object);
 +      void build_particle_settings(ParticleSettings *part);
        void build_cloth(Object *object);
        void build_animdata(ID *id);
        void build_driver(ID *id, FCurve *fcurve);
        void build_cachefile(CacheFile *cache_file);
        void build_mask(Mask *mask);
        void build_movieclip(MovieClip *clip);
 +      void build_lightprobe(Object *object);
  
 +      struct LayerCollectionState {
 +              int index;
 +              LayerCollection *parent;
 +      };
 +      void build_layer_collection(ID *owner_id,
 +                                  LayerCollection *layer_collection,
 +                                  LayerCollectionState *state);
 +      void build_layer_collections(ID *owner_id,
 +                                   ListBase *layer_collections,
 +                                   LayerCollectionState *state);
 +      void build_view_layer_collections(ID *owner_id, ViewLayer *view_layer);
  protected:
 +      struct SavedEntryTag {
 +              ID *id;
 +              eDepsNode_Type component_type;
 +              eDepsOperation_Code opcode;
 +      };
 +      vector<SavedEntryTag> saved_entry_tags_;
 +
+       struct BuilderWalkUserData {
+               DepsgraphNodeBuilder *builder;
+       };
+       static void modifier_walk(void *user_data,
+                                 struct Object *object,
+                                 struct ID **idpoin,
+                                 int cb_flag);
+       static void constraint_walk(bConstraint *constraint,
+                                   ID **idpoin,
+                                   bool is_reference,
+                                   void *user_data);
        /* State which never changes, same for the whole builder time. */
        Main *bmain_;
        Depsgraph *graph_;
        /* State which demotes currently built entities. */
        Scene *scene_;
  
 +      GHash *cow_id_hash_;
        BuilderMap built_map_;
  };
  
index 4600bfedf28c7ed3bf764b1aa15f3044b838a310,9cfe83e008758b6c64647e68d0f1bf8672718500..5ac49f540b109dfa7efe33b4be4d4bf5ee0e62a6
@@@ -46,17 -46,16 +46,18 @@@ 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"
+ #include "BKE_constraint.h"
  } /* extern "C" */
  
  #include "DEG_depsgraph.h"
  #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"
@@@ -70,12 -69,16 +71,16 @@@ void DepsgraphNodeBuilder::build_pose_c
                                                    bPoseChannel *pchan,
                                                    int pchan_index)
  {
-       /* create node for constraint stack */
+       /* Pull indirect dependencies via constraints. */
+       BuilderWalkUserData data;
+       data.builder = this;
+       BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data);
+       /* 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,
 +                                       get_cow_datablock(scene_),
 +                                       get_cow_datablock(object),
                                         pchan_index),
                           DEG_OPCODE_BONE_CONSTRAINTS);
  }
@@@ -85,7 -88,6 +90,7 @@@ void DepsgraphNodeBuilder::build_ik_pos
                                           bPoseChannel *pchan,
                                           bConstraint *con)
  {
 +      Object *object_cow = get_cow_datablock(object);
        bKinematicConstraint *data = (bKinematicConstraint *)con->data;
  
        /* Find the chain's root. */
                return;
        }
  
 -      int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan);
 +      int rootchan_index = BLI_findindex(&object_cow->pose->chanbase, rootchan);
        BLI_assert(rootchan_index != -1);
        /* 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,
 +                                       get_cow_datablock(scene_),
 +                                       object_cow,
                                         rootchan_index),
                           DEG_OPCODE_POSE_IK_SOLVER);
  }
@@@ -117,23 -119,21 +122,23 @@@ void DepsgraphNodeBuilder::build_spline
                                                 bPoseChannel *pchan,
                                                 bConstraint *con)
  {
 +      Object *object_cow = get_cow_datablock(object);
        bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
  
        /* Find the chain's root. */
        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.
         */
 -      int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan);
 +      int rootchan_index = BLI_findindex(&object_cow->pose->chanbase, rootchan);
        BLI_assert(rootchan_index != -1);
        add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
                           function_bind(BKE_pose_splineik_evaluate,
                                         _1,
 -                                       scene_,
 -                                       object,
 +                                       get_cow_datablock(scene_),
 +                                       object_cow,
                                         rootchan_index),
                           DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
  }
  /* Pose/Armature Bones Graph */
  void DepsgraphNodeBuilder::build_rig(Object *object)
  {
 -      bArmature *arm = (bArmature *)object->data;
 +      bArmature *armature = (bArmature *)object->data;
 +      Scene *scene_cow;
 +      Object *object_cow;
 +      bArmature *armature_cow;
 +      if (DEG_depsgraph_use_copy_on_write()) {
 +              /* NOTE: We need to expand both object and armature, so this way we can
 +               * safely create object level pose.
 +               */
 +              scene_cow = get_cow_datablock(scene_);
 +              object_cow = expand_cow_datablock(object);
 +              armature_cow = expand_cow_datablock(armature);
 +      }
 +      else {
 +              scene_cow = scene_;
 +              object_cow = object;
 +              armature_cow = armature;
 +      }
        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 (!built_map_.checkIsBuilt(arm)) {
 -              build_animdata(&arm->id);
 +      if (!built_map_.checkIsBuilt(armature)) {
 +              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,
        }
  
        /* Rebuild pose if not up to date. */
 -      if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) {
 -              BKE_pose_rebuild_ex(object, arm, false);
 +      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 (object->adt) {
 -                      object->adt->recalc |= ADT_RECALC_ANIM;
 +              if (object_cow->adt) {
 +                      object_cow->adt->recalc |= ADT_RECALC_ANIM;
                }
        }
  
        /* speed optimization for animation lookups */
 -      if (object->pose) {
 -              BKE_pose_channels_hash_make(object->pose);
 -              if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
 -                      BKE_pose_update_constraint_flags(object->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);
                }
        }
  
         * - 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.
         */
  
                                     DEG_NODE_TYPE_EVAL_POSE,
                                     function_bind(BKE_pose_eval_init,
                                                   _1,
 -                                                 scene_,
 -                                                 object),
 +                                                 scene_cow,
 +                                                 object_cow),
                                     DEG_OPCODE_POSE_INIT);
        op_node->set_as_entry();
  
                                     DEG_NODE_TYPE_EVAL_POSE,
                                     function_bind(BKE_pose_eval_init_ik,
                                                   _1,
 -                                                 scene_,
 -                                                 object),
 +                                                 scene_cow,
 +                                                 object_cow),
                                     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),
 +                                                 scene_cow,
 +                                                 object_cow),
                                     DEG_OPCODE_POSE_DONE);
        op_node->set_as_exit();
  
        /* bones */
        int pchan_index = 0;
 -      LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
 +      LISTBASE_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
                /* Node for bone evaluation. */
                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(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
 -                                 function_bind(BKE_pose_eval_bone, _1, scene_, object, pchan_index),
 +                                 function_bind(BKE_pose_eval_bone, _1,
 +                                               scene_cow,
 +                                               object_cow,
 +                                               pchan_index),
                                   DEG_OPCODE_BONE_POSE_PARENT);
  
 +              /* NOTE: Dedicated noop for easier relationship construction. */
                add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
 -                                 NULL, /* NOTE: dedicated noop for easier relationship construction */
 +                                 NULL,
                                   DEG_OPCODE_BONE_READY);
  
                op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
                                             function_bind(BKE_pose_bone_done,
                                                           _1,
 -                                                         object,
 +                                                         object_cow,
                                                           pchan_index),
                                             DEG_OPCODE_BONE_DONE);
                op_node->set_as_exit();
                                           DEG_OPCODE_PARAMETERS_EVAL,
                                           pchan->name);
                }
 -              /* Constraints. */
 +              /* Build constraints. */
                if (pchan->constraints.first != NULL) {
                        build_pose_constraints(object, pchan, pchan_index);
                }
                 *
                 * 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...
 +               *   as in ik-tree building
 +               * - Animated chain-lengths are a problem.
                 */
                LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
                        switch (con->type) {
                }
  
                /* Custom shape. */
 +              /* NOTE: Custom shape datablock is already remapped to CoW version. */
                if (pchan->custom != NULL) {
 -                      build_object(NULL, pchan->custom);
 +                      build_object(NULL,
 +                                   get_orig_datablock(pchan->custom),
 +                                   DEG_ID_LINKED_INDIRECTLY);
                }
  
                pchan_index++;
@@@ -330,52 -304,34 +335,52 @@@ void DepsgraphNodeBuilder::build_proxy_
  {
        bArmature *arm = (bArmature *)object->data;
        OperationDepsNode *op_node;
 -
 -      build_animdata(&arm->id);
 -
 +      Object *object_cow;
 +      if (DEG_depsgraph_use_copy_on_write()) {
 +              /* NOTE: We need to expand both object and armature, so this way we can
 +               * safely create object level pose.
 +               */
 +              object_cow = expand_cow_datablock(object);
 +      }
 +      else {
 +              object_cow = object;
 +      }
 +      /* Sanity check. */
        BLI_assert(object->pose != NULL);
 -
 +      /* Animation. */
 +      build_animdata(&arm->id);
        /* speed optimization for animation lookups */
        BKE_pose_channels_hash_make(object->pose);
 -      if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
 -              BKE_pose_update_constraint_flags(object->pose);
 +      if (object_cow->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
 +              BKE_pose_update_constraint_flags(object_cow->pose);
        }
 -
        op_node = add_operation_node(&object->id,
                                     DEG_NODE_TYPE_EVAL_POSE,
 -                                   function_bind(BKE_pose_eval_proxy_copy, _1, object),
 +                                   function_bind(BKE_pose_eval_proxy_copy,
 +                                                 _1,
 +                                                 object_cow),
                                     DEG_OPCODE_POSE_INIT);
        op_node->set_as_entry();
  
 -
        LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
 -              op_node = add_operation_node(&object->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(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
 -                                 NULL, DEG_OPCODE_BONE_READY);
 -
 -              op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
 -                                           NULL, DEG_OPCODE_BONE_DONE);
 +              /* Bone is ready for solvers. */
 +              add_operation_node(&object->id,
 +                                 DEG_NODE_TYPE_BONE,
 +                                 pchan->name,
 +                                 NULL,
 +                                 DEG_OPCODE_BONE_READY);
 +              /* Bone is fully evaluated. */
 +              op_node = add_operation_node(&object->id,
 +                                           DEG_NODE_TYPE_BONE,
 +                                           pchan->name,
 +                                           NULL,
 +                                           DEG_OPCODE_BONE_DONE);
                op_node->set_as_exit();
  
                /* Custom properties. */
                                           pchan->name);
                }
        }
 -
 -      op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE,
 -                                   NULL, DEG_OPCODE_POSE_DONE);
 +      op_node = add_operation_node(&object->id,
 +                                   DEG_NODE_TYPE_EVAL_POSE,
 +                                   NULL,
 +                                   DEG_OPCODE_POSE_DONE);
        op_node->set_as_exit();
  }