diff options
Diffstat (limited to 'source/blender/depsgraph/intern/depsgraph_tag.cc')
-rw-r--r-- | source/blender/depsgraph/intern/depsgraph_tag.cc | 816 |
1 files changed, 556 insertions, 260 deletions
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 948e4fc1f1b..9128571155f 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -35,20 +35,28 @@ #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_anim_types.h" +#include "DNA_curve_types.h" +#include "DNA_key_types.h" +#include "DNA_lattice_types.h" +#include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "DNA_particle_types.h" #include "DNA_screen_types.h" #include "DNA_windowmanager_types.h" - +#include "BKE_animsys.h" #include "BKE_idcode.h" #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" @@ -56,6 +64,7 @@ extern "C" { } /* extern "C" */ #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "intern/builder/deg_builder.h" #include "intern/eval/deg_eval_flush.h" @@ -70,298 +79,572 @@ 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 lib_id_recalc_tag(Main *bmain, ID *id) -{ - id->recalc |= ID_RECALC; - DEG_id_type_tag(bmain, GS(id->name)); -} +void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag); -void lib_id_recalc_data_tag(Main *bmain, ID *id) +void depsgraph_geometry_tag_to_component(const ID *id, + eDepsNode_Type *component_type) { - id->recalc |= ID_RECALC_DATA; - 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_LATTICE: + 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_tag_flag(Main *bmain, ID *id, int flag) +void depsgraph_select_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. + 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. * - * But this flag will also let us to re-construct entry - * nodes for update after relations update and after layer - * visibility changes. + * TODO(sergey): We can introduce explicit exit operation which + * does nothing and which is only used to cascade flush down the + * road. */ - ID_Type idtype = GS(id->name); - if (idtype == ID_OB) { - Object *object = (Object *)id; - object->recalc |= (flag & OB_RECALC_ALL); - } - - 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); + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_VIEW_LAYER_EVAL; + } + else if (id_type == ID_OB) { + *component_type = DEG_NODE_TYPE_OBJECT_FROM_LAYER; + *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS; } else { - lib_id_recalc_tag(bmain, id); + *component_type = DEG_NODE_TYPE_BATCH_CACHE; + *operation_code = DEG_OPCODE_GEOMETRY_SELECT_UPDATE; } } -#ifdef DEPSGRAPH_USE_LEGACY_TAGGING -void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, short flag) +void depsgraph_base_flags_tag_to_component_opcode( + const ID *id, + eDepsNode_Type *component_type, + eDepsOperation_Code *operation_code) { - 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); - } - } - } - } + 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_EVAL; + } + else if (id_type == ID_OB) { + *component_type = DEG_NODE_TYPE_OBJECT_FROM_LAYER; + *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS; } } -#endif -} /* namespace */ +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; + } + 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, + */ + *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; + } +} -/* 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 id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, 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); + bNodeTree *ntree = ntreeFromID(id); + if (ntree == NULL) { + return; } + deg_graph_id_tag_update(bmain, graph, &ntree->id, flag); } -/* Tag given ID for an update in all the dependency graphs. */ -void DEG_id_tag_update(ID *id, short flag) +void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id) { - DEG_id_tag_update_ex(G.main, id, flag); + /* 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_id_tag_update_ex(Main *bmain, ID *id, short flag) +void depsgraph_tag_component(Depsgraph *graph, + IDDepsNode *id_node, + eDepsNode_Type component_type, + eDepsOperation_Code operation_code) { - if (id == NULL) { - /* Ideally should not happen, but old depsgraph allowed this. */ + ComponentDepsNode *component_node = + id_node->find_component(component_type); + if (component_node == NULL) { return; } - DEG_DEBUG_PRINTF(TAG, "%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) { + 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); + } + } + /* If component depends on copy-on-write, tag it as well. */ + if (component_node->need_tag_cow_before_update()) { + ComponentDepsNode *cow_comp = + id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE); + cow_comp->tag_update(graph); + id_node->id_orig->recalc |= ID_RECALC_COPY_ON_WRITE; + } +} + +/* This is a tag compatibility with legacy code. + * + * Mainly, old code was tagging object with OB_RECALC_DATA tag to inform + * that object's data datablock changed. Now API expects that ID is given + * explicitly, but not all areas are aware of this yet. + */ +void deg_graph_id_tag_legacy_compat(Main *bmain, + ID *id, + eDepsgraph_Tag tag) +{ + if (tag == DEG_TAG_GEOMETRY || tag == 0) { + switch (GS(id->name)) { + case ID_OB: + { Object *object = (Object *)id; - if (object->data != NULL) { - DEG_graph_id_tag_update(bmain, - graph, - (ID *)object->data); + ID *data_id = (ID *)object->data; + if (data_id != NULL) { + DEG_id_tag_update_ex(bmain, data_id, 0); + } + break; + } + /* TODO(sergey): Shape keys are annoying, maybe we should find a + * way to chain geometry evaluation to them, so we don't need extra + * tagging here. + */ + case ID_ME: + { + Mesh *mesh = (Mesh *)id; + ID *key_id = &mesh->key->id; + if (key_id != NULL) { + DEG_id_tag_update_ex(bmain, key_id, 0); } + break; } - if (flag & (OB_RECALC_OB | OB_RECALC_DATA)) { - DEG_graph_id_tag_update(bmain, graph, id); + case ID_LT: + { + Lattice *lattice = (Lattice *)id; + ID *key_id = &lattice->key->id; + if (key_id != NULL) { + DEG_id_tag_update_ex(bmain, key_id, 0); + } + break; } - else if (flag & OB_RECALC_TIME) { - DEG_graph_id_tag_update(bmain, graph, id); + case ID_CU: + { + Curve *curve = (Curve *)id; + ID *key_id = &curve->key->id; + if (key_id != NULL) { + DEG_id_tag_update_ex(bmain, key_id, 0); + } + break; } + default: + break; } } +} -#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. +static 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 { + depsgraph_tag_component(graph, id_node, component_type, operation_code); + } + /* TODO(sergey): Get rid of this once all areas are using proper data ID + * for tagging. */ - depsgraph_legacy_handle_update_tag(bmain, id, flag); -#endif + deg_graph_id_tag_legacy_compat(bmain, id, tag); + } -/* Mark a particular datablock type as having changing. */ -void DEG_id_type_tag(Main *bmain, short idtype) +string stringify_append_bit(const string& str, eDepsgraph_Tag tag) { - if (idtype == ID_NT) { - /* Stupid workaround so parent datablocks of nested nodetree get looped - * over when we loop over tagged datablock types. - */ - DEG_id_type_tag(bmain, ID_MA); - DEG_id_type_tag(bmain, ID_TE); - DEG_id_type_tag(bmain, ID_LA); - DEG_id_type_tag(bmain, ID_WO); - DEG_id_type_tag(bmain, ID_SCE); + string result = str; + if (!result.empty()) { + result += ", "; } + result += DEG_update_tag_as_string(tag); + return result; +} - bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1; +string stringify_update_bitfield(int flag) +{ + if (flag == 0) { + return "LEGACY_0"; + } + string result = ""; + int current_flag = flag; + /* Special cases to avoid ALL flags form being split into + * individual bits. + */ + if ((current_flag & DEG_TAG_PSYS_ALL) == DEG_TAG_PSYS_ALL) { + result = stringify_append_bit(result, DEG_TAG_PSYS_ALL); + } + /* Handle all the rest of the flags. */ + while (current_flag != 0) { + eDepsgraph_Tag tag = + (eDepsgraph_Tag)(1 << bitscan_forward_clear_i(¤t_flag)); + result = stringify_append_bit(result, tag); + } + return result; } -/* Recursively push updates out to all nodes dependent on this, - * until all affected are tagged and/or scheduled up for eval +/* Special tag function which tags all components which needs to be tagged + * for update flag=0. + * + * TODO(sergey): This is something to be avoid in the future, make it more + * explicit and granular for users to tag what they really need. */ -void DEG_ids_flush_tagged(Main *bmain) +void deg_graph_node_tag_zero(Main *bmain, Depsgraph *graph, IDDepsNode *id_node) { - for (Scene *scene = (Scene *)bmain->scene.first; - scene != NULL; - scene = (Scene *)scene->id.next) + if (id_node == NULL) { + return; + } + ID *id = id_node->id_orig; + /* TODO(sergey): Which recalc flags to set here? */ + id->recalc |= ID_RECALC_ALL & ~(DEG_TAG_PSYS_ALL | ID_RECALC_ANIMATION); + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components) { - DEG_scene_flush_update(bmain, scene); + if (comp_node->type == DEG_NODE_TYPE_ANIMATION) { + continue; + } + comp_node->tag_update(graph); } + GHASH_FOREACH_END(); + deg_graph_id_tag_legacy_compat(bmain, id, (eDepsgraph_Tag)0); } -void DEG_scene_flush_update(Main *bmain, Scene *scene) +void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag) { - if (scene->depsgraph == NULL) { - return; + const int debug_flags = (graph != NULL) + ? DEG_debug_flags_get((::Depsgraph *)graph) + : G.debug; + if (debug_flags & G_DEBUG_DEPSGRAPH_TAG) { + printf("%s: id=%s flags=%s\n", + __func__, + id->name, + stringify_update_bitfield(flag).c_str()); + } + IDDepsNode *id_node = (graph != NULL) ? graph->find_id_node(id) + : NULL; + DEG_id_type_tag(bmain, GS(id->name)); + if (flag == 0) { + deg_graph_node_tag_zero(bmain, graph, id_node); + } + id->recalc |= (flag & PSYS_RECALC); + 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); } - DEG::deg_graph_flush_updates( - bmain, - reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph)); + /* Special case for nested node tree datablocks. */ + id_tag_update_ntree_special(bmain, graph, id, flag); } -/* Update dependency graph when visible scenes/layers changes. */ -void DEG_graph_on_visible_update(Main *bmain, Scene *scene) +void deg_id_tag_update(Main *bmain, ID *id, int flag) { - 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; + deg_graph_id_tag_update(bmain, NULL, id, flag); + LISTBASE_FOREACH (Scene *, scene, &bmain->scene) { + LISTBASE_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); } } } - 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. +} + +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 = DEG_TAG_COPY_ON_WRITE; + /* 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). * - * This is mainly needed on file load only, after that updates of invisible objects - * will be stored in the pending list. + * TODO(sergey): Need to generalize this somehow. */ - 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); - } - } - } + if (id_type == ID_OB) { + flag |= OB_RECALC_OB | OB_RECALC_DATA; } + deg_graph_id_tag_update(bmain, graph, id_node->id_orig, flag); } - 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) { + /* 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); + if (scene_id_node != NULL) { + scene_id_node->tag_update(graph); + } + else { + BLI_assert(graph->need_update); + } + } +} + +} /* namespace */ + +} // namespace DEG + +const char *DEG_update_tag_as_string(eDepsgraph_Tag flag) +{ + switch (flag) { + case DEG_TAG_TRANSFORM: return "TRANSFORM"; + case DEG_TAG_GEOMETRY: return "GEOMETRY"; + case DEG_TAG_TIME: return "TIME"; + case DEG_TAG_PSYS_REDO: return "PSYS_REDO"; + case DEG_TAG_PSYS_RESET: return "PSYS_RESET"; + case DEG_TAG_PSYS_TYPE: return "PSYS_TYPE"; + case DEG_TAG_PSYS_CHILD: return "PSYS_CHILD"; + case DEG_TAG_PSYS_PHYS: return "PSYS_PHYS"; + case DEG_TAG_PSYS_ALL: return "PSYS_ALL"; + case DEG_TAG_COPY_ON_WRITE: return "COPY_ON_WRITE"; + case DEG_TAG_SHADING_UPDATE: return "SHADING_UPDATE"; + case DEG_TAG_SELECT_UPDATE: return "SELECT_UPDATE"; + case DEG_TAG_BASE_FLAGS_UPDATE: return "BASE_FLAGS_UPDATE"; + case DEG_TAG_EDITORS_UPDATE: return "EDITORS_UPDATE"; + } + BLI_assert(!"Unhandled update flag, should never happen!"); + return "UNKNOWN"; +} + +/* Data-Based Tagging */ + +/* 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; } - /* Special trick to get local view to work. */ - LISTBASE_FOREACH (Base *, base, &scene->base) { - Object *object = base->object; - DEG::IDDepsNode *id_node = graph->find_id_node(&object->id); - id_node->layers = 0; - } - LISTBASE_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 || object->type == OB_CAMERA) { - /* Camera should always be updated, it used directly by viewport. */ - id_node->layers |= (unsigned int)(-1); - } + DEG::deg_id_tag_update(bmain, id, flag); +} + +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 id_type) +{ + if (id_type == ID_NT) { + /* Stupid workaround so parent datablocks of nested nodetree get looped + * over when we loop over tagged datablock types. + */ + DEG_id_type_tag(bmain, ID_MA); + DEG_id_type_tag(bmain, ID_TE); + DEG_id_type_tag(bmain, ID_LA); + DEG_id_type_tag(bmain, ID_WO); + DEG_id_type_tag(bmain, ID_SCE); } - DEG::deg_graph_build_flush_layers(graph); - LISTBASE_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; + + int id_type_index = BKE_idcode_to_index(id_type); + + LISTBASE_FOREACH (Scene *, scene, &bmain->scene) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + Depsgraph *depsgraph = + (Depsgraph *)BKE_scene_get_depsgraph(scene, + view_layer, + false); + if (depsgraph != NULL) { + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); + deg_graph->id_type_updated[id_type_index] = 1; + } } - GHASH_FOREACH_END(); } } +void DEG_graph_flush_update(Main *bmain, Depsgraph *depsgraph) +{ + if (depsgraph == NULL) { + return; + } + 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, Depsgraph *depsgraph) +{ + 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); + LISTBASE_FOREACH (Scene *, scene, &bmain->scene) { + LISTBASE_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,55 +652,68 @@ 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; - bool updated = false; - - /* Loop over all ID types. */ - a = set_listbasepointers(bmain, lbarray); - while (a--) { - ListBase *lb = lbarray[a]; - ID *id = (ID *)lb->first; - - if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { - updated = true; - break; - } - } + bool updated = time || DEG_id_type_any_updated(depsgraph); + + 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); +} - DEG::deg_editors_scene_update(bmain, scene, (updated || time)); +static void deg_graph_clear_id_node_func( + void *__restrict data_v, + const int i, + const ParallelRangeTLS *__restrict /*tls*/) +{ + /* TODO: we clear original ID recalc flags here, but this may not work + * correctly when there are multiple depsgraph with others still using + * the recalc flag. */ + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(data_v); + DEG::IDDepsNode *id_node = deg_graph->id_nodes[i]; + id_node->id_cow->recalc &= ~ID_RECALC_ALL; + id_node->id_orig->recalc &= ~ID_RECALC_ALL; + + /* Clear embedded node trees too. */ + bNodeTree *ntree_cow = ntreeFromID(id_node->id_cow); + if (ntree_cow) { + ntree_cow->id.recalc &= ~ID_RECALC_ALL; + } + bNodeTree *ntree_orig = ntreeFromID(id_node->id_orig); + if (ntree_orig) { + ntree_orig->id.recalc &= ~ID_RECALC_ALL; + } } -void DEG_ids_clear_recalc(Main *bmain) +void DEG_ids_clear_recalc(Main *UNUSED(bmain), + Depsgraph *depsgraph) { - ListBase *lbarray[MAX_LIBARRAY]; - bNodeTree *ntree; - int a; + DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); /* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags * and id_tags storage from the new dependency graph. */ - /* Loop over all ID types. */ - a = set_listbasepointers(bmain, lbarray); - while (a--) { - ListBase *lb = lbarray[a]; - ID *id = (ID *)lb->first; - - if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { - for (; id; id = (ID *)id->next) { - id->recalc &= ~ID_RECALC_ALL; - - /* Some ID's contain semi-datablock nodetree */ - ntree = ntreeFromID(id); - if (ntree != NULL) { - ntree->id.recalc &= ~ID_RECALC_ALL; - } - } - } + if (!DEG_id_type_any_updated(depsgraph)) { + return; } - memset(bmain->id_tag_update, 0, sizeof(bmain->id_tag_update)); + /* Go over all ID nodes nodes, clearing tags. */ + const int num_id_nodes = deg_graph->id_nodes.size(); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + BLI_task_parallel_range(0, num_id_nodes, + deg_graph, + deg_graph_clear_id_node_func, + &settings); + + memset(deg_graph->id_type_updated, 0, sizeof(deg_graph->id_type_updated)); } |