Skip to content

Instantly share code, notes, and snippets.

@Frizi
Created October 12, 2019 19:37
Show Gist options
  • Save Frizi/efba8dd45c614b2e4848984a27f0c5dd to your computer and use it in GitHub Desktop.
Save Frizi/efba8dd45c614b2e4848984a27f0c5dd to your computer and use it in GitHub Desktop.
impl<'a, B: Backend, T: ?Sized> Reducer<B, T> for CombineSubpassesReducer {
fn reduce(&mut self, editor: &mut GraphEditor<B, T>, node: NodeIndex) -> Reduction {
let mut candidate_merge = None;
match editor.graph().node_weight(node) {
Some(PlanNodeData::RenderSubpass(_)) => {
let mut read_attachments = walk_attachments(editor.graph().parents(node));
// Do all attachments I read come from the same node? If so, which node?
while let Some((_, access_node)) = read_attachments.walk_next(editor.graph()) {
// take attachment writer
let (_, writer) = walk_origins(editor.graph().parents(access_node))
.walk_next(editor.graph())
.expect("Attachment node must have an orign");
match candidate_merge {
Some(candidate) if candidate != writer => {
// this subpass attachments are written by more than one subpass
log::trace!("CombineSubpassesReducer bailout: found another writer");
return Reduction::NoChange;
}
None => {
match editor.graph().node_weight(writer) {
Some(PlanNodeData::RenderSubpass(_)) => {
candidate_merge = Some(writer)
}
_ => {
log::trace!(
"CombineSubpassesReducer bailout: written by non-subpass"
);
// Written by not a subpass
return Reduction::NoChange;
}
}
}
_ => {}
}
}
}
_ => return Reduction::NoChange,
};
match candidate_merge {
Some(merge_target) => {
// append this pass data to other pass and replace current node with it,
let this_node = std::mem::replace(
editor.graph_mut().node_weight_mut(node).unwrap(),
PlanNodeData::Tombstone,
);
let mut reads = editor.graph().parents(node);
while let Some((read_edge, read_node)) = reads.walk_next(editor.graph()) {
if editor
.graph()
.edge_weight(read_edge)
.unwrap()
.is_attachment()
{
editor.kill(read_node);
} else if let Some(edge_data) = editor.graph_mut().remove_edge(read_edge) {
editor
.graph_mut()
.add_edge(read_node, merge_target, edge_data)
.unwrap();
}
}
let merge_node = editor.graph_mut().node_weight_mut(merge_target).unwrap();
match (this_node, merge_node) {
(
PlanNodeData::RenderSubpass(ref mut this_groups),
PlanNodeData::RenderSubpass(ref mut merge_groups),
) => {
merge_groups.extend(this_groups.drain());
}
_ => unreachable!(),
}
Reduction::Replace(merge_target)
}
_ => Reduction::NoChange,
}
}
}
fn walk_origins<'w, 'a: 'w, B: Backend, T: ?Sized + 'w>(
walker: impl Walker<&'w PlanDag<'a, B, T>, Item = (EdgeIndex, NodeIndex)>,
) -> impl Walker<&'w PlanDag<'a, B, T>, Item = (EdgeIndex, NodeIndex)> {
walker.filter(|graph, &(edge, _)| {
graph.edge_weight(edge).map_or(false, |e| match e {
PlanEdge::Origin => true,
_ => false,
})
})
}
fn walk_attachments<'w, 'a: 'w, B: Backend, T: ?Sized + 'w>(
walker: impl Walker<&'w PlanDag<'a, B, T>, Item = (EdgeIndex, NodeIndex)>,
) -> impl Walker<&'w PlanDag<'a, B, T>, Item = (EdgeIndex, NodeIndex)> {
walker.filter(|graph, &(edge, _)| {
graph.edge_weight(edge).map_or(false, |e| match e {
PlanEdge::ImageAccess(access, _) => access.is_attachment(),
_ => false,
})
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment