diff options
Diffstat (limited to 'source/blender/depsgraph/intern/depsgraph_tag.cc')
-rw-r--r-- | source/blender/depsgraph/intern/depsgraph_tag.cc | 567 |
1 files changed, 339 insertions, 228 deletions
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 7f08f3f8052..f364ac52b38 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -35,8 +35,9 @@ #include <queue> #include "BLI_utildefines.h" -#include "BLI_task.h" #include "BLI_listbase.h" +#include "BLI_math_bits.h" +#include "BLI_task.h" extern "C" { #include "DNA_object_types.h" @@ -49,6 +50,8 @@ extern "C" { #include "BKE_library.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_scene.h" +#include "BKE_workspace.h" #define new new_ #include "BKE_screen.h" @@ -70,162 +73,358 @@ extern "C" { /* *********************** */ /* 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 DEG { namespace { -/* Data-Based Tagging ------------------------------- */ +void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag); -void lib_id_recalc_tag(Main *bmain, ID *id) +void depsgraph_geometry_tag_to_component(const ID *id, + eDepsNode_Type *component_type) { - id->recalc |= ID_RECALC; - DEG_id_type_tag(bmain, GS(id->name)); + const ID_Type id_type = GS(id->name); + switch (id_type) { + case ID_OB: + { + const Object *object = (Object *)id; + switch (object->type) { + case OB_MESH: + case OB_CURVE: + case OB_SURF: + case OB_FONT: + case OB_MBALL: + *component_type = DEG_NODE_TYPE_GEOMETRY; + break; + case OB_ARMATURE: + *component_type = DEG_NODE_TYPE_EVAL_POSE; + break; + /* TODO(sergey): More cases here? */ + } + break; + } + case ID_ME: + *component_type = DEG_NODE_TYPE_GEOMETRY; + break; + case ID_PA: + return; + case ID_LP: + *component_type = DEG_NODE_TYPE_PARAMETERS; + break; + default: + break; + } } -void lib_id_recalc_data_tag(Main *bmain, ID *id) +void depsgraph_select_tag_to_component_opcode( + const ID *id, + eDepsNode_Type *component_type, + eDepsOperation_Code *operation_code) { - id->recalc |= ID_RECALC_DATA; - DEG_id_type_tag(bmain, GS(id->name)); + const ID_Type id_type = GS(id->name); + if (id_type == ID_SCE) { + /* We need to flush base flags to all objects in a scene since we + * don't know which ones changed. However, we don't want to update + * the whole scene, so pick up some operation which will do as less + * as possible. + * + * TODO(sergey): We can introduce explicit exit operation which + * does nothing and which is only used to cascade flush down the + * road. + */ + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_VIEW_LAYER_DONE; + } + else if (id_type == ID_OB) { + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS; + } + else { + *component_type = DEG_NODE_TYPE_BATCH_CACHE; + *operation_code = DEG_OPCODE_GEOMETRY_SELECT_UPDATE; + } } -void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag) +void depsgraph_base_flags_tag_to_component_opcode( + const ID *id, + eDepsNode_Type *component_type, + eDepsOperation_Code *operation_code) { - 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. - */ - ID_Type idtype = GS(id->name); - if (idtype == ID_OB) { - Object *object = (Object *)id; - object->recalc |= (flag & OB_RECALC_ALL); - } + const ID_Type id_type = GS(id->name); + if (id_type == ID_SCE) { + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_VIEW_LAYER_INIT; + } + else if (id_type == ID_OB) { + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS; + } +} - if (flag & OB_RECALC_OB) - lib_id_recalc_tag(bmain, id); - if (flag & (OB_RECALC_DATA | PSYS_RECALC)) - lib_id_recalc_data_tag(bmain, id); +void depsgraph_tag_to_component_opcode(const ID *id, + eDepsgraph_Tag tag, + eDepsNode_Type *component_type, + eDepsOperation_Code *operation_code) +{ + const ID_Type id_type = GS(id->name); + *component_type = DEG_NODE_TYPE_UNDEFINED; + *operation_code = DEG_OPCODE_OPERATION; + /* Special case for now, in the future we should get rid of this. */ + if (tag == 0) { + *component_type = DEG_NODE_TYPE_ID_REF; + *operation_code = DEG_OPCODE_OPERATION; + return; } - else { - lib_id_recalc_tag(bmain, id); + switch (tag) { + case DEG_TAG_TRANSFORM: + *component_type = DEG_NODE_TYPE_TRANSFORM; + break; + case DEG_TAG_GEOMETRY: + depsgraph_geometry_tag_to_component(id, component_type); + break; + case DEG_TAG_TIME: + *component_type = DEG_NODE_TYPE_ANIMATION; + break; + case DEG_TAG_PSYS_REDO: + case DEG_TAG_PSYS_RESET: + case DEG_TAG_PSYS_TYPE: + case DEG_TAG_PSYS_CHILD: + case DEG_TAG_PSYS_PHYS: + if (id_type == ID_PA) { + /* NOTES: + * - For particle settings node we need to use different + * component. Will be nice to get this unified with object, + * but we can survive for now with single exception here. + * Particles needs reconsideration anyway, + * - We do direct injection of particle settings recalc flag + * here. This is what we need to do for until particles + * are switched away from own recalc flag and are using + * ID->recalc flags instead. + */ + ParticleSettings *particle_settings = (ParticleSettings *)id; + particle_settings->recalc |= (tag & DEG_TAG_PSYS_ALL); + *component_type = DEG_NODE_TYPE_PARAMETERS; + } + else { + *component_type = DEG_NODE_TYPE_EVAL_PARTICLES; + } + break; + case DEG_TAG_COPY_ON_WRITE: + *component_type = DEG_NODE_TYPE_COPY_ON_WRITE; + break; + case DEG_TAG_SHADING_UPDATE: + if (id_type == ID_NT) { + *component_type = DEG_NODE_TYPE_SHADING_PARAMETERS; + } + else { + *component_type = DEG_NODE_TYPE_SHADING; + } + break; + case DEG_TAG_SELECT_UPDATE: + depsgraph_select_tag_to_component_opcode(id, + component_type, + operation_code); + break; + case DEG_TAG_BASE_FLAGS_UPDATE: + depsgraph_base_flags_tag_to_component_opcode(id, + component_type, + operation_code); + case DEG_TAG_EDITORS_UPDATE: + /* There is no such node in depsgraph, this tag is to be handled + * separately. + */ + break; + case DEG_TAG_PSYS_ALL: + BLI_assert(!"Should not happen"); + break; + } +} + +void id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, ID *id, int flag) +{ + bNodeTree *ntree = ntreeFromID(id); + if (ntree == NULL) { + return; } + deg_graph_id_tag_update(bmain, graph, &ntree->id, flag); } -#ifdef DEPSGRAPH_USE_LEGACY_TAGGING -void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, short flag) +void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id) { - 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: We handle this immediately, without delaying anything, to be + * sure we don't cause threading issues with OpenGL. + */ + /* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */ + DEGEditorUpdateContext update_ctx = {NULL}; + update_ctx.bmain = bmain; + update_ctx.depsgraph = (::Depsgraph *)graph; + update_ctx.scene = graph->scene; + update_ctx.view_layer = graph->view_layer; + deg_editors_id_update(&update_ctx, id); +} + +void deg_graph_id_tag_update_single_flag(Main *bmain, + Depsgraph *graph, + ID *id, + IDDepsNode *id_node, + eDepsgraph_Tag tag) +{ + if (tag == DEG_TAG_EDITORS_UPDATE) { + if (graph != NULL) { + depsgraph_update_editors_tag(bmain, graph, id); + } + return; + } + /* Get description of what is to be tagged. */ + eDepsNode_Type component_type; + eDepsOperation_Code operation_code; + depsgraph_tag_to_component_opcode(id, + tag, + &component_type, + &operation_code); + /* Check whether we've got something to tag. */ + if (component_type == DEG_NODE_TYPE_UNDEFINED) { + /* Given ID does not support tag. */ + /* TODO(sergey): Shall we raise some panic here? */ + return; + } + /* Tag ID recalc flag. */ + DepsNodeFactory *factory = deg_type_get_factory(component_type); + BLI_assert(factory != NULL); + id->recalc |= factory->id_recalc_tag(); + /* Some sanity checks before moving forward. */ + if (id_node == NULL) { + /* Happens when object is tagged for update and not yet in the + * dependency graph (but will be after relations update). + */ + return; + } + /* Tag corresponding dependency graph operation for update. */ + if (component_type == DEG_NODE_TYPE_ID_REF) { + id_node->tag_update(graph); + } + else { + ComponentDepsNode *component_node = + id_node->find_component(component_type); + if (component_node != NULL) { + if (operation_code == DEG_OPCODE_OPERATION) { + component_node->tag_update(graph); + } + else { + OperationDepsNode *operation_node = + component_node->find_operation(operation_code); + if (operation_node != NULL) { + operation_node->tag_update(graph); } } } } } -#endif -} /* namespace */ +void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag) +{ + IDDepsNode *id_node = (graph != NULL) ? graph->find_id_node(id) + : NULL; + DEG_id_type_tag(bmain, GS(id->name)); + if (flag == 0) { + /* TODO(sergey): Which recalc flags to set here? */ + id->recalc |= ID_RECALC_ALL; + if (id_node != NULL) { + id_node->tag_update(graph); + } + } + int current_flag = flag; + while (current_flag != 0) { + eDepsgraph_Tag tag = + (eDepsgraph_Tag)(1 << bitscan_forward_clear_i(¤t_flag)); + deg_graph_id_tag_update_single_flag(bmain, + graph, + id, + id_node, + tag); + } + /* Special case for nested node tree datablocks. */ + id_tag_update_ntree_special(bmain, graph, id, flag); +} -/* 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) +void deg_id_tag_update(Main *bmain, ID *id, int flag) { - 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); + deg_graph_id_tag_update(bmain, NULL, id, flag); + LINKLIST_FOREACH(Scene *, scene, &bmain->scene) { + LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + Depsgraph *depsgraph = + (Depsgraph *)BKE_scene_get_depsgraph(scene, + view_layer, + false); + if (depsgraph != NULL) { + deg_graph_id_tag_update(bmain, depsgraph, id, flag); + } + } } } +void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph) +{ + /* Make sure objects are up to date. */ + foreach (DEG::IDDepsNode *id_node, graph->id_nodes) { + const ID_Type id_type = GS(id_node->id_orig->name); + 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); + } + /* Make sure collection properties are up to date. */ + for (Scene *scene_iter = graph->scene; + scene_iter != NULL; + scene_iter = scene_iter->set) + { + IDDepsNode *scene_id_node = graph->find_id_node(&scene_iter->id); + BLI_assert(scene_id_node != NULL); + scene_id_node->tag_update(graph); + } +} + +} /* namespace */ + +} // namespace DEG + +/* Data-Based Tagging */ + /* Tag given ID for an update in all the dependency graphs. */ -void DEG_id_tag_update(ID *id, short flag) +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, short 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); - 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); - } - } - } + DEG::deg_id_tag_update(bmain, 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_id_tag_update(struct Main *bmain, + struct Depsgraph *depsgraph, + struct ID *id, + int flag) +{ + DEG::Depsgraph *graph = (DEG::Depsgraph *)depsgraph; + DEG::deg_graph_id_tag_update(bmain, graph, id, flag); } /* Mark a particular datablock type as having changing. */ -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. */ @@ -236,132 +435,35 @@ 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; -} - -/* 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) -{ - for (Scene *scene = (Scene *)bmain->scene.first; - scene != NULL; - scene = (Scene *)scene->id.next) - { - DEG_scene_flush_update(bmain, scene); - } + bmain->id_tag_update[BKE_idcode_to_index(id_type)] = 1; } -void DEG_scene_flush_update(Main *bmain, Scene *scene) +void DEG_graph_flush_update(Main *bmain, Depsgraph *depsgraph) { - if (scene->depsgraph == NULL) { + if (depsgraph == NULL) { return; } - DEG::deg_graph_flush_updates( - bmain, - reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph)); + DEG::deg_graph_flush_updates(bmain, (DEG::Depsgraph *)depsgraph); } /* Update dependency graph when visible scenes/layers changes. */ -void DEG_graph_on_visible_update(Main *bmain, Scene *scene) +void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph) { - 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. - */ - foreach (DEG::IDDepsNode *id_node, graph->id_nodes) { - ID *id = id_node->id; - if ((id->recalc & 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->recalc & 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); - } - } - } - } - } - scene->lay_updated |= graph->layers; - /* If graph is tagged for update, we don't need to bother with updates here, - * nodes will be re-created. - */ - if (graph->need_update) { - return; - } - /* 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 *)depsgraph; + DEG::deg_graph_on_visible_update(bmain, graph); } void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time)) { - for (Scene *scene = (Scene *)bmain->scene.first; - scene != NULL; - scene = (Scene *)scene->id.next) - { - if (scene->depsgraph != NULL) { - DEG_graph_on_visible_update(bmain, scene); + LINKLIST_FOREACH(Scene *, scene, &bmain->scene) { + LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + Depsgraph *depsgraph = + (Depsgraph *)BKE_scene_get_depsgraph(scene, + view_layer, + false); + if (depsgraph != NULL) { + DEG_graph_on_visible_update(bmain, depsgraph); + } } } } @@ -369,7 +471,11 @@ void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time)) /* Check if something was changed in the database and inform * editors about this. */ -void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time) +void DEG_ids_check_recalc(Main *bmain, + Depsgraph *depsgraph, + Scene *scene, + ViewLayer *view_layer, + bool time) { ListBase *lbarray[MAX_LIBARRAY]; int a; @@ -387,7 +493,12 @@ void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time) } } - DEG::deg_editors_scene_update(bmain, scene, (updated || time)); + DEGEditorUpdateContext update_ctx = {NULL}; + update_ctx.bmain = bmain; + update_ctx.depsgraph = depsgraph; + update_ctx.scene = scene; + update_ctx.view_layer = view_layer; + DEG::deg_editors_scene_update(&update_ctx, (updated || time)); } void DEG_ids_clear_recalc(Main *bmain) |