Skip to content

Commit

Permalink
Split ScheduleGraph::process_configs function (adopted) (#12435)
Browse files Browse the repository at this point in the history
Adoption of #10617, resolved conflicts with main

---------

Co-authored-by: Stepan Koltsov <stepan.koltsov@gmail.com>
  • Loading branch information
yyogo and stepancheg authored Mar 17, 2024
1 parent 1323de7 commit e9dc270
Showing 1 changed file with 89 additions and 135 deletions.
224 changes: 89 additions & 135 deletions crates/bevy_ecs/src/schedule/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,42 @@ impl ScheduleGraph {
&self.conflicting_systems
}

fn process_config<T: ProcessNodeConfig>(
&mut self,
config: NodeConfig<T>,
collect_nodes: bool,
) -> ProcessConfigsResult {
ProcessConfigsResult {
densely_chained: true,
nodes: collect_nodes
.then_some(T::process_config(self, config))
.into_iter()
.collect(),
}
}

fn apply_collective_conditions<T: ProcessNodeConfig>(
&mut self,
configs: &mut [NodeConfigs<T>],
collective_conditions: Vec<BoxedCondition>,
) {
if !collective_conditions.is_empty() {
if let [config] = configs {
for condition in collective_conditions {
config.run_if_dyn(condition);
}
} else {
let set = self.create_anonymous_set();
for config in configs.iter_mut() {
config.in_set_inner(set.intern());
}
let mut set_config = SystemSetConfig::new(set.intern());
set_config.conditions.extend(collective_conditions);
self.configure_set_inner(set_config).unwrap();
}
}
}

/// Adds the config nodes to the graph.
///
/// `collect_nodes` controls whether the `NodeId`s of the processed config nodes are stored in the returned [`ProcessConfigsResult`].
Expand All @@ -676,157 +712,75 @@ impl ScheduleGraph {
collect_nodes: bool,
) -> ProcessConfigsResult {
match configs {
NodeConfigs::NodeConfig(config) => {
let node_id = T::process_config(self, config);
if collect_nodes {
ProcessConfigsResult {
densely_chained: true,
nodes: vec![node_id],
}
} else {
ProcessConfigsResult {
densely_chained: true,
nodes: Vec::new(),
}
}
}
NodeConfigs::NodeConfig(config) => self.process_config(config, collect_nodes),
NodeConfigs::Configs {
mut configs,
collective_conditions,
chained,
} => {
let more_than_one_entry = configs.len() > 1;
if !collective_conditions.is_empty() {
if more_than_one_entry {
let set = self.create_anonymous_set();
for config in &mut configs {
config.in_set_inner(set.intern());
}
let mut set_config = SystemSetConfig::new(set.intern());
set_config.conditions.extend(collective_conditions);
self.configure_set_inner(set_config).unwrap();
} else {
for condition in collective_conditions {
configs[0].run_if_dyn(condition);
}
}
}
let mut config_iter = configs.into_iter();
let mut nodes_in_scope = Vec::new();
let mut densely_chained = true;
if chained == Chain::Yes || chained == Chain::YesIgnoreDeferred {
let Some(prev) = config_iter.next() else {
return ProcessConfigsResult {
nodes: Vec::new(),
densely_chained: true,
};
self.apply_collective_conditions(&mut configs, collective_conditions);

let ignore_deferred = matches!(chained, Chain::YesIgnoreDeferred);
let chained = matches!(chained, Chain::Yes | Chain::YesIgnoreDeferred);

// Densely chained if
// * chained and all configs in the chain are densely chained, or
// * unchained with a single densely chained config
let mut densely_chained = chained || configs.len() == 1;
let mut configs = configs.into_iter();
let mut nodes = Vec::new();

let Some(first) = configs.next() else {
return ProcessConfigsResult {
nodes: Vec::new(),
densely_chained,
};
let mut previous_result = self.process_configs(prev, true);
densely_chained = previous_result.densely_chained;
for current in config_iter {
let current_result = self.process_configs(current, true);
densely_chained = densely_chained && current_result.densely_chained;
match (
previous_result.densely_chained,
current_result.densely_chained,
) {
// Both groups are "densely" chained, so we can simplify the graph by only
// chaining the last in the previous list to the first in the current list
(true, true) => {
let last_in_prev = previous_result.nodes.last().unwrap();
let first_in_current = current_result.nodes.first().unwrap();
self.dependency.graph.add_edge(
*last_in_prev,
*first_in_current,
(),
);

if chained == Chain::YesIgnoreDeferred {
self.no_sync_edges
.insert((*last_in_prev, *first_in_current));
}
}
// The previous group is "densely" chained, so we can simplify the graph by only
// chaining the last item from the previous list to every item in the current list
(true, false) => {
let last_in_prev = previous_result.nodes.last().unwrap();
for current_node in &current_result.nodes {
self.dependency.graph.add_edge(
*last_in_prev,
*current_node,
(),
);

if chained == Chain::YesIgnoreDeferred {
self.no_sync_edges.insert((*last_in_prev, *current_node));
}
}
}
// The current list is currently "densely" chained, so we can simplify the graph by
// only chaining every item in the previous list to the first item in the current list
(false, true) => {
let first_in_current = current_result.nodes.first().unwrap();
for previous_node in &previous_result.nodes {
self.dependency.graph.add_edge(
*previous_node,
*first_in_current,
(),
);

if chained == Chain::YesIgnoreDeferred {
self.no_sync_edges
.insert((*previous_node, *first_in_current));
}
}
}
// Neither of the lists are "densely" chained, so we must chain every item in the first
// list to every item in the second list
(false, false) => {
for previous_node in &previous_result.nodes {
for current_node in &current_result.nodes {
self.dependency.graph.add_edge(
*previous_node,
*current_node,
(),
);

if chained == Chain::YesIgnoreDeferred {
self.no_sync_edges
.insert((*previous_node, *current_node));
}
}
};
let mut previous_result = self.process_configs(first, collect_nodes || chained);
densely_chained &= previous_result.densely_chained;

for current in configs {
let current_result = self.process_configs(current, collect_nodes || chained);
densely_chained &= current_result.densely_chained;

if chained {
// if the current result is densely chained, we only need to chain the first node
let current_nodes = if current_result.densely_chained {
&current_result.nodes[..1]
} else {
&current_result.nodes
};
// if the previous result was densely chained, we only need to chain the last node
let previous_nodes = if previous_result.densely_chained {
&previous_result.nodes[previous_result.nodes.len() - 1..]
} else {
&previous_result.nodes
};

for previous_node in previous_nodes {
for current_node in current_nodes {
self.dependency
.graph
.add_edge(*previous_node, *current_node, ());

if ignore_deferred {
self.no_sync_edges.insert((*previous_node, *current_node));
}
}
}

if collect_nodes {
nodes_in_scope.append(&mut previous_result.nodes);
}

previous_result = current_result;
}

// ensure the last config's nodes are added
if collect_nodes {
nodes_in_scope.append(&mut previous_result.nodes);
}
} else {
for config in config_iter {
let result = self.process_configs(config, collect_nodes);
densely_chained = densely_chained && result.densely_chained;
if collect_nodes {
nodes_in_scope.extend(result.nodes);
}
nodes.append(&mut previous_result.nodes);
}

// an "unchained" SystemConfig is only densely chained if it has exactly one densely chained entry
if more_than_one_entry {
densely_chained = false;
}
previous_result = current_result;
}
if collect_nodes {
nodes.append(&mut previous_result.nodes);
}

ProcessConfigsResult {
nodes: nodes_in_scope,
nodes,
densely_chained,
}
}
Expand Down

0 comments on commit e9dc270

Please sign in to comment.