From 131887b633bbee7717732b7175ec3d44194e3869 Mon Sep 17 00:00:00 2001
From: Janis <janis@nirgendwo.xyz>
Date: Mon, 6 Jan 2025 04:01:15 +0100
Subject: [PATCH] quick save #2

---
 crates/renderer/src/render_graph.rs | 208 +++++++++++++++++++---------
 1 file changed, 146 insertions(+), 62 deletions(-)

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<u32> {
+                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::<PreviousRef>::None;
+                let mut last_write = Option::<PreviousRef>::None;
+                let mut last_ref = Option::<PreviousRef>::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,
                             )