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/builder/deg_builder_cycle.cc')
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc281
1 files changed, 139 insertions, 142 deletions
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index a6d86f5178f..af5c4e7130b 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -41,89 +41,88 @@ namespace DEG {
namespace {
enum eCyclicCheckVisitedState {
- /* Not is not visited at all during traversal. */
- NODE_NOT_VISITED = 0,
- /* Node has been visited during traversal and not in current stack. */
- NODE_VISITED = 1,
- /* Node has been visited during traversal and is in current stack. */
- NODE_IN_STACK = 2,
+ /* Not is not visited at all during traversal. */
+ NODE_NOT_VISITED = 0,
+ /* Node has been visited during traversal and not in current stack. */
+ NODE_VISITED = 1,
+ /* Node has been visited during traversal and is in current stack. */
+ NODE_IN_STACK = 2,
};
struct StackEntry {
- OperationNode *node;
- StackEntry *from;
- Relation *via_relation;
+ OperationNode *node;
+ StackEntry *from;
+ Relation *via_relation;
};
struct CyclesSolverState {
- CyclesSolverState(Depsgraph *graph)
- : graph(graph),
- traversal_stack(BLI_stack_new(sizeof(StackEntry),
- "DEG detect cycles stack")),
- num_cycles(0)
- {
- /* pass */
- }
- ~CyclesSolverState() {
- BLI_stack_free(traversal_stack);
- if (num_cycles != 0) {
- printf("Detected %d dependency cycles\n", num_cycles);
- }
- }
- Depsgraph *graph;
- BLI_Stack *traversal_stack;
- int num_cycles;
+ CyclesSolverState(Depsgraph *graph)
+ : graph(graph),
+ traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack")),
+ num_cycles(0)
+ {
+ /* pass */
+ }
+ ~CyclesSolverState()
+ {
+ BLI_stack_free(traversal_stack);
+ if (num_cycles != 0) {
+ printf("Detected %d dependency cycles\n", num_cycles);
+ }
+ }
+ Depsgraph *graph;
+ BLI_Stack *traversal_stack;
+ int num_cycles;
};
-BLI_INLINE void set_node_visited_state(Node *node,
- eCyclicCheckVisitedState state)
+BLI_INLINE void set_node_visited_state(Node *node, eCyclicCheckVisitedState state)
{
- node->custom_flags = (node->custom_flags & ~0x3) | (int)state;
+ node->custom_flags = (node->custom_flags & ~0x3) | (int)state;
}
BLI_INLINE eCyclicCheckVisitedState get_node_visited_state(Node *node)
{
- return (eCyclicCheckVisitedState)(node->custom_flags & 0x3);
+ return (eCyclicCheckVisitedState)(node->custom_flags & 0x3);
}
BLI_INLINE void set_node_num_visited_children(Node *node, int num_children)
{
- node->custom_flags = (node->custom_flags & 0x3) | (num_children << 2);
+ node->custom_flags = (node->custom_flags & 0x3) | (num_children << 2);
}
BLI_INLINE int get_node_num_visited_children(Node *node)
{
- return node->custom_flags >> 2;
+ return node->custom_flags >> 2;
}
void schedule_node_to_stack(CyclesSolverState *state, OperationNode *node)
{
- StackEntry entry;
- entry.node = node;
- entry.from = NULL;
- entry.via_relation = NULL;
- BLI_stack_push(state->traversal_stack, &entry);
- set_node_visited_state(node, NODE_IN_STACK);
+ StackEntry entry;
+ entry.node = node;
+ entry.from = NULL;
+ entry.via_relation = NULL;
+ BLI_stack_push(state->traversal_stack, &entry);
+ set_node_visited_state(node, NODE_IN_STACK);
}
/* Schedule leaf nodes (node without input links) for traversal. */
void schedule_leaf_nodes(CyclesSolverState *state)
{
- for (OperationNode *node : state->graph->operations) {
- bool has_inlinks = false;
- for (Relation *rel : node->inlinks) {
- if (rel->from->type == NodeType::OPERATION) {
- has_inlinks = true;
- }
- }
- node->custom_flags = 0;
- if (has_inlinks == false) {
- schedule_node_to_stack(state, node);
- }
- else {
- set_node_visited_state(node, NODE_NOT_VISITED);
- }
- }
+ for (OperationNode *node : state->graph->operations) {
+ bool has_inlinks = false;
+ for (Relation *rel : node->inlinks) {
+ if (rel->from->type == NodeType::OPERATION) {
+ has_inlinks = true;
+ }
+ }
+ node->custom_flags = 0;
+ if (has_inlinks == false) {
+ schedule_node_to_stack(state, node);
+ }
+ else {
+ set_node_visited_state(node, NODE_NOT_VISITED);
+ }
+ }
}
/* Schedule node which was not checked yet for being belong to
@@ -131,113 +130,111 @@ void schedule_leaf_nodes(CyclesSolverState *state)
*/
bool schedule_non_checked_node(CyclesSolverState *state)
{
- for (OperationNode *node : state->graph->operations) {
- if (get_node_visited_state(node) == NODE_NOT_VISITED) {
- schedule_node_to_stack(state, node);
- return true;
- }
- }
- return false;
+ for (OperationNode *node : state->graph->operations) {
+ if (get_node_visited_state(node) == NODE_NOT_VISITED) {
+ schedule_node_to_stack(state, node);
+ return true;
+ }
+ }
+ return false;
}
bool check_relation_can_murder(Relation *relation)
{
- if (relation->flag & RELATION_FLAG_GODMODE) {
- return false;
- }
- return true;
+ if (relation->flag & RELATION_FLAG_GODMODE) {
+ return false;
+ }
+ return true;
}
-Relation *select_relation_to_murder(Relation *relation,
- StackEntry *cycle_start_entry)
+Relation *select_relation_to_murder(Relation *relation, StackEntry *cycle_start_entry)
{
- /* More or less russian roulette solver, which will make sure only
- * specially marked relations are kept alive.
- *
- * TODO(sergey): There might be better strategies here. */
- if (check_relation_can_murder(relation)) {
- return relation;
- }
- StackEntry *current = cycle_start_entry;
- OperationNode *to_node = (OperationNode *)relation->to;
- while (current->node != to_node) {
- if (check_relation_can_murder(current->via_relation)) {
- return current->via_relation;
- }
- current = current->from;
- }
- return relation;
+ /* More or less russian roulette solver, which will make sure only
+ * specially marked relations are kept alive.
+ *
+ * TODO(sergey): There might be better strategies here. */
+ if (check_relation_can_murder(relation)) {
+ return relation;
+ }
+ StackEntry *current = cycle_start_entry;
+ OperationNode *to_node = (OperationNode *)relation->to;
+ while (current->node != to_node) {
+ if (check_relation_can_murder(current->via_relation)) {
+ return current->via_relation;
+ }
+ current = current->from;
+ }
+ return relation;
}
/* Solve cycles with all nodes which are scheduled for traversal. */
void solve_cycles(CyclesSolverState *state)
{
- BLI_Stack *traversal_stack = state->traversal_stack;
- while (!BLI_stack_is_empty(traversal_stack)) {
- StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack);
- OperationNode *node = entry->node;
- bool all_child_traversed = true;
- const int num_visited = get_node_num_visited_children(node);
- for (int i = num_visited; i < node->outlinks.size(); ++i) {
- Relation *rel = node->outlinks[i];
- if (rel->to->type == NodeType::OPERATION) {
- OperationNode *to = (OperationNode *)rel->to;
- eCyclicCheckVisitedState to_state = get_node_visited_state(to);
- if (to_state == NODE_IN_STACK) {
- printf("Dependency cycle detected:\n");
- printf(" '%s' depends on '%s' through '%s'\n",
- to->full_identifier().c_str(),
- node->full_identifier().c_str(),
- rel->name);
- StackEntry *current = entry;
- while (current->node != to) {
- BLI_assert(current != NULL);
- printf(" '%s' depends on '%s' through '%s'\n",
- current->node->full_identifier().c_str(),
- current->from->node->full_identifier().c_str(),
- current->via_relation->name);
- current = current->from;
- }
- Relation *sacrificial_relation =
- select_relation_to_murder(rel, entry);
- sacrificial_relation->flag |= RELATION_FLAG_CYCLIC;
- ++state->num_cycles;
- }
- else if (to_state == NODE_NOT_VISITED) {
- StackEntry new_entry;
- new_entry.node = to;
- new_entry.from = entry;
- new_entry.via_relation = rel;
- BLI_stack_push(traversal_stack, &new_entry);
- set_node_visited_state(node, NODE_IN_STACK);
- all_child_traversed = false;
- set_node_num_visited_children(node, i);
- break;
- }
- }
- }
- if (all_child_traversed) {
- set_node_visited_state(node, NODE_VISITED);
- BLI_stack_discard(traversal_stack);
- }
- }
+ BLI_Stack *traversal_stack = state->traversal_stack;
+ while (!BLI_stack_is_empty(traversal_stack)) {
+ StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack);
+ OperationNode *node = entry->node;
+ bool all_child_traversed = true;
+ const int num_visited = get_node_num_visited_children(node);
+ for (int i = num_visited; i < node->outlinks.size(); ++i) {
+ Relation *rel = node->outlinks[i];
+ if (rel->to->type == NodeType::OPERATION) {
+ OperationNode *to = (OperationNode *)rel->to;
+ eCyclicCheckVisitedState to_state = get_node_visited_state(to);
+ if (to_state == NODE_IN_STACK) {
+ printf("Dependency cycle detected:\n");
+ printf(" '%s' depends on '%s' through '%s'\n",
+ to->full_identifier().c_str(),
+ node->full_identifier().c_str(),
+ rel->name);
+ StackEntry *current = entry;
+ while (current->node != to) {
+ BLI_assert(current != NULL);
+ printf(" '%s' depends on '%s' through '%s'\n",
+ current->node->full_identifier().c_str(),
+ current->from->node->full_identifier().c_str(),
+ current->via_relation->name);
+ current = current->from;
+ }
+ Relation *sacrificial_relation = select_relation_to_murder(rel, entry);
+ sacrificial_relation->flag |= RELATION_FLAG_CYCLIC;
+ ++state->num_cycles;
+ }
+ else if (to_state == NODE_NOT_VISITED) {
+ StackEntry new_entry;
+ new_entry.node = to;
+ new_entry.from = entry;
+ new_entry.via_relation = rel;
+ BLI_stack_push(traversal_stack, &new_entry);
+ set_node_visited_state(node, NODE_IN_STACK);
+ all_child_traversed = false;
+ set_node_num_visited_children(node, i);
+ break;
+ }
+ }
+ }
+ if (all_child_traversed) {
+ set_node_visited_state(node, NODE_VISITED);
+ BLI_stack_discard(traversal_stack);
+ }
+ }
}
} // namespace
void deg_graph_detect_cycles(Depsgraph *graph)
{
- CyclesSolverState state(graph);
- /* First we solve cycles which are reachable from leaf nodes. */
- schedule_leaf_nodes(&state);
- solve_cycles(&state);
- /* We are not done yet. It is possible to have closed loop cycle,
- * for example A -> B -> C -> A. These nodes were not scheduled
- * yet (since they all have inlinks), and were not traversed since
- * nobody else points to them. */
- while (schedule_non_checked_node(&state)) {
- solve_cycles(&state);
- }
+ CyclesSolverState state(graph);
+ /* First we solve cycles which are reachable from leaf nodes. */
+ schedule_leaf_nodes(&state);
+ solve_cycles(&state);
+ /* We are not done yet. It is possible to have closed loop cycle,
+ * for example A -> B -> C -> A. These nodes were not scheduled
+ * yet (since they all have inlinks), and were not traversed since
+ * nobody else points to them. */
+ while (schedule_non_checked_node(&state)) {
+ solve_cycles(&state);
+ }
}
} // namespace DEG