[Bf-blender-cvs] [31041d8] depsgraph_refactor: Depsgraph: Solution for missing update tag when adding new object

Sergey Sharybin noreply at git.blender.org
Mon Dec 8 14:59:42 CET 2014


Commit: 31041d86b7a4754ced3ededc28624844165687eb
Author: Sergey Sharybin
Date:   Mon Dec 8 18:51:43 2014 +0500
Branches: depsgraph_refactor
https://developer.blender.org/rB31041d86b7a4754ced3ededc28624844165687eb

Depsgraph: Solution for missing update tag when adding new object

The issue was caused by new object add tagging object for recalc and tagging
relations for update. With new dependency graph it lead to situation when
ID tags are simply lost because of the whole graph being rebuilt.

The idea of this change is:

- Relations update tag doesn't destroy graph, it only stores flag in the
  graph that it's relations need to be updated.

- ID tagging now stores an ID which is currently missing in the dependency
  graph. Tag of those IDs would happen later after relations are all up to
  date.

- Relations update reconstructs the graph and re-tags all the nodes which
  were previously tagged for recalc.

This gives quite the same behavior that with old dependency graph, making
it possible to store recalc tags separately from the graph nodes themselves
in order to be able to invalidate graph without rebuilding it and still
have proper track for what's changed. This is a crucial thing to have in
order to have reasonable speed of python scripts.

Alternative to a separate storage in the Depsgraph would be to re-use
recalc flags stored in the ID itself.

There are probably some more tweaks to be done in this area, let's see
how this behaves for now.

P.S. This change also seems to solve issues with missing updates of the
armatures when exiting edit mode.

===================================================================

M	source/blender/blenkernel/intern/depsgraph.c
M	source/blender/depsgraph/DEG_depsgraph_build.h
M	source/blender/depsgraph/intern/depsgraph.cpp
M	source/blender/depsgraph/intern/depsgraph.h
M	source/blender/depsgraph/intern/depsgraph_build.cpp
M	source/blender/depsgraph/intern/depsgraph_tag.cpp

===================================================================

diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index f0425a1..91eac59 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -982,10 +982,10 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask)
 	// solve_cycles(dag);
 	
 	/********* new depsgraph *********/
-	if (sce->depsgraph)
-		DEG_graph_free(sce->depsgraph);
-	sce->depsgraph = DEG_graph_new();
-	DEG_graph_build_from_scene(sce->depsgraph, bmain, sce);
+	if (sce->depsgraph == NULL) {
+		sce->depsgraph = DEG_graph_new();
+		DEG_graph_build_from_scene(sce->depsgraph, bmain, sce);
+	}
 	/******************/
 	
 	return dag;
@@ -1398,16 +1398,16 @@ static void scene_sort_groups(Main *bmain, Scene *sce)
 }
 
 /* free the depency graph */
-static void dag_scene_free(Scene *sce)
+static void dag_scene_free(Scene *sce, bool free_new_graph)
 {
 	if (sce->theDag) {
 		free_forest(sce->theDag);
 		MEM_freeN(sce->theDag);
 		sce->theDag = NULL;
 	}
-	
+
 	/********* new depsgraph *********/
-	if (sce->depsgraph) {
+	if (sce->depsgraph && free_new_graph) {
 		DEG_graph_free(sce->depsgraph);
 		sce->depsgraph = NULL;
 	}
@@ -1533,7 +1533,7 @@ static void dag_invisible_dependencies_check_flush(Main *bmain, Scene *scene)
 }
 
 /* sort the base list on dependency order */
-static void dag_scene_build(Main *bmain, Scene *sce)
+static void dag_scene_build(Main *bmain, Scene *sce, bool rebuild_new_graph)
 {
 	DagNode *node, *rootnode;
 	DagNodeQueue *nqueue;
@@ -1544,7 +1544,14 @@ static void dag_scene_build(Main *bmain, Scene *sce)
 	Base *base;
 
 	BLI_listbase_clear(&tempbase);
-	
+
+	/********* new depsgraph *********/
+	if (rebuild_new_graph && sce->depsgraph != NULL) {
+		DEG_graph_free(sce->depsgraph);
+		sce->depsgraph = NULL;
+	}
+	/******************/
+
 	build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA);
 	
 	dag_check_cycle(sce->theDag);
@@ -1637,23 +1644,29 @@ static void dag_scene_build(Main *bmain, Scene *sce)
 void DAG_relations_tag_update(Main *bmain)
 {
 	Scene *sce;
-
-	for (sce = bmain->scene.first; sce; sce = sce->id.next)
-		dag_scene_free(sce);
+	for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+		dag_scene_free(sce, false);
+		if (sce->depsgraph != NULL) {
+			DEG_graph_tag_relations_update(sce->depsgraph);
+		}
+	}
 }
 
 /* rebuild dependency graph only for a given scene */
 void DAG_scene_relations_rebuild(Main *bmain, Scene *sce)
 {
-	dag_scene_free(sce);
+	dag_scene_free(sce, true);
 	DAG_scene_relations_update(bmain, sce);
 }
 
 /* create dependency graph if it was cleared or didn't exist yet */
 void DAG_scene_relations_update(Main *bmain, Scene *sce)
 {
+	if (sce->depsgraph != NULL) {
+		DEG_scene_relations_update(bmain, sce);
+	}
 	if (!sce->theDag)
-		dag_scene_build(bmain, sce);
+		dag_scene_build(bmain, sce, false);
 }
 
 /* Tag specific ID node for rebuild, keep rest of the graph untouched. */
@@ -1683,7 +1696,7 @@ void DAG_scene_free(Scene *sce)
 		MEM_freeN(sce->theDag);
 		sce->theDag = NULL;
 	}
-	
+
 	/********* new depsgraph *********/
 	if (sce->depsgraph) {
 		DEG_graph_free(sce->depsgraph);
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index df7c907..83a4d74 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -51,14 +51,19 @@ extern "C" {
 #if 0 /* XXX unused, old API functions */
 /* Rebuild dependency graph only for a given scene */
 void DEG_scene_relations_rebuild(Depsgraph *graph, struct Main *bmain, struct Scene *scene);
-
-/* Create dependency graph if it was cleared or didn't exist yet */
-void DEG_scene_relations_update(struct Main *bmain, struct Scene *scene);
 #endif
 
 /* Build depsgraph for the given scene, and dump results in given graph container */
 void DEG_graph_build_from_scene(struct Depsgraph *graph, struct Main *bmain, struct Scene *scene);
 
+/* Tag relations for update. */
+void DEG_graph_tag_relations_update(struct Depsgraph *graph);
+
+/* Create new graph if didn't exist yet,
+ * or update relations if graph was tagged for update.
+ */
+void DEG_scene_relations_update(struct Main *bmain, struct Scene *scene);
+
 /* Add Dependencies  ----------------------------- */
 
 /* Handle for components to define their dependencies from callbacks.
diff --git a/source/blender/depsgraph/intern/depsgraph.cpp b/source/blender/depsgraph/intern/depsgraph.cpp
index ef2bda1..4505318 100644
--- a/source/blender/depsgraph/intern/depsgraph.cpp
+++ b/source/blender/depsgraph/intern/depsgraph.cpp
@@ -328,6 +328,24 @@ void Depsgraph::add_entry_tag(OperationDepsNode *node)
 	this->entry_tags.insert(node);
 }
 
+/* Tag a specific ID as needing updates. */
+void Depsgraph::add_id_tag(const ID *id)
+{
+	/* Tagging of actual operations happens in DEG_scene_relations_update(). */
+	this->id_tags.insert(id);
+}
+
+void Depsgraph::clear_all_nodes()
+{
+	if (this->root_node) {
+		OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
+		root_node = NULL;
+	}
+	clear_id_nodes();
+	clear_subgraph_nodes();
+	id_hash.clear();
+}
+
 /* ************************************************** */
 /* Public Graph API */
 
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 10a4dcc..747acd3 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -98,6 +98,7 @@ struct Depsgraph {
 	typedef unordered_map<const ID *, IDDepsNode *> IDNodeMap;
 	typedef unordered_set<SubgraphDepsNode *> Subgraphs;
 	typedef unordered_set<OperationDepsNode *> EntryTags;
+	typedef unordered_set<const ID *> IDTags;
 	typedef vector<OperationDepsNode *> OperationNodes;
 
 	Depsgraph();
@@ -154,6 +155,12 @@ struct Depsgraph {
 	/* Tag a specific node as needing updates. */
 	void add_entry_tag(OperationDepsNode *node);
 
+	/* Tag a specific ID as needing updates. */
+	void add_id_tag(const ID *id);
+
+	/* Clear storage used by all nodes. */
+	void clear_all_nodes();
+
 	/* Core Graph Functionality ........... */
 
 	/* <ID : IDDepsNode> mapping from ID blocks to nodes representing these blocks
@@ -166,11 +173,19 @@ struct Depsgraph {
 	/* Subgraphs referenced in tree. */
 	Subgraphs subgraphs;
 
+	/* Indicates whether relations needs to be updated. */
+	bool need_update;
+
 	/* Quick-Access Temp Data ............. */
 
 	/* Nodes which have been tagged as "directly modified". */
 	EntryTags entry_tags;
 
+	/* Nodes which have been tagged for update but were missing
+	 * in the current dependency graph.
+	 */
+	IDTags id_tags;
+
 	/* Convenience Data ................... */
 
 	/* XXX: should be collected after building (if actually needed?) */
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cpp b/source/blender/depsgraph/intern/depsgraph_build.cpp
index 4210a84..ab6d534 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cpp
+++ b/source/blender/depsgraph/intern/depsgraph_build.cpp
@@ -480,5 +480,60 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
 	deg_graph_transitive_reduction(graph);
 }
 
-/* ************************************************* */
+/* Tag relations for update. */
+void DEG_graph_tag_relations_update(Depsgraph *graph)
+{
+	graph->need_update = true;
+}
+
+/* Create new graph if didn't exist yet,
+ * or update relations if graph was tagged for update.
+ */
+void DEG_scene_relations_update(Main *bmain, Scene *scene)
+{
+	if (scene->depsgraph == NULL) {
+		/* Rebuild graph from scratch and exit. */
+		scene->depsgraph = DEG_graph_new();
+		DEG_graph_build_from_scene(scene->depsgraph, bmain, scene);
+		return;
+	}
+
+	Depsgraph *graph = scene->depsgraph;
+	if (!graph->need_update) {
+		/* Graph is up to date, nothing to do. */
+		return;
+	}
 
+	/* Store all oeprations which needs to be re-tagged in new graph. */
+	for (Depsgraph::EntryTags::const_iterator it = graph->entry_tags.begin();
+	     it != graph->entry_tags.end();
+	     ++it)
+	{
+		OperationDepsNode *node = *it;
+		/* TODO(sergey): Ideally we'll need to only re-tag operations,
+		 * not the whole ID nodes.
+		 */
+		graph->add_id_tag(node->owner->owner->id);
+	}
+
+	/* Clear all previous nodes and operations. */
+	graph->clear_all_nodes();
+	graph->operations.clear();
+	graph->entry_tags.clear();
+
+	/* Build new nodes and relations. */
+	DEG_graph_build_from_scene(graph, bmain, scene);
+
+	for (Depsgraph::IDTags::const_iterator it = graph->id_tags.begin();
+	     it != graph->id_tags.end();
+	     ++it)
+	{
+		const ID *id = *it;
+		DEG_id_tag_update(graph, id);
+	}
+	graph->id_tags.clear();
+
+	graph->need_update = false;
+}
+
+/* ************************************************* */
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cpp b/source/blender/depsgraph/intern/depsgraph_tag.cpp
index 9598daf..9ed8b0f 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cpp
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cpp
@@ -57,10 +57,13 @@ extern "C" {
 void DEG_id_tag_update(Depsgraph *graph, const ID *id)
 {
 	IDDepsNode *node = graph->find_id_node(id);
-	if (node)
+	if (node) {
 		node->tag_update(graph);
-	else
-		printf("Missing node in %s, id %s\n", __func__, id->name);
+	}
+	else {
+		/* Store the ID for tagging later. */
+		graph->add_id_tag(id);
+	}
 }
 
 /* Tag nodes related to a specific piece of data */




More information about the Bf-blender-cvs mailing list