diff --git a/crates/renderer/src/render_graph.rs b/crates/renderer/src/render_graph.rs index 1584227..8bf17fd 100644 --- a/crates/renderer/src/render_graph.rs +++ b/crates/renderer/src/render_graph.rs @@ -86,11 +86,11 @@ impl core::ops::BitOr for Access { type Output = Self; fn bitor(self, rhs: Self) -> Self::Output { - assert_eq!(self.layout, rhs.layout); + //assert_eq!(self.layout, rhs.layout); Self { stage: self.stage | rhs.stage, mask: self.mask | rhs.mask, - layout: self.layout, + layout: self.layout.max(rhs.layout), } } } @@ -161,6 +161,13 @@ impl Access { mask: self.mask, } } + pub fn empty() -> Self { + Self { + stage: vk::PipelineStageFlags2::NONE, + mask: vk::AccessFlags2::empty(), + layout: None, + } + } pub fn undefined() -> Self { Self { stage: vk::PipelineStageFlags2::NONE, @@ -393,13 +400,30 @@ impl RenderGraph { } impl PassNode { - fn into_u32(&self) -> u32 { + fn into_node_idx(&self) -> u32 { match self { PassNode::First => 0, PassNode::Last => 1, PassNode::Pass(i) => 2 + *i as u32, } } + fn into_u32(&self, max_i: u32) -> u32 { + match self { + PassNode::First => 0, + PassNode::Last => max_i + 1, + PassNode::Pass(i) => 1 + *i as u32, + } + } + fn range_full(from: Self, to: Self, max_i: u32) -> std::ops::RangeInclusive { + from.into_u32(max_i)..=to.into_u32(max_i) + } + fn from_u32(v: u32, max_i: u32) -> Self { + match v { + 0 => Self::First, + n if n == 1 + max_i => Self::Last, + n => Self::Pass(n as usize - 1), + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -436,6 +460,20 @@ impl RenderGraph { access: RefAccess::Write(Access::undefined()), }); } + for rid in self.resources.keys() { + references.insert(GraphRef { + pass: PassNode::First, + resource: *rid, + access: RefAccess::Write( + self.accesses + .get(rid) + .cloned() + .unwrap_or(Access::undefined()), + ), + }); + + intervals.insert(*rid, (PassNode::First, PassNode::First)); + } for (i, pass) in self.pass_descs.iter().enumerate() { let mut reads = BTreeMap::new(); @@ -476,6 +514,7 @@ impl RenderGraph { }) .or_insert((PassNode::Pass(i), PassNode::Pass(i))); } + references.extend(writes.into_iter().map(|(resource, access)| GraphRef { pass: PassNode::Pass(i), resource, @@ -500,6 +539,9 @@ impl RenderGraph { .or_insert((PassNode::Last, PassNode::Last)); } + eprintln!("references: {references:#?}"); + eprintln!("intervals: {intervals:#?}"); + (references, intervals) }; @@ -570,35 +612,62 @@ impl RenderGraph { let mut to_make_available = AccessMask::undefined(); // writes already made-visible let mut made_visible = AccessMask::undefined(); - let mut last_read = PreviousRef::Write(PassNode::First, Access::undefined()); - let mut last_write = PreviousRef::Write(PassNode::First, Access::undefined()); - let mut last_ref = PreviousRef::Write(PassNode::First, Access::undefined()); + let mut last_read = Option::::None; + let mut last_write = Option::::None; + let mut last_ref = Option::::None; - references - .range( + // pass, read, write + let mut current_pass = (from, Access::empty(), Access::empty()); + let max_i = self.pass_descs.len() as u32; + eprintln!("{rid:?}:"); + for pass in + PassNode::range_full(from, to, max_i).map(|i| PassNode::from_u32(i, max_i)) + { + eprintln!("{pass:?}:"); + let mut range = references.range( GraphRef { - pass: from, + pass, resource: rid, access: RefAccess::__Min, }..GraphRef { - pass: to, + pass, resource: rid, access: RefAccess::__Max, }, - ) - .for_each(|a| { + ); + + while let Some(a) = range.next() { + eprintln!("{a:?}"); + eprintln!("made_visible: {made_visible:?}"); + eprintln!("to_make_available: {to_make_available:?}"); + if a.pass != current_pass.0 { + if current_pass.1 != Access::empty() { + last_read = Some(PreviousRef::Read(current_pass.0, current_pass.1)); + last_ref = Some(PreviousRef::Read(current_pass.0, current_pass.1)); + } + if current_pass.2 != Access::empty() { + last_write = + Some(PreviousRef::Write(current_pass.0, current_pass.2)); + last_ref = Some(PreviousRef::Write(current_pass.0, current_pass.2)); + } + + current_pass = (a.pass, Access::empty(), Access::empty()); + } + // TODO: VkEvents can make this more // fine-grained but also probably have zero // real-world benefit :< - last_ref = match a.access { + match a.access { RefAccess::None => { // make-available previous writes // no-op edge between previous reference and a.pass - edges.push(((last_ref.node(), a.pass), (rid, Barrier::Logical))); + if let Some(last_ref) = last_ref.as_ref() { + edges + .push(((last_ref.node(), a.pass), (rid, Barrier::Logical))); + } // because this is the last node, setting last_ref isn't required. - PreviousRef::Read(a.pass, Access::undefined()) } RefAccess::Read(access) => { // - if read: no writes pending, check for @@ -610,34 +679,37 @@ impl RenderGraph { made_visible = made_visible | make_visible_mask; match last_ref { - PreviousRef::Read(pass_node, before) => { - if !make_visible_mask.is_empty() { - // make-visible reads. - edges.push(( - (last_write.node(), a.pass), - ( - rid, - Barrier::MakeVisible { - src: last_write.access().stage, - dst: ( - make_visible_mask.stage, - make_visible_mask.mask, - ), - }, - ), - )); - } else { - // still require a after b - edges.push(( - (last_write.node(), a.pass), - ( - rid, - Barrier::Execution { - src: last_write.access().stage, - dst: access.stage, - }, - ), - )); + None => {} + Some(PreviousRef::Read(pass_node, before)) => { + if let Some(last_write) = last_write.as_ref() { + if !make_visible_mask.is_empty() { + // make-visible reads. + edges.push(( + (last_write.node(), a.pass), + ( + rid, + Barrier::MakeVisible { + src: last_write.access().stage, + dst: ( + make_visible_mask.stage, + make_visible_mask.mask, + ), + }, + ), + )); + } else { + // still require a after b + edges.push(( + (last_write.node(), a.pass), + ( + rid, + Barrier::Execution { + src: last_write.access().stage, + dst: access.stage, + }, + ), + )); + } } if before.layout != access.layout { @@ -653,15 +725,15 @@ impl RenderGraph { )); } } - PreviousRef::Write(..) => { + Some(PreviousRef::Write(write, before)) => { // make writes visible - if make_visible_mask.is_empty() { + if !make_visible_mask.is_empty() { edges.push(( - (last_write.node(), a.pass), + (write, a.pass), ( rid, Barrier::MakeVisible { - src: last_write.access().stage, + src: before.stage, dst: ( make_visible_mask.stage, make_visible_mask.mask, @@ -672,8 +744,14 @@ impl RenderGraph { } // make all writes available if !to_make_available.is_empty() { + tracing::debug!( + "making available {:?} for {:?} on {:?}", + to_make_available, + rid, + a.pass + ); edges.push(( - (last_write.node(), a.pass), + (write, a.pass), ( rid, Barrier::MakeAvailable { @@ -694,11 +772,11 @@ impl RenderGraph { { // still require a after b edges.push(( - (last_write.node(), a.pass), + (write, a.pass), ( rid, Barrier::Execution { - src: last_write.access().stage, + src: before.stage, dst: access.stage, }, ), @@ -706,8 +784,7 @@ impl RenderGraph { } } } - last_read = PreviousRef::Read(a.pass, access); - last_write + current_pass.1 = current_pass.1 | access; } RefAccess::Write(access) => { // - if read: execution barrier against write-after-read @@ -715,7 +792,8 @@ impl RenderGraph { to_make_available = to_make_available | access.into_access_mask(); match last_ref { - PreviousRef::Read(pass_node, before) => { + None => {} + Some(PreviousRef::Read(pass_node, before)) => { // execution barrier to ward against write-after-read edges.push(( (pass_node, a.pass), @@ -728,7 +806,7 @@ impl RenderGraph { ), )); } - PreviousRef::Write(pass_node, before) => { + Some(PreviousRef::Write(pass_node, before)) => { if before.layout != access.layout { // as far as I understand the spec, // this already makes-available @@ -742,9 +820,10 @@ impl RenderGraph { }, ), )); - } else { - // write_no_sync: pass tells us that - // writes do not interleave. + } + // write_no_sync: pass tells us that + // writes do not interleave. + if let Some(last_read) = last_read.as_ref() { edges.push(( (last_read.node(), a.pass), (rid, Barrier::Logical), @@ -752,12 +831,13 @@ impl RenderGraph { } } } - last_write = PreviousRef::Write(a.pass, access); - last_write + + current_pass.2 = current_pass.2 | access; } _ => unreachable!(), }; - }); + } + } }); let mut dag = petgraph::graph::DiGraph::new(); @@ -768,7 +848,11 @@ impl RenderGraph { dag.add_node(PassNode::Last); for ((from, to), weight) in edges { - dag.add_edge(from.into_u32().into(), to.into_u32().into(), weight); + dag.add_edge( + from.into_node_idx().into(), + to.into_node_idx().into(), + weight, + ); } #[cfg(any(debug_assertions, test))] @@ -781,7 +865,7 @@ impl RenderGraph { &[], &|_graph, edgeref| { format!( - "label = \"{},{}\"", + "label = \"{},{:#?}\"", edgeref.weight().0.as_u32(), edgeref.weight().1, )