[Bf-blender-cvs] [342226a6706] master: Depsgraph: Synchronize flushing with 2.8 branch

Sergey Sharybin noreply at git.blender.org
Mon Dec 18 16:35:28 CET 2017


Commit: 342226a67063ca5563c70ab45fe158af5bbc8317
Author: Sergey Sharybin
Date:   Mon Dec 18 16:33:12 2017 +0100
Branches: master
https://developer.blender.org/rB342226a67063ca5563c70ab45fe158af5bbc8317

Depsgraph: Synchronize flushing with 2.8 branch

Not only this helps merges form master to the branch, but also:

- Allows us to production-check changes as soon as possible.
- Avoids some unnecessary editors update about ID changes.
- Adds small optimization on queue size by always keeping one of the pointers
  outside of the queue.

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

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 79ef0f32dda..219ed981870 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -54,12 +54,19 @@ extern "C" {
 
 namespace DEG {
 
+enum {
+	ID_STATE_NONE     = 0,
+	ID_STATE_MODIFIED = 1,
+};
+
 enum {
 	COMPONENT_STATE_NONE      = 0,
 	COMPONENT_STATE_SCHEDULED = 1,
 	COMPONENT_STATE_DONE      = 2,
 };
 
+typedef std::deque<OperationDepsNode *> FlushQueue;
+
 namespace {
 
 // TODO(sergey): De-duplicate with depsgraph_tag,cc
@@ -75,176 +82,200 @@ void lib_id_recalc_data_tag(Main *bmain, ID *id)
 	DEG_id_type_tag(bmain, GS(id->name));
 }
 
-}  /* namespace */
-
-typedef std::deque<OperationDepsNode *> FlushQueue;
-
-static void flush_init_func(void *data_v, int i)
+void flush_init_operation_node_func(void *data_v, int i)
 {
-	/* ID node's done flag is used to avoid multiple editors update
-	 * for the same ID.
-	 */
 	Depsgraph *graph = (Depsgraph *)data_v;
 	OperationDepsNode *node = graph->operations[i];
-	ComponentDepsNode *comp_node = node->owner;
-	IDDepsNode *id_node = comp_node->owner;
-	id_node->done = 0;
-	comp_node->done = COMPONENT_STATE_NONE;
 	node->scheduled = false;
 }
 
-/* Flush updates from tagged nodes outwards until all affected nodes
- * are tagged.
- */
-void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
+void flush_init_id_node_func(void *data_v, int i)
 {
-	/* Sanity check. */
-	if (graph == NULL) {
-		return;
-	}
-
-	/* Nothing to update, early out. */
-	if (BLI_gset_size(graph->entry_tags) == 0) {
-		return;
-	}
+	Depsgraph *graph = (Depsgraph *)data_v;
+	IDDepsNode *id_node = graph->id_nodes[i];
+	id_node->done = ID_STATE_NONE;
+	GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+		comp_node->done = COMPONENT_STATE_NONE;
+	GHASH_FOREACH_END();
+}
 
-	/* TODO(sergey): With a bit of flag magic we can get rid of this
-	 * extra loop.
-	 */
+BLI_INLINE void flush_prepare(Depsgraph *graph)
+{
 	const int num_operations = graph->operations.size();
-	const bool do_threads = num_operations > 256;
-	BLI_task_parallel_range(0,
-	                        num_operations,
+	BLI_task_parallel_range(0, num_operations,
+	                        graph,
+	                        flush_init_operation_node_func,
+	                        (num_operations > 256));
+	const int num_id_nodes = graph->id_nodes.size();
+	BLI_task_parallel_range(0, num_id_nodes,
 	                        graph,
-	                        flush_init_func,
-	                        do_threads);
+	                        flush_init_id_node_func,
+	                        (num_id_nodes > 256));
+}
 
-	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!
-	 */
-	GSET_FOREACH_BEGIN(OperationDepsNode *, node, graph->entry_tags)
+BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue)
+{
+	GSET_FOREACH_BEGIN(OperationDepsNode *, op_node, graph->entry_tags)
 	{
-		queue.push_back(node);
-		node->scheduled = true;
+		queue->push_back(op_node);
+		op_node->scheduled = true;
 	}
 	GSET_FOREACH_END();
+}
 
-	int num_flushed_objects = 0;
-	while (!queue.empty()) {
-		OperationDepsNode *node = queue.front();
-		queue.pop_front();
-
-		for (;;) {
-			node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+BLI_INLINE void flush_handle_id_node(IDDepsNode *id_node)
+{
+	id_node->done = ID_STATE_MODIFIED;
+}
 
-			ComponentDepsNode *comp_node = node->owner;
-			IDDepsNode *id_node = comp_node->owner;
+/* TODO(sergey): We can reduce number of arguments here. */
+BLI_INLINE void flush_handle_component_node(Depsgraph * /*graph*/,
+                                            IDDepsNode *id_node,
+                                            ComponentDepsNode *comp_node,
+                                            FlushQueue *queue)
+{
+	/* We only handle component once. */
+	if (comp_node->done == COMPONENT_STATE_DONE) {
+		return;
+	}
+	comp_node->done = COMPONENT_STATE_DONE;
+	/* Tag all required operations in component for update.  */
+	foreach (OperationDepsNode *op, comp_node->operations) {
+		op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+	}
+	if (GS(id_node->id->name) == ID_OB) {
+		Object *object = (Object *)id_node->id;
+		/* This code is used to preserve those areas which does
+		 * direct object update,
+		 *
+		 * Plus it ensures visibility changes and relations and
+		 * layers visibility update has proper flags to work with.
+		 */
+		switch (comp_node->type) {
+			case DEG_NODE_TYPE_UNDEFINED:
+			case DEG_NODE_TYPE_OPERATION:
+			case DEG_NODE_TYPE_TIMESOURCE:
+			case DEG_NODE_TYPE_ID_REF:
+			case DEG_NODE_TYPE_SEQUENCER:
+			case NUM_DEG_NODE_TYPES:
+				/* Ignore, does not translate to object component. */
+				BLI_assert(!"This should never happen!");
+				break;
+			case DEG_NODE_TYPE_ANIMATION:
+				object->recalc |= OB_RECALC_TIME;
+				break;
+			case DEG_NODE_TYPE_TRANSFORM:
+				object->recalc |= OB_RECALC_OB;
+				break;
+			case DEG_NODE_TYPE_GEOMETRY:
+			case DEG_NODE_TYPE_EVAL_POSE:
+			case DEG_NODE_TYPE_BONE:
+			case DEG_NODE_TYPE_EVAL_PARTICLES:
+			case DEG_NODE_TYPE_SHADING:
+			case DEG_NODE_TYPE_CACHE:
+			case DEG_NODE_TYPE_PROXY:
+				object->recalc |= OB_RECALC_DATA;
+				break;
+			case DEG_NODE_TYPE_PARAMETERS:
+				break;
+		}
+	}
+	/* 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 *id = id_node->id;
-			if (id_node->done == 0) {
-				deg_editors_id_update(bmain, id);
-				lib_id_recalc_tag(bmain, id);
-				/* TODO(sergey): For until we've got proper data nodes in the graph. */
-				lib_id_recalc_data_tag(bmain, id);
+/* 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);
 			}
-
-			if (comp_node->done != COMPONENT_STATE_DONE) {
-				Object *object = NULL;
-				if (GS(id->name) == ID_OB) {
-					object = (Object *)id;
-					if (id_node->done == 0) {
-						++num_flushed_objects;
-					}
-				}
-				foreach (OperationDepsNode *op, comp_node->operations) {
-					op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
-				}
-				if (object != NULL) {
-					/* This code is used to preserve those areas which does
-					 * direct object update,
-					 *
-					 * Plus it ensures visibility changes and relations and
-					 * layers visibility update has proper flags to work with.
-					 */
-					switch (comp_node->type) {
-						case DEG_NODE_TYPE_UNDEFINED:
-						case DEG_NODE_TYPE_OPERATION:
-						case DEG_NODE_TYPE_TIMESOURCE:
-						case DEG_NODE_TYPE_ID_REF:
-						case DEG_NODE_TYPE_SEQUENCER:
-						case NUM_DEG_NODE_TYPES:
-							/* Ignore, does not translate to object component. */
-							BLI_assert(!"This should never happen!");
-							break;
-						case DEG_NODE_TYPE_ANIMATION:
-							object->recalc |= OB_RECALC_TIME;
-							break;
-						case DEG_NODE_TYPE_TRANSFORM:
-							object->recalc |= OB_RECALC_OB;
-							break;
-						case DEG_NODE_TYPE_GEOMETRY:
-						case DEG_NODE_TYPE_EVAL_POSE:
-						case DEG_NODE_TYPE_BONE:
-						case DEG_NODE_TYPE_EVAL_PARTICLES:
-						case DEG_NODE_TYPE_SHADING:
-						case DEG_NODE_TYPE_CACHE:
-						case DEG_NODE_TYPE_PROXY:
-							object->recalc |= OB_RECALC_DATA;
-							break;
-						case DEG_NODE_TYPE_PARAMETERS:
-							break;
-					}
-				}
-				/* 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;
-					}
-				}
+			else {
+				result = to_node;
 			}
+			to_node->scheduled = true;
+		}
+	}
+	return result;
+}
 
-			id_node->done = 1;
-			comp_node->done = COMPONENT_STATE_DONE;
+BLI_INLINE void flush_editors_id_update(Main *bmain,
+                                        Depsgraph *graph)
+{
+	foreach (IDDepsNode *id_node, graph->id_nodes) {
+		if (id_node->done != ID_STATE_MODIFIED) {
+			continue;
+		}
+		/* TODO(sergey): Do we need to pass original or evaluated ID here? */
+		ID *id = id_node->id;
+		deg_editors_id_update(bmain, id);
+		lib_id_recalc_tag(bmain, id);
+		/* TODO(sergey): For until we've got proper data nodes in the graph. */
+		lib_id_recalc_data_tag(bmain, id);
+	}
+}
 
-			/* 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;
-				}
-	

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list