[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