diff options
Diffstat (limited to 'source/blender/depsgraph/intern/depsgraph_tag.cc')
-rw-r--r-- | source/blender/depsgraph/intern/depsgraph_tag.cc | 475 |
1 files changed, 258 insertions, 217 deletions
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 31b4bbc7950..38919fb890e 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -49,6 +49,7 @@ extern "C" { #include "BKE_library.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_workspace.h" #define new new_ #include "BKE_screen.h" @@ -66,18 +67,17 @@ extern "C" { #include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" +/* Define this in order to have more strict sanitization of what tagging flags + * are used for ID databnlocks. Ideally, we would always want this, but there + * are cases in generic modules (like IR remapping) where we don't want to spent + * lots of time trying to guess which components are to be updated. + */ +// #define STRICT_COMPONENT_TAGGING + /* *********************** */ /* Update Tagging/Flushing */ -/* Legacy depsgraph did some special trickery for things like particle systems - * when tagging ID for an update. Ideally that tagging needs to become obsolete - * in favor of havng dedicated node for that which gets tagged, but for until - * design of those areas is more clear we'll do the same legacy code here. - * - sergey - - */ -#define DEPSGRAPH_USE_LEGACY_TAGGING - -namespace { +namespace DEG { /* Data-Based Tagging ------------------------------- */ @@ -93,168 +93,295 @@ void lib_id_recalc_data_tag(Main *bmain, ID *id) DEG_id_type_tag(bmain, GS(id->name)); } +namespace { + void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag) { + /* This bit of code ensures legacy object->recalc flags are still filled in + * the same way as it was expected with the old dependency graph. + * + * This is because some areas like motion paths and likely some other + * physics baking process are doing manual scene update on all the frames, + * trying to minimize number of updates. + * + * But this flag will also let us to re-construct entry nodes for update + * after relations update and after layer visibility changes. + */ if (flag) { - /* This bit of code ensures legacy object->recalc flags - * are still filled in the same way as it was expected - * with the old dependency graph. - * - * This is because some areas like motion paths and likely - * some other physics baking process are doing manual scene - * update on all the frames, trying to minimize number of - * updates. - * - * But this flag will also let us to re-construct entry - * nodes for update after relations update and after layer - * visibility changes. - */ - short idtype = GS(id->name); - if (idtype == ID_OB) { + short id_type = GS(id->name); + if (id_type == ID_OB) { Object *object = (Object *)id; object->recalc |= (flag & OB_RECALC_ALL); } - - if (flag & OB_RECALC_OB) + if (flag & OB_RECALC_OB) { lib_id_recalc_tag(bmain, id); - if (flag & (OB_RECALC_DATA | PSYS_RECALC)) + } + if (flag & (OB_RECALC_DATA | PSYS_RECALC)) { lib_id_recalc_data_tag(bmain, id); + } } else { lib_id_recalc_tag(bmain, id); } } -#ifdef DEPSGRAPH_USE_LEGACY_TAGGING -void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, short flag) +/* Special tagging */ +void id_tag_update_special_zero_flag(Depsgraph *graph, IDDepsNode *id_node) { - if (flag) { - Object *object; - short idtype = GS(id->name); - if (idtype == ID_PA) { - ParticleSystem *psys; - for (object = (Object *)bmain->object.first; - object != NULL; - object = (Object *)object->id.next) - { - for (psys = (ParticleSystem *)object->particlesystem.first; - psys != NULL; - psys = (ParticleSystem *)psys->next) - { - if (&psys->part->id == id) { - DEG_id_tag_update_ex(bmain, &object->id, flag & OB_RECALC_ALL); - psys->recalc |= (flag & PSYS_RECALC); - } - } + /* NOTE: Full ID node update for now, need to minimize that i9n the future. */ + id_node->tag_update(graph); +} + +/* Tag corresponding to OB_RECALC_OB. */ +void id_tag_update_object_transform(Depsgraph *graph, IDDepsNode *id_node) +{ + ComponentDepsNode *transform_comp = + id_node->find_component(DEG_NODE_TYPE_TRANSFORM); + if (transform_comp == NULL) { +#ifdef STRICT_COMPONENT_TAGGING + DEG_ERROR_PRINTF("ERROR: Unable to find transform component for %s\n", + id_node->id_orig->name); + BLI_assert(!"This is not supposed to happen!"); +#endif + return; + } + transform_comp->tag_update(graph); +} + +/* Tag corresponding to OB_RECALC_DATA. */ +void id_tag_update_object_data(Depsgraph *graph, IDDepsNode *id_node) +{ + const short id_type = GS(id_node->id_orig->name); + ComponentDepsNode *data_comp = NULL; + switch (id_type) { + case ID_OB: + { + const Object *object = (Object *)id_node->id_orig; + switch (object->type) { + case OB_MESH: + case OB_CURVE: + case OB_SURF: + case OB_FONT: + case OB_MBALL: + data_comp = id_node->find_component(DEG_NODE_TYPE_GEOMETRY); + break; + case OB_ARMATURE: + data_comp = id_node->find_component(DEG_NODE_TYPE_EVAL_POSE); + break; + /* TODO(sergey): More cases here? */ } + break; } + case ID_ME: + data_comp = id_node->find_component(DEG_NODE_TYPE_GEOMETRY); + break; + case ID_PA: + return; } -} + if (data_comp == NULL) { +#ifdef STRICT_COMPONENT_TAGGING + DEG_ERROR_PRINTF("ERROR: Unable to find data component for %s\n", + id_node->id_orig->name); + BLI_assert(!"This is not supposed to happen!"); #endif + return; + } + data_comp->tag_update(graph); + /* Special legacy compatibility code, tag data ID for update when object + * is tagged for data update. + */ + if (id_type == ID_OB) { + Object *object = (Object *)id_node->id_orig; + ID *data_id = (ID *)object->data; + if (data_id != NULL) { + IDDepsNode *data_id_node = graph->find_id_node(data_id); + // BLI_assert(data_id_node != NULL); + /* TODO(sergey): Do we want more granular tags here? */ + /* TODO(sergey): Hrm, during some operations it's possible to have + * object node existing but not it's data. For example, when making + * objects local. This is valid situation, but how can we distinguish + * that from someone trying to do stupid things with dependency + * graph? + */ + if (data_id_node != NULL) { + data_id_node->tag_update(graph); + } + } + } +} -} /* namespace */ - -/* Tag all nodes in ID-block for update. - * This is a crude measure, but is most convenient for old code. - */ -void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id) +/* Tag corresponding to OB_RECALC_TIME. */ +void id_tag_update_object_time(Depsgraph *graph, IDDepsNode *id_node) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); - DEG::IDDepsNode *node = deg_graph->find_id_node(id); - lib_id_recalc_tag(bmain, id); - if (node != NULL) { - node->tag_update(deg_graph); + ComponentDepsNode *animation_comp = + id_node->find_component(DEG_NODE_TYPE_ANIMATION); + if (animation_comp == NULL) { + /* It's not necessarily we've got animation component in cases when + * we are tagging for time updates. + */ + return; } + animation_comp->tag_update(graph); + /* TODO(sergey): More components to tag here? */ } -/* Tag nodes related to a specific piece of data */ -void DEG_graph_data_tag_update(Depsgraph *graph, const PointerRNA *ptr) +void id_tag_update_particle(Depsgraph *graph, IDDepsNode *id_node, int tag) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); - DEG::DepsNode *node = deg_graph->find_node_from_pointer(ptr, NULL); - if (node != NULL) { - node->tag_update(deg_graph); - } - else { - printf("Missing node in %s\n", __func__); - BLI_assert(!"Shouldn't happens since it'll miss crucial update."); + ComponentDepsNode *particle_comp = + id_node->find_component(DEG_NODE_TYPE_PARAMETERS); + ParticleSettings *particle_settings = (ParticleSettings *)id_node->id_orig; + particle_settings->recalc |= (tag & PSYS_RECALC); + if (particle_comp == NULL) { +#ifdef STRICT_COMPONENT_TAGGING + DEG_ERROR_PRINTF("ERROR: Unable to find particle component for %s\n", + id_node->id_orig->name); + BLI_assert(!"This is not supposed to happen!"); +#endif + return; } + particle_comp->tag_update(graph); } -/* Tag nodes related to a specific property. */ -void DEG_graph_property_tag_update(Depsgraph *graph, - const PointerRNA *ptr, - const PropertyRNA *prop) +void id_tag_update_shading(Depsgraph *graph, IDDepsNode *id_node) { - DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); - DEG::DepsNode *node = deg_graph->find_node_from_pointer(ptr, prop); - if (node != NULL) { - node->tag_update(deg_graph); - } - else { - printf("Missing node in %s\n", __func__); - BLI_assert(!"Shouldn't happens since it'll miss crucial update."); + ComponentDepsNode *shading_comp = + id_node->find_component(DEG_NODE_TYPE_SHADING); + if (shading_comp == NULL) { +#ifdef STRICT_COMPONENT_TAGGING + DEG_ERROR_PRINTF("ERROR: Unable to find shading component for %s\n", + id_node->id_orig->name); + BLI_assert(!"This is not supposed to happen!"); +#endif + return; } + shading_comp->tag_update(graph); } -/* Tag given ID for an update in all the dependency graphs. */ -void DEG_id_tag_update(ID *id, short flag) +#ifdef WITH_COPY_ON_WRITE +/* Tag corresponding to DEG_TAG_COPY_ON_WRITE. */ +void id_tag_update_copy_on_write(Depsgraph *graph, IDDepsNode *id_node) { - DEG_id_tag_update_ex(G.main, id, flag); + ComponentDepsNode *cow_comp = + id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE); + OperationDepsNode *cow_node = cow_comp->get_entry_operation(); + cow_node->tag_update(graph); } +#endif -void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag) +void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag) { - if (id == NULL) { - /* Ideally should not happen, but old depsgraph allowed this. */ + Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); + IDDepsNode *id_node = deg_graph->find_id_node(id); + /* Make sure legacy flags are all nicely update. */ + lib_id_recalc_tag_flag(bmain, id, flag); + if (id_node == NULL) { + /* Shouldn't happen, but better be sure here. */ return; } - DEG_DEBUG_PRINTF("%s: id=%s flag=%d\n", __func__, id->name, flag); + /* Tag components based on flags. */ + if (flag == 0) { + id_tag_update_special_zero_flag(graph, id_node); + return; + } + if (flag & OB_RECALC_OB) { + id_tag_update_object_transform(graph, id_node); + } + if (flag & OB_RECALC_DATA) { + id_tag_update_object_data(graph, id_node); +#ifdef WITH_COPY_ON_WRITE + if (flag & DEG_TAG_COPY_ON_WRITE) { + const short id_type = GS(id_node->id_orig->name); + if (id_type == ID_OB) { + Object *object = (Object *)id_node->id_orig; + ID *ob_data = (ID *)object->data; + DEG_id_tag_update_ex(bmain, ob_data, flag); + } + } +#endif + } + if (flag & OB_RECALC_TIME) { + id_tag_update_object_time(graph, id_node); + } + if (flag & PSYS_RECALC) { + id_tag_update_particle(graph, id_node, flag); + } + if (flag & DEG_TAG_SHADING_UPDATE) { + id_tag_update_shading(graph, id_node); + } +#ifdef WITH_COPY_ON_WRITE + if (flag & DEG_TAG_COPY_ON_WRITE) { + id_tag_update_copy_on_write(graph, id_node); + } +#endif +} + +void deg_id_tag_update(Main *bmain, ID *id, int flag) +{ lib_id_recalc_tag_flag(bmain, id, flag); for (Scene *scene = (Scene *)bmain->scene.first; scene != NULL; scene = (Scene *)scene->id.next) { - if (scene->depsgraph) { - Depsgraph *graph = scene->depsgraph; - if (flag == 0) { - /* TODO(sergey): Currently blender is still tagging IDs - * for recalc just using flag=0. This isn't totally correct - * but we'd better deal with such cases and don't fail. - */ - DEG_graph_id_tag_update(bmain, graph, id); - continue; - } - if (flag & OB_RECALC_DATA && GS(id->name) == ID_OB) { - Object *object = (Object *)id; - if (object->data != NULL) { - DEG_graph_id_tag_update(bmain, - graph, - (ID *)object->data); - } - } - if (flag & (OB_RECALC_OB | OB_RECALC_DATA)) { - DEG_graph_id_tag_update(bmain, graph, id); - } - else if (flag & OB_RECALC_TIME) { - DEG_graph_id_tag_update(bmain, graph, id); - } + if (scene->depsgraph_legacy != NULL) { + Depsgraph *graph = (Depsgraph *)scene->depsgraph_legacy; + deg_graph_id_tag_update(bmain, graph, id, flag); } } +} -#ifdef DEPSGRAPH_USE_LEGACY_TAGGING - /* Special handling from the legacy depsgraph. - * TODO(sergey): Need to get rid of those once all the areas - * are re-formulated in terms of franular nodes. - */ - depsgraph_legacy_handle_update_tag(bmain, id, flag); -#endif +void deg_graph_on_visible_update(Main *bmain, Scene *scene, Depsgraph *graph) +{ + /* Make sure objects are up to date. */ + GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash) + { + const short id_type = GS(id_node->id_orig->name); + if (id_type != ID_OB) { + /* Ignore non-object nodes on visibility changes. */ + continue; + } + int flag = 0; + /* We only tag components which needs an update. Tagging everything is + * not a good idea because that might reset particles cache (or any + * other type of cache). + * + * TODO(sergey): Need to generalize this somehow. + */ + if (id_type == ID_OB) { + flag |= OB_RECALC_OB | OB_RECALC_DATA | DEG_TAG_COPY_ON_WRITE; + } + deg_graph_id_tag_update(bmain, graph, id_node->id_orig, flag); + } + GHASH_FOREACH_END(); + /* Make sure collection properties are up to date. */ + IDDepsNode *scene_id_node = graph->find_id_node(&scene->id); + BLI_assert(scene_id_node != NULL); + scene_id_node->tag_update(graph); +} + +} /* namespace */ + +} // namespace DEG + +/* Tag given ID for an update in all the dependency graphs. */ +void DEG_id_tag_update(ID *id, int flag) +{ + DEG_id_tag_update_ex(G.main, id, flag); +} + +void DEG_id_tag_update_ex(Main *bmain, ID *id, int flag) +{ + if (id == NULL) { + /* Ideally should not happen, but old depsgraph allowed this. */ + return; + } + DEG_DEBUG_PRINTF("%s: id=%s flag=%d\n", __func__, id->name, flag); + DEG::deg_id_tag_update(bmain, id, flag); } /* Tag given ID type for update. */ -void DEG_id_type_tag(Main *bmain, short idtype) +void DEG_id_type_tag(Main *bmain, short id_type) { - if (idtype == ID_NT) { + if (id_type == ID_NT) { /* Stupid workaround so parent datablocks of nested nodetree get looped * over when we loop over tagged datablock types. */ @@ -265,113 +392,27 @@ void DEG_id_type_tag(Main *bmain, short idtype) DEG_id_type_tag(bmain, ID_SCE); } - bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1; + bmain->id_tag_update[BKE_idcode_to_index(id_type)] = 1; } /* Recursively push updates out to all nodes dependent on this, * until all affected are tagged and/or scheduled up for eval */ -void DEG_ids_flush_tagged(Main *bmain) +void DEG_ids_flush_tagged(Main *bmain, Scene *scene) { - for (Scene *scene = (Scene *)bmain->scene.first; - scene != NULL; - scene = (Scene *)scene->id.next) - { - /* TODO(sergey): Only visible scenes? */ - if (scene->depsgraph != NULL) { - DEG::deg_graph_flush_updates( - bmain, - reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph)); - } + /* TODO(sergey): Only visible scenes? */ + if (scene->depsgraph_legacy != NULL) { + DEG::deg_graph_flush_updates( + bmain, + reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph_legacy)); } } /* Update dependency graph when visible scenes/layers changes. */ void DEG_graph_on_visible_update(Main *bmain, Scene *scene) { - DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph); - wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; - int old_layers = graph->layers; - if (wm != NULL) { - BKE_main_id_tag_listbase(&bmain->scene, LIB_TAG_DOIT, true); - graph->layers = 0; - for (wmWindow *win = (wmWindow *)wm->windows.first; - win != NULL; - win = (wmWindow *)win->next) - { - Scene *scene = win->screen->scene; - if (scene->id.tag & LIB_TAG_DOIT) { - graph->layers |= BKE_screen_visible_layers(win->screen, scene); - scene->id.tag &= ~LIB_TAG_DOIT; - } - } - } - else { - /* All the layers for background render for now. */ - graph->layers = (1 << 20) - 1; - } - if (old_layers != graph->layers) { - /* Tag all objects which becomes visible (or which becomes needed for dependencies) - * for recalc. - * - * This is mainly needed on file load only, after that updates of invisible objects - * will be stored in the pending list. - */ - GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash) - { - ID *id = id_node->id; - if ((id->tag & LIB_TAG_ID_RECALC_ALL) != 0 || - (id_node->layers & scene->lay_updated) == 0) - { - id_node->tag_update(graph); - } - /* A bit of magic: if object->recalc is set it means somebody tagged - * it for update. If corresponding ID recalc flags are zero it means - * graph has been evaluated after that and the recalc was skipped - * because of visibility check. - */ - if (GS(id->name) == ID_OB) { - Object *object = (Object *)id; - if ((id->tag & LIB_TAG_ID_RECALC_ALL) == 0 && - (object->recalc & OB_RECALC_ALL) != 0) - { - id_node->tag_update(graph); - DEG::ComponentDepsNode *anim_comp = - id_node->find_component(DEG::DEG_NODE_TYPE_ANIMATION); - if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) { - anim_comp->tag_update(graph); - } - } - } - } - GHASH_FOREACH_END(); - } - scene->lay_updated |= graph->layers; - /* Special trick to get local view to work. */ - LINKLIST_FOREACH (Base *, base, &scene->base) { - Object *object = base->object; - DEG::IDDepsNode *id_node = graph->find_id_node(&object->id); - id_node->layers = 0; - } - LINKLIST_FOREACH (Base *, base, &scene->base) { - Object *object = base->object; - DEG::IDDepsNode *id_node = graph->find_id_node(&object->id); - id_node->layers |= base->lay; - if (object == scene->camera) { - /* Camera should always be updated, it used directly by viewport. */ - id_node->layers |= (unsigned int)(-1); - } - } - DEG::deg_graph_build_flush_layers(graph); - LINKLIST_FOREACH (Base *, base, &scene->base) { - Object *object = base->object; - DEG::IDDepsNode *id_node = graph->find_id_node(&object->id); - GHASH_FOREACH_BEGIN(DEG::ComponentDepsNode *, comp, id_node->components) - { - id_node->layers |= comp->layers; - } - GHASH_FOREACH_END(); - } + DEG::Depsgraph *graph = (DEG::Depsgraph *)scene->depsgraph_legacy; + DEG::deg_graph_on_visible_update(bmain, scene, graph); } void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time)) @@ -380,7 +421,7 @@ void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time)) scene != NULL; scene = (Scene *)scene->id.next) { - if (scene->depsgraph != NULL) { + if (scene->depsgraph_legacy != NULL) { DEG_graph_on_visible_update(bmain, scene); } } |