[Bf-blender-cvs] [983b1a34783] blender2.8: Depsgraph: Cleanup, simplify evaluation flush function

Sergey Sharybin noreply at git.blender.org
Fri Dec 1 16:07:56 CET 2017


Commit: 983b1a34783e9600731b973ba52ecc8924bff169
Author: Sergey Sharybin
Date:   Fri Dec 1 16:02:10 2017 +0100
Branches: blender2.8
https://developer.blender.org/rB983b1a34783e9600731b973ba52ecc8924bff169

Depsgraph: Cleanup, simplify evaluation flush function

Also avoid once queue push for cases when current operation has multiple
outgoing relations.

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

M	source/blender/depsgraph/intern/eval/deg_eval_flush.cc

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

diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index c336c1dd60f..6c491c389ca 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -63,7 +63,9 @@ enum {
 
 typedef std::deque<OperationDepsNode *> FlushQueue;
 
-static void flush_init_func(void *data_v, int i)
+namespace {
+
+void flush_init_func(void *data_v, int i)
 {
 	/* ID node's done flag is used to avoid multiple editors update
 	 * for the same ID.
@@ -77,22 +79,8 @@ static void flush_init_func(void *data_v, int i)
 	node->scheduled = false;
 }
 
-/* Flush updates from tagged nodes outwards until all affected nodes
- * are tagged.
- */
-void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
+BLI_INLINE void flush_prepare(Depsgraph *graph)
 {
-	const bool use_copy_on_write = DEG_depsgraph_use_copy_on_write();
-	/* Sanity check. */
-	if (graph == NULL) {
-		return;
-	}
-
-	/* Nothing to update, early out. */
-	if (BLI_gset_size(graph->entry_tags) == 0) {
-		return;
-	}
-
 	/* TODO(sergey): With a bit of flag magic we can get rid of this
 	 * extra loop.
 	 */
@@ -103,128 +91,163 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
 	                        graph,
 	                        flush_init_func,
 	                        do_threads);
+}
 
-	FlushQueue queue;
-	/* Starting from the tagged "entry" nodes, flush outwards... */
-	/* NOTE: Also need to ensure that for each of these, there is a path back to
-	 *       root, or else they won't be done.
-	 * NOTE: Count how many nodes we need to handle - entry nodes may be
-	 *       component nodes which don't count for this purpose!
-	 */
+BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue)
+{
 	GSET_FOREACH_BEGIN(OperationDepsNode *, op_node, graph->entry_tags)
 	{
-		queue.push_back(op_node);
+		queue->push_back(op_node);
 		op_node->scheduled = true;
 	}
 	GSET_FOREACH_END();
+}
 
-	DEGEditorUpdateContext update_ctx = {NULL};
-	update_ctx.bmain = bmain;
-	update_ctx.scene = graph->scene;
-	update_ctx.view_layer = graph->view_layer;
-
-	int num_flushed_objects = 0;
-	while (!queue.empty()) {
-		OperationDepsNode *node = queue.front();
-		queue.pop_front();
-
-		for (;;) {
-			node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
-
-			ComponentDepsNode *comp_node = node->owner;
-			IDDepsNode *id_node = comp_node->owner;
-
-			/* TODO(sergey): Do we need to pass original or evaluated ID here? */
-			ID *id_orig = id_node->id_orig;
-			ID *id_cow = id_node->id_cow;
-			if (id_node->done == 0) {
-				/* Copy tag from original data to CoW storage.
-				 * This is because DEG_id_tag_update() sets tags on original
-				 * data.
-				 */
-				id_cow->tag |= (id_orig->tag & LIB_TAG_ID_RECALC_ALL);
-				if (deg_copy_on_write_is_expanded(id_cow)) {
-					deg_editors_id_update(&update_ctx, id_cow);
-				}
-				lib_id_recalc_tag(bmain, id_orig);
-				/* TODO(sergey): For until we've got proper data nodes in the graph. */
-				lib_id_recalc_data_tag(bmain, id_orig);
-			}
+BLI_INLINE void flush_handle_id_node(Main *bmain,
+                                     IDDepsNode *id_node,
+                                     const DEGEditorUpdateContext *update_ctx)
+{
+	/* We only inform ID node once. */
+	if (id_node->done != 0) {
+		return;
+	}
+	id_node->done = 1;
+	/* TODO(sergey): Do we need to pass original or evaluated ID here? */
+	ID *id_orig = id_node->id_orig;
+	ID *id_cow = id_node->id_cow;
+	/* Copy tag from original data to CoW storage.
+	 * This is because DEG_id_tag_update() sets tags on original
+	 * data.
+	 */
+	id_cow->tag |= (id_orig->tag & LIB_TAG_ID_RECALC_ALL);
+	if (deg_copy_on_write_is_expanded(id_cow)) {
+		deg_editors_id_update(update_ctx, id_cow);
+	}
+	lib_id_recalc_tag(bmain, id_orig);
+	/* TODO(sergey): For until we've got proper data nodes in the graph. */
+	lib_id_recalc_data_tag(bmain, id_orig);
+}
 
-			if (comp_node->done != COMPONENT_STATE_DONE) {
-				/* Currently this is needed to get object->mesh to be replaced with
-				 * original mesh (rather than being evaluated_mesh).
-				 *
-				 * TODO(sergey): This is something we need to avoid.
-				 */
-				if (use_copy_on_write && comp_node->depends_on_cow()) {
-					ComponentDepsNode *cow_comp =
-					        id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE);
-					cow_comp->tag_update(graph);
-				}
-
-				if (GS(id_orig->name) == ID_OB) {
-					if (id_node->done == 0) {
-						++num_flushed_objects;
-					}
-				}
-				foreach (OperationDepsNode *op, comp_node->operations) {
-					/* We don't want to flush tags in "upstream" direction for
-					 * certain types of operations.
-					 *
-					 * TODO(sergey): Need a more generic solution for this.
-					 */
-					if (op->opcode == DEG_OPCODE_PARTICLE_SETTINGS_EVAL) {
-						continue;
-					}
-					op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
-				}
-				/* When some target changes bone, we might need to re-run the
-				 * whole IK solver, otherwise result might be unpredictable.
-				 */
-				if (comp_node->type == DEG_NODE_TYPE_BONE) {
-					ComponentDepsNode *pose_comp =
-					        id_node->find_component(DEG_NODE_TYPE_EVAL_POSE);
-					BLI_assert(pose_comp != NULL);
-					if (pose_comp->done == COMPONENT_STATE_NONE) {
-						queue.push_front(pose_comp->get_entry_operation());
-						pose_comp->done = COMPONENT_STATE_SCHEDULED;
-					}
-				}
-			}
+/* TODO(sergey): We can reduce number of arguments here. */
+BLI_INLINE void flush_handle_component_node(Depsgraph *graph,
+                                            IDDepsNode *id_node,
+                                            ComponentDepsNode *comp_node,
+                                            bool use_copy_on_write,
+                                            FlushQueue *queue)
+{
+	/* We only handle component once. */
+	if (comp_node->done == COMPONENT_STATE_DONE) {
+		return;
+	}
+	comp_node->done = COMPONENT_STATE_DONE;
+	/* Currently this is needed to get object->mesh to be replaced with
+	 * original mesh (rather than being evaluated_mesh).
+	 *
+	 * TODO(sergey): This is something we need to avoid.
+	 */
+	if (use_copy_on_write && comp_node->depends_on_cow()) {
+		ComponentDepsNode *cow_comp =
+		        id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE);
+		cow_comp->tag_update(graph);
+	}
+	/* Tag all required operations in component for update.  */
+	foreach (OperationDepsNode *op, comp_node->operations) {
+		/* We don't want to flush tags in "upstream" direction for
+		 * certain types of operations.
+		 *
+		 * TODO(sergey): Need a more generic solution for this.
+		 */
+		if (op->opcode == DEG_OPCODE_PARTICLE_SETTINGS_EVAL) {
+			continue;
+		}
+		op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+	}
+	/* When some target changes bone, we might need to re-run the
+	 * whole IK solver, otherwise result might be unpredictable.
+	 */
+	if (comp_node->type == DEG_NODE_TYPE_BONE) {
+		ComponentDepsNode *pose_comp =
+		        id_node->find_component(DEG_NODE_TYPE_EVAL_POSE);
+		BLI_assert(pose_comp != NULL);
+		if (pose_comp->done == COMPONENT_STATE_NONE) {
+			queue->push_front(pose_comp->get_entry_operation());
+			pose_comp->done = COMPONENT_STATE_SCHEDULED;
+		}
+	}
+}
 
-			id_node->done = 1;
-			comp_node->done = COMPONENT_STATE_DONE;
-
-			/* Flush to nodes along links... */
-			/* TODO(sergey): This is mainly giving speedup due ot less queue pushes, which
-			 * reduces number of memory allocations.
-			 *
-			 * We should try solve the allocation issue instead of doing crazy things here.
-			 */
-			if (node->outlinks.size() == 1) {
-				OperationDepsNode *to_node = (OperationDepsNode *)node->outlinks[0]->to;
-				if (to_node->scheduled == false) {
-					to_node->scheduled = true;
-					node = to_node;
-				}
-				else {
-					break;
-				}
+/* Schedule children of the given operation node for traversal.
+ *
+ * One of the children will by-pass the queue and will be returned as a function
+ * return value, so it can start being handled right away, without building too
+ * much of a queue.
+ */
+BLI_INLINE OperationDepsNode *flush_schedule_children(
+        OperationDepsNode *op_node,
+        FlushQueue *queue)
+{
+	OperationDepsNode *result = NULL;
+	foreach (DepsRelation *rel, op_node->outlinks) {
+		OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
+		if (to_node->scheduled == false) {
+			if (result != NULL) {
+				queue->push_front(to_node);
 			}
 			else {
-				foreach (DepsRelation *rel, node->outlinks) {
-					OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
-					if (to_node->scheduled == false) {
-						queue.push_front(to_node);
-						to_node->scheduled = true;
-					}
-				}
-				break;
+				result = to_node;
 			}
+			to_node->scheduled = true;
+		}
+	}
+	return result;
+}
+
+}  // namespace
+
+/* Flush updates from tagged nodes outwards until all affected nodes
+ * are tagged.
+ */
+void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
+{
+	const bool use_copy_on_write = DEG_depsgraph_use_copy_on_write();
+	/* Sanity checks. */
+	BLI_assert(bmain != NULL);
+	BLI_assert(graph != NULL);
+	/* Nothing to update, early out. */
+	if (BLI_gset_size(graph->entry_tags) == 0) {
+		return;
+	}
+	/* Reset all flags, get ready for the flush. */
+	flush_prepare(graph);
+	/* Starting from the tagged "entry" nodes, flush outwards. */
+	FlushQueue queue;
+	flush_schedule_entrypoints(graph, &queue);
+	/* Prepare update context for editors. */
+	DEGEditorUpdateContext update_ctx = {
+		.bmain = bmain,
+		.scene = graph->scene,
+		.view_layer = graph->view_layer,
+	};
+	/* Do actual flush. */
+	while (!queue.empty()) {
+		OperationDepsNode *op_node = queue.front();
+		queue.pop_front();
+		while (op_node != NULL) {
+			/* Tag operation as required for update. */
+			op_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+			/* Inform corresponding ID and component nodes about the change. */
+			ComponentDepsNode *comp_node = op_node->owner;
+			IDDepsNode *id_node = comp_node->owner;
+			flush_handle_id_node(bmain, id_node, &update_ctx);
+			flush_handle_component_node(graph,
+			                            id_node,
+			                            comp_node

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list