quick save #2

This commit is contained in:
Janis 2025-01-06 04:01:15 +01:00
parent 146ffa654f
commit 131887b633

View file

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