quick save #2
This commit is contained in:
parent
146ffa654f
commit
131887b633
|
@ -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,34 +679,37 @@ 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 => {}
|
||||||
if !make_visible_mask.is_empty() {
|
Some(PreviousRef::Read(pass_node, before)) => {
|
||||||
// make-visible reads.
|
if let Some(last_write) = last_write.as_ref() {
|
||||||
edges.push((
|
if !make_visible_mask.is_empty() {
|
||||||
(last_write.node(), a.pass),
|
// make-visible reads.
|
||||||
(
|
edges.push((
|
||||||
rid,
|
(last_write.node(), a.pass),
|
||||||
Barrier::MakeVisible {
|
(
|
||||||
src: last_write.access().stage,
|
rid,
|
||||||
dst: (
|
Barrier::MakeVisible {
|
||||||
make_visible_mask.stage,
|
src: last_write.access().stage,
|
||||||
make_visible_mask.mask,
|
dst: (
|
||||||
),
|
make_visible_mask.stage,
|
||||||
},
|
make_visible_mask.mask,
|
||||||
),
|
),
|
||||||
));
|
},
|
||||||
} else {
|
),
|
||||||
// still require a after b
|
));
|
||||||
edges.push((
|
} else {
|
||||||
(last_write.node(), a.pass),
|
// still require a after b
|
||||||
(
|
edges.push((
|
||||||
rid,
|
(last_write.node(), a.pass),
|
||||||
Barrier::Execution {
|
(
|
||||||
src: last_write.access().stage,
|
rid,
|
||||||
dst: access.stage,
|
Barrier::Execution {
|
||||||
},
|
src: last_write.access().stage,
|
||||||
),
|
dst: access.stage,
|
||||||
));
|
},
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if before.layout != access.layout {
|
if before.layout != access.layout {
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue