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 | 635 |
1 files changed, 468 insertions, 167 deletions
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 8d20a671202..ddae761cea0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -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" @@ -72,7 +73,6 @@ extern "C" { #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" @@ -103,6 +103,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" @@ -127,7 +128,9 @@ static void modifier_walk(void *user_data, { BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; if (*obpoin) { - data->builder->build_object(NULL, *obpoin); + data->builder->build_object(NULL, + *obpoin, + DEG_ID_LINKED_INDIRECTLY); } } @@ -140,11 +143,19 @@ void constraint_walk(bConstraint * /*con*/, if (*idpoin) { ID *id = *idpoin; if (GS(id->name) == ID_OB) { - data->builder->build_object(NULL, (Object *)id); + data->builder->build_object(NULL, + (Object *)id, + DEG_ID_LINKED_INDIRECTLY); } } } +void free_copy_on_write_datablock(void *id_v) +{ + ID *id = (ID *)id_v; + deg_free_copy_on_write_datablock(id); +} + } /* namespace */ /* ************ */ @@ -155,17 +166,51 @@ void constraint_walk(bConstraint * /*con*/, 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) +IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id, bool do_tag) { - return graph_->add_id_node(id, id->name); + if (!DEG_depsgraph_use_copy_on_write()) { + return graph_->add_id_node(id, do_tag); + } + 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, do_tag, 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_size(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() @@ -276,6 +321,32 @@ 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_COPY_ON_WRITE) { + /* ID is already remapped to copy-on-write. */ + return id_orig; + } + IDDepsNode *id_node = add_id_node(id_orig, false); + 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() { @@ -295,52 +366,116 @@ void DepsgraphNodeBuilder::begin_build() { } } FOREACH_NODETREE_END; + + 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)) { + 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) { ID *group_id = &group->id; if (group_id->tag & LIB_TAG_DOIT) { return; } group_id->tag |= LIB_TAG_DOIT; - - BLI_LISTBASE_FOREACH (GroupObject *, go, &group->gobject) { - build_object(base, go->ob); + /* Build group objects. */ + BLI_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 = (object->id.tag & LIB_TAG_DOIT); - 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) { + if (object->id.tag & LIB_TAG_DOIT) { + 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; } object->id.tag |= LIB_TAG_DOIT; + /* 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) { @@ -374,12 +509,30 @@ void DepsgraphNodeBuilder::build_object(Base *base, Object *object) /* 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) @@ -388,9 +541,9 @@ 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: @@ -421,6 +574,9 @@ void DepsgraphNodeBuilder::build_object_data(Object *object) case OB_CAMERA: build_camera(object); break; + case OB_LIGHTPROBE: + build_lightprobe(object); + break; default: { ID *obdata = (ID *)object->data; @@ -435,39 +591,44 @@ void DepsgraphNodeBuilder::build_object_data(Object *object) 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(); } @@ -493,7 +654,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); } @@ -504,23 +668,34 @@ 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); - /* 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 */ @@ -538,21 +713,28 @@ void DepsgraphNodeBuilder::build_animdata(ID *id) */ OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu) { + ID *id_cow = get_cow_id(id); + /* Create data node for this driver */ /* TODO(sergey): Avoid creating same operation multiple times, * in the future we need to avoid lookup of the operation as well * and use some tagging magic instead. */ - OperationDepsNode *driver_op = find_operation_node(id, - DEG_NODE_TYPE_PARAMETERS, - DEG_OPCODE_DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); + OperationDepsNode *driver_op = find_operation_node( + id, + DEG_NODE_TYPE_PARAMETERS, + DEG_OPCODE_DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); if (driver_op == NULL) { + /* TODO(sergey): Shall we use COW of fcu itself here? */ driver_op = add_operation_node(id, DEG_NODE_TYPE_PARAMETERS, - function_bind(BKE_animsys_eval_driver, _1, id, fcu), + function_bind(BKE_animsys_eval_driver, + _1, + id_cow, + fcu), DEG_OPCODE_DRIVER, fcu->rna_path ? fcu->rna_path : "", fcu->array_index); @@ -569,20 +751,19 @@ void DepsgraphNodeBuilder::build_world(World *world) if (world_id->tag & LIB_TAG_DOIT) { return; } - + /* Animation. */ build_animdata(world_id); - /* world itself */ add_operation_node(world_id, - DEG_NODE_TYPE_PARAMETERS, - NULL, - DEG_OPCODE_PARAMETERS_EVAL); - + 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); } } @@ -591,55 +772,66 @@ 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) { - BLI_LISTBASE_FOREACH (GroupObject *, go, &rbw->group->gobject) { - Object *object = go->ob; + BLI_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); } } @@ -666,41 +858,76 @@ void DepsgraphNodeBuilder::build_particles(Object *object) 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); /* particle systems */ BLI_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); + /* Build particle settings operations. + * + * NOTE: The call itself ensures settings are only build once. + */ + build_particle_settings(part); + + /* Update on particle settings change. */ + add_operation_node(psys_comp, + function_bind(BKE_particle_system_settings_eval, + _1, + psys), + DEG_OPCODE_PARTICLE_SETTINGS_EVAL, + psys->name); - /* this particle system */ - // TODO: for now, this will just be a placeholder "ubereval" node + /* Particle system evaluation. */ add_operation_node(psys_comp, NULL, DEG_OPCODE_PARTICLE_SYSTEM_EVAL, psys->name); } - /* pointcache */ - // TODO... + /* TODO(sergey): Do we need a point cache operations here? */ +} + +void DepsgraphNodeBuilder::build_particle_settings(ParticleSettings *part) { + ID *part_id = &part->id; + if (part_id->tag & LIB_TAG_DOIT) { + return; + } + part_id->tag |= LIB_TAG_DOIT; + /* Animation data. */ + build_animdata(part_id); + /* Parameters change. */ + add_operation_node(part_id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PARTICLE_SETTINGS_EVAL); + add_operation_node(part_id, + DEG_NODE_TYPE_PARAMETERS, + function_bind(BKE_particle_system_settings_recalc_clear, + _1, + part), + DEG_OPCODE_PARTICLE_SETTINGS_RECALC_CLEAR); } 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); } @@ -718,8 +945,9 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key) // 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); /* TODO(sergey): This way using this object's properties as driver target * works fine. @@ -743,8 +971,8 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) 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(); @@ -765,10 +993,21 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) } /* 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); + } } } @@ -777,9 +1016,14 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) // add geometry collider relations } + ID *obdata = (ID *)object->data; if (obdata->tag & LIB_TAG_DOIT) { return; } + obdata->tag |= LIB_TAG_DOIT; + /* 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); @@ -802,7 +1046,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(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(); @@ -819,9 +1063,10 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) /* 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"); } @@ -846,23 +1091,22 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) 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; } @@ -874,7 +1118,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) 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(); @@ -891,12 +1135,28 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object) 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) { - /* TODO: Link scene-camera links in somehow... */ + /* Object itself. */ + add_operation_node(&object->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PARAMETERS_EVAL, + "Camera Parameters"); + + /* Object data. */ + /* TODO: Link scene-camera links in somehow. */ Camera *cam = (Camera *)object->data; ID *camera_id = &cam->id; if (camera_id->tag & LIB_TAG_DOIT) { @@ -909,17 +1169,19 @@ void DepsgraphNodeBuilder::build_camera(Object *object) DEG_NODE_TYPE_PARAMETERS, NULL, DEG_OPCODE_PARAMETERS_EVAL); - - if (cam->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 itself. */ + add_operation_node(&object->id, + DEG_NODE_TYPE_PARAMETERS, + NULL, + DEG_OPCODE_PARAMETERS_EVAL, + "Lamp Parameters"); + + /* Object data. */ Lamp *la = (Lamp *)object->data; ID *lamp_id = &la->id; if (lamp_id->tag & LIB_TAG_DOIT) { @@ -928,7 +1190,6 @@ void DepsgraphNodeBuilder::build_lamp(Object *object) build_animdata(&la->id); - /* TODO(sergey): Is it really how we're supposed to work with drivers? */ add_operation_node(lamp_id, DEG_NODE_TYPE_PARAMETERS, NULL, @@ -945,22 +1206,30 @@ void DepsgraphNodeBuilder::build_lamp(Object *object) void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) { - if (!ntree) + if (ntree == NULL) { return; - + } /* nodetree itself */ ID *ntree_id = &ntree->id; - 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... */ BLI_LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { ID *id = bnode->id; @@ -978,7 +1247,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) 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 @@ -1003,36 +1272,40 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) } /* Recursively build graph for material */ -void DepsgraphNodeBuilder::build_material(Material *ma) +void DepsgraphNodeBuilder::build_material(Material *material) { - ID *ma_id = &ma->id; - if (ma_id->tag & LIB_TAG_DOIT) { + ID *material_id = &material->id; + if (material_id->tag & LIB_TAG_DOIT) { return; } - - add_operation_node(ma_id, DEG_NODE_TYPE_SHADING, NULL, - DEG_OPCODE_PLACEHOLDER, "Material Update"); - - /* material animation */ - build_animdata(ma_id); - - /* textures */ - build_texture_stack(ma->mtex); - - /* material's nodetree */ - build_nodetree(ma->nodetree); + material_id->tag |= LIB_TAG_DOIT; + /* 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. */ + 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); + } } } @@ -1077,7 +1350,9 @@ 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); } @@ -1109,29 +1384,55 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file) 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); } +void DepsgraphNodeBuilder::build_lightprobe(Object *object) +{ + LightProbe *probe = (LightProbe *)object->data; + ID *probe_id = &probe->id; + if (probe_id->tag & LIB_TAG_DOIT) { + return; + } + probe_id->tag |= LIB_TAG_DOIT; + /* 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); +} + } // namespace DEG |