Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/depsgraph/intern/depsgraph_tag.cc')
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc816
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(&current_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(&current_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));
}