diff options
Diffstat (limited to 'source/blender/depsgraph/intern/builder/deg_builder_nodes.cc')
-rw-r--r-- | source/blender/depsgraph/intern/builder/deg_builder_nodes.cc | 838 |
1 files changed, 595 insertions, 243 deletions
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index b0894101414..cfb2f1bc8d6 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -62,21 +62,22 @@ 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_speaker_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_animsys.h" +#include "BKE_collection.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" -#include "BKE_group.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" @@ -90,6 +91,7 @@ extern "C" { #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" @@ -103,6 +105,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_id.h" @@ -114,6 +117,17 @@ extern "C" { namespace DEG { +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 */ @@ -122,17 +136,49 @@ namespace DEG { DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph) : bmain_(bmain), graph_(graph), - scene_(NULL) + scene_(NULL), + view_layer_(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); + 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, 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() @@ -259,24 +305,105 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( 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_COPIED_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; +} + /* **** Build functions for entity nodes **** */ -void DepsgraphNodeBuilder::begin_build() { +void DepsgraphNodeBuilder::begin_build() +{ + /* 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_id(ID* id) { +void DepsgraphNodeBuilder::build_id(ID *id) { if (id == NULL) { return; } switch (GS(id->name)) { - case ID_SCE: - build_scene((Scene *)id); + case ID_AR: + build_armature((bArmature *)id); + break; + case ID_CA: + build_camera((Camera *)id); break; case ID_GR: - build_group(NULL, (Group *)id); + build_collection(DEG_COLLECTION_OWNER_UNKNOWN, (Collection *)id); break; case ID_OB: - build_object(NULL, (Object *)id); + build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY); + break; + case ID_KE: + build_shapekeys((Key *)id); + break; + case ID_LA: + build_lamp((Lamp *)id); + break; + case ID_LP: + build_lightprobe((LightProbe *)id); break; case ID_NT: build_nodetree((bNodeTree *)id); @@ -299,52 +426,87 @@ void DepsgraphNodeBuilder::build_id(ID* id) { case ID_MC: build_movieclip((MovieClip *)id); break; + case ID_ME: + case ID_CU: + case ID_MB: + case ID_LT: + build_object_data_geometry_datablock(id); + break; + case ID_SPK: + build_speaker((Speaker *)id); + break; default: - /* fprintf(stderr, "Unhandled ID %s\n", id->name); */ + fprintf(stderr, "Unhandled ID %s\n", id->name); + BLI_assert(!"Should never happen"); break; } } -void DepsgraphNodeBuilder::build_group(Base *base, Group *group) +void DepsgraphNodeBuilder::build_collection( + eDepsNode_CollectionOwner owner_type, + Collection *collection) { - if (built_map_.checkIsBuiltAndTag(group)) { + if (built_map_.checkIsBuiltAndTag(collection)) { return; } - LISTBASE_FOREACH (GroupObject *, go, &group->gobject) { - build_object(base, go->ob); + const bool allow_restrict_flags = (owner_type == DEG_COLLECTION_OWNER_SCENE); + if (allow_restrict_flags) { + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) + ? COLLECTION_RESTRICT_VIEW + : COLLECTION_RESTRICT_RENDER; + if (collection->flag & restrict_flag) { + return; + } + } + /* Collection itself. */ + add_id_node(&collection->id); + /* Build collection objects. */ + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + if (allow_restrict_flags) { + const int restrict_flag = ( + (graph_->mode == DAG_EVAL_VIEWPORT) ? + OB_RESTRICT_VIEW : + OB_RESTRICT_RENDER); + if (cob->ob->restrictflag & restrict_flag) { + continue; + } + } + build_object(-1, cob->ob, DEG_ID_LINKED_INDIRECTLY); + } + /* Build child collections. */ + LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { + build_collection(owner_type, child->collection); } } -void DepsgraphNodeBuilder::build_object(Base *base, Object *object) +void DepsgraphNodeBuilder::build_object(int base_index, + 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_index, 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_index, object, linked_state); /* Transform. */ build_object_transform(object); /* Parent. */ if (object->parent != NULL) { - build_object(NULL, object->parent); + build_object(-1, object->parent, DEG_ID_LINKED_INDIRECTLY); } /* Modifiers. */ if (object->modifiers.first != NULL) { @@ -380,15 +542,40 @@ void DepsgraphNodeBuilder::build_object(Base *base, Object *object) if (object->gpd != NULL) { build_gpencil(object->gpd); } - /* Object that this is a proxy for. */ - if (object->proxy) { - object->proxy->proxy_from = object; - build_object(base, object->proxy); + /* Proxy object to copy from. */ + if (object->proxy_from != NULL) { + build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY); + } + if (object->proxy_group != NULL) { + build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY); } /* Object dupligroup. */ if (object->dup_group != NULL) { - build_group(base, object->dup_group); + build_collection(DEG_COLLECTION_OWNER_OBJECT, object->dup_group); + } +} + +void DepsgraphNodeBuilder::build_object_flags( + int base_index, + Object *object, + eDepsNode_LinkedState_Type linked_state) +{ + if (base_index == -1) { + return; } + Scene *scene_cow = get_cow_datablock(scene_); + Object *object_cow = get_cow_datablock(object); + const bool is_from_set = (linked_state == DEG_ID_LINKED_VIA_SET); + /* TODO(sergey): Is this really best component to be used? */ + add_operation_node(&object->id, + DEG_NODE_TYPE_OBJECT_FROM_LAYER, + function_bind(BKE_object_eval_flush_base_flags, + _1, + scene_cow, + view_layer_index_, + object_cow, base_index, + is_from_set), + DEG_OPCODE_OBJECT_BASE_FLAGS); } void DepsgraphNodeBuilder::build_object_data(Object *object) @@ -397,15 +584,15 @@ void DepsgraphNodeBuilder::build_object_data(Object *object) 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_MBALL: case OB_LATTICE: - build_obdata_geom(object); + build_object_data_geometry(object); /* TODO(sergey): Only for until we support granular * update of curves. */ @@ -425,10 +612,16 @@ void DepsgraphNodeBuilder::build_object_data(Object *object) } break; case OB_LAMP: - build_lamp(object); + build_object_data_lamp(object); break; case OB_CAMERA: - build_camera(object); + build_object_data_camera(object); + break; + case OB_LIGHTPROBE: + build_object_data_lightprobe(object); + break; + case OB_SPEAKER: + build_object_data_speaker(object); break; default: { @@ -441,42 +634,79 @@ void DepsgraphNodeBuilder::build_object_data(Object *object) } } +void DepsgraphNodeBuilder::build_object_data_camera(Object *object) +{ + Camera *camera = (Camera *)object->data; + build_camera(camera); +} + +void DepsgraphNodeBuilder::build_object_data_lamp(Object *object) +{ + Lamp *lamp = (Lamp *)object->data; + build_lamp(lamp); +} + +void DepsgraphNodeBuilder::build_object_data_lightprobe(Object *object) +{ + LightProbe *probe = (LightProbe *)object->data; + build_lightprobe(probe); + add_operation_node(&object->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_LIGHT_PROBE_EVAL); +} + +void DepsgraphNodeBuilder::build_object_data_speaker(Object *object) +{ + Speaker *speaker = (Speaker *)object->data; + build_speaker(speaker); + add_operation_node(&object->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_SPEAKER_EVAL); +} + 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(); } @@ -502,7 +732,10 @@ void DepsgraphNodeBuilder::build_object_constraints(Object *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); } @@ -513,29 +746,48 @@ void DepsgraphNodeBuilder::build_object_constraints(Object *object) 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); + + if (adt->action != NULL && + !built_map_.checkIsBuiltAndTag(&adt->action->id)) + { + add_operation_node(&adt->action->id, DEG_NODE_TYPE_ANIMATION, + NULL, + DEG_OPCODE_ANIMATION); + } - /* 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 */ + int driver_index = 0; LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { /* create driver */ - build_driver(id, fcu); + build_driver(id, fcu, driver_index++); } } } @@ -544,13 +796,21 @@ void DepsgraphNodeBuilder::build_animdata(ID *id) * Build graph node(s) for Driver * \param id: ID-Block that driver is attached to * \param fcu: Driver-FCurve + * \param driver_index: Index in animation data drivers list */ -void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve) +void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index) { /* Create data node for this driver */ + ID *id_cow = get_cow_id(id); + ChannelDriver *driver_orig = fcurve->driver; + + /* TODO(sergey): ideally we could pass the COW of fcu, but since it + * has not yet been allocated at this point we can't. As a workaround + * the animation systems allocates an array so we can do a fast lookup + * with the driver index. */ 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, driver_index, driver_orig), DEG_OPCODE_DRIVER, fcurve->rna_path ? fcurve->rna_path : "", fcurve->array_index); @@ -602,17 +862,17 @@ void DepsgraphNodeBuilder::build_world(World *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); - /* textures */ - build_texture_stack(world->mtex); + add_operation_node(&world->id, + DEG_NODE_TYPE_SHADING, + function_bind(BKE_world_eval, + _1, + get_cow_datablock(world)), + DEG_OPCODE_WORLD_UPDATE); /* world's nodetree */ - if (world->nodetree) { + if (world->nodetree != NULL) { build_nodetree(world->nodetree); } } @@ -621,57 +881,70 @@ 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) { - LISTBASE_FOREACH (GroupObject *, go, &rbw->group->gobject) { - Object *object = go->ob; + build_collection(DEG_COLLECTION_OWNER_OBJECT, rbw->group); - if (!object || (object->type != OB_MESH)) + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) + { + if (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); } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } } @@ -694,20 +967,26 @@ void DepsgraphNodeBuilder::build_particles(Object *object) /* 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, @@ -716,35 +995,61 @@ void DepsgraphNodeBuilder::build_particles(Object *object) switch (part->ren_as) { case PART_DRAW_OB: if (part->dup_ob != NULL) { - build_object(NULL, part->dup_ob); + build_object(-1, + part->dup_ob, + DEG_ID_LINKED_INDIRECTLY); } break; case PART_DRAW_GR: if (part->dup_group != NULL) { - build_group(NULL, part->dup_group); + build_collection(DEG_COLLECTION_OWNER_OBJECT, 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); } /* Shapekeys */ void DepsgraphNodeBuilder::build_shapekeys(Key *key) { + if (built_map_.checkIsBuiltAndTag(key)) { + return; + } build_animdata(&key->id); add_operation_node(&key->id, DEG_NODE_TYPE_GEOMETRY, @@ -754,11 +1059,11 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key) /* ObData Geometry Evaluation */ // XXX: what happens if the datablock is shared! -void DepsgraphNodeBuilder::build_obdata_geom(Object *object) +void DepsgraphNodeBuilder::build_object_data_geometry(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. * We'll get rid of this node as soon as all the granular update functions @@ -769,10 +1074,9 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) op_node = add_operation_node(&object->id, DEG_NODE_TYPE_GEOMETRY, function_bind(BKE_object_eval_uber_data, - bmain_, _1, - scene_, - object), + scene_cow, + object_cow), DEG_OPCODE_GEOMETRY_UBEREVAL); op_node->set_as_exit(); @@ -782,182 +1086,181 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) DEG_OPCODE_PLACEHOLDER, "Eval Init"); op_node->set_as_entry(); - // TODO: "Done" operation - /* Cloth modifier. */ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { if (md->type == eModifierType_Cloth) { build_cloth(object); } } + /* Materials. */ + 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); + } - /* materials */ - for (int a = 1; a <= object->totcol; a++) { - Material *ma = give_current_material(object, a); - if (ma != NULL) { - build_material(ma); + for (int a = 1; a <= object->totcol; a++) { + Material *ma = give_current_material(object, a); + if (ma != NULL) { + build_material(ma); + } } } - - /* geometry collision */ + /* Geometry collision. */ if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) { // add geometry collider relations } + build_object_data_geometry_datablock((ID *)object->data); +} +void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata) +{ if (built_map_.checkIsBuiltAndTag(obdata)) { return; } - + OperationDepsNode *op_node; + /* 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); + /* Animation. */ + build_animdata(obdata); /* ShapeKeys */ - Key *key = BKE_key_from_object(object); + Key *key = BKE_key_from_id(obdata); if (key) { build_shapekeys(key); } - - build_animdata(obdata); - /* Nodes for result of obdata's evaluation, and geometry * evaluation on object. */ - switch (object->type) { - case OB_MESH: + const ID_Type id_type = GS(obdata->name); + switch (id_type) { + case ID_ME: { - //Mesh *me = (Mesh *)object->data; - - /* evaluation operations */ op_node = add_operation_node(obdata, 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(); break; } - - case OB_MBALL: + case ID_MB: { - Object *mom = BKE_mball_basis_find(bmain_, bmain_->eval_ctx, scene_, object); - /* NOTE: Only the motherball gets evaluated, it's children are - * having empty placeholders for the correct relations being built. - */ - if (mom == object) { - /* metaball evaluation operations */ - op_node = add_operation_node(obdata, - DEG_NODE_TYPE_GEOMETRY, - function_bind(BKE_mball_eval_geometry, - _1, - (MetaBall *)obdata), - DEG_OPCODE_PLACEHOLDER, - "Geometry Eval"); - } - else { - op_node = add_operation_node(obdata, - DEG_NODE_TYPE_GEOMETRY, - NULL, - DEG_OPCODE_PLACEHOLDER, - "Geometry Eval"); - op_node->set_as_entry(); - } + op_node = add_operation_node(obdata, + DEG_NODE_TYPE_GEOMETRY, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); + op_node->set_as_entry(); break; } - - case OB_CURVE: - case OB_SURF: - case OB_FONT: + case ID_CU: { - /* Curve/nurms evaluation operations. */ - /* - calculate curve geometry (including path) */ op_node = add_operation_node(obdata, 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(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY); } if (cu->taperobj != NULL) { - build_object(NULL, cu->taperobj); + build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY); } - if (object->type == OB_FONT && cu->textoncurve != NULL) { - build_object(NULL, cu->textoncurve); + if (cu->textoncurve != NULL) { + build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY); } break; } - - case OB_LATTICE: + case ID_LT: { - /* Lattice evaluation operations. */ op_node = add_operation_node(obdata, 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(); break; } + default: + BLI_assert(!"Should not happen"); + break; } - op_node = add_operation_node(obdata, DEG_NODE_TYPE_GEOMETRY, NULL, DEG_OPCODE_PLACEHOLDER, "Eval Done"); op_node->set_as_exit(); - /* Parameters for driver sources. */ add_operation_node(obdata, 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) +void DepsgraphNodeBuilder::build_armature(bArmature *armature) { - /* TODO: Link scene-camera links in somehow... */ - Camera *camera = (Camera *)object->data; - if (built_map_.checkIsBuiltAndTag(camera)) { + if (built_map_.checkIsBuiltAndTag(armature)) { return; } - build_animdata(&camera->id); - add_operation_node(&camera->id, + build_animdata(&armature->id); + /* Make sure pose is up-to-date with armature updates. */ + add_operation_node(&armature->id, 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"); + DEG_OPCODE_PLACEHOLDER, + "Armature Eval"); +} + +void DepsgraphNodeBuilder::build_camera(Camera *camera) +{ + if (built_map_.checkIsBuiltAndTag(camera)) { + return; } + OperationDepsNode *op_node; + build_animdata(&camera->id); + op_node = add_operation_node(&camera->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PARAMETERS_EVAL); + op_node->set_as_exit(); } -/* Lamps */ -void DepsgraphNodeBuilder::build_lamp(Object *object) +void DepsgraphNodeBuilder::build_lamp(Lamp *lamp) { - Lamp *lamp = (Lamp *)object->data; if (built_map_.checkIsBuiltAndTag(lamp)) { return; } + OperationDepsNode *op_node; 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, - DEG_OPCODE_PARAMETERS_EVAL); + op_node = add_operation_node(&lamp->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PARAMETERS_EVAL); + op_node->set_as_exit(); /* lamp's nodetree */ build_nodetree(lamp->nodetree); - /* textures */ - build_texture_stack(lamp->mtex); } void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) @@ -968,16 +1271,26 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) 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; @@ -995,7 +1308,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) build_image((Image *)id); } else if (id_type == ID_OB) { - build_object(NULL, (Object *)id); + build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY); } else if (id_type == ID_SCE) { /* Scenes are used by compositor trees, and handled by render @@ -1023,30 +1336,22 @@ void DepsgraphNodeBuilder::build_material(Material *material) 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 */ - 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++) { - MTex *mtex = texture_stack[i]; - if (mtex && mtex->tex) - build_texture(mtex->tex); - } -} - /* Recursively build graph for texture */ void DepsgraphNodeBuilder::build_texture(Tex *texture) { @@ -1089,13 +1394,18 @@ void DepsgraphNodeBuilder::build_compositor(Scene *scene) // 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); } void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd) { + if (built_map_.checkIsBuiltAndTag(gpd)) { + return; + } ID *gpd_id = &gpd->id; /* TODO(sergey): what about multiple users of same datablock? This should @@ -1110,6 +1420,9 @@ void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd) void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file) { + if (built_map_.checkIsBuiltAndTag(cache_file)) { + return; + } ID *cache_file_id = &cache_file->id; /* Animation, */ build_animdata(cache_file_id); @@ -1120,32 +1433,68 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file) void DepsgraphNodeBuilder::build_mask(Mask *mask) { + if (built_map_.checkIsBuiltAndTag(mask)) { + return; + } 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) +{ + if (built_map_.checkIsBuiltAndTag(clip)) { + return; + } 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); } +void DepsgraphNodeBuilder::build_lightprobe(LightProbe *probe) +{ + 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_LIGHT_PROBE_EVAL); + + build_animdata(&probe->id); +} + +void DepsgraphNodeBuilder::build_speaker(Speaker *speaker) +{ + if (built_map_.checkIsBuiltAndTag(speaker)) { + return; + } + /* Placeholder so we can add relations and tag ID node for update. */ + add_operation_node(&speaker->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_SPEAKER_EVAL); + build_animdata(&speaker->id); +} + /* **** ID traversal callbacks functions **** */ void DepsgraphNodeBuilder::modifier_walk(void *user_data, @@ -1160,7 +1509,9 @@ void DepsgraphNodeBuilder::modifier_walk(void *user_data, } switch (GS(id->name)) { case ID_OB: - data->builder->build_object(NULL, (Object *)id); + data->builder->build_object(-1, + (Object *)id, + DEG_ID_LINKED_INDIRECTLY); break; case ID_TE: data->builder->build_texture((Tex *)id); @@ -1183,7 +1534,9 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/, } switch (GS(id->name)) { case ID_OB: - data->builder->build_object(NULL, (Object *)id); + data->builder->build_object(-1, + (Object *)id, + DEG_ID_LINKED_INDIRECTLY); break; default: /* pass */ @@ -1191,5 +1544,4 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/, } } - } // namespace DEG |