side effects need stage and access

This commit is contained in:
janis 2026-04-13 23:39:26 +02:00
parent 8ccdfad42a
commit 28c4f52a2b
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
3 changed files with 188 additions and 199 deletions

View file

@ -14,12 +14,33 @@
use crate::{ use crate::{
device::DeviceOwned, device::DeviceOwned,
pipeline::Pipeline,
render_graph::recorder::{CommandRecorder, SideEffectMap}, render_graph::recorder::{CommandRecorder, SideEffectMap},
}; };
use super::resources::*; use super::resources::*;
pub struct ImportResource<T: Resource> {
pub resource: T,
pub access: vk::AccessFlags2,
pub stage: vk::PipelineStageFlags2,
pub layout: Option<vk::ImageLayout>,
}
impl<T: Resource> Command for ImportResource<T> {
fn side_effects(&self, mut map: SideEffectMap) {
self.resource
.side_effect(map.reborrow().into_side_effect_map2(
self.stage,
self.access,
self.layout,
));
}
fn apply(self, _recorder: &mut CommandRecorder) {
// No actual GPU commands needed for import, as it's just a logical operation
}
}
// pub struct CopyBuffers { // pub struct CopyBuffers {
// pub src: Read<BufferSlice>, // pub src: Read<BufferSlice>,
// pub dst: Write<BufferSlice>, // pub dst: Write<BufferSlice>,
@ -46,16 +67,16 @@ pub struct Copy<T: Resource, U: Resource> {
} }
impl<T: Resource, U: Resource> Copy<T, U> { impl<T: Resource, U: Resource> Copy<T, U> {
fn side_effects_inner(&self, mut map: SideEffectMap) { fn side_effects_inner(&self, mut map: SideEffectMap) {
self.src.side_effect( self.src.side_effect(map.reborrow().into_side_effect_map2(
map.reborrow(), vk::PipelineStageFlags2::TRANSFER,
vk::AccessFlags2::TRANSFER_READ, vk::AccessFlags2::TRANSFER_READ,
Some(vk::ImageLayout::TRANSFER_SRC_OPTIMAL), Some(vk::ImageLayout::TRANSFER_SRC_OPTIMAL),
); ));
self.dst.side_effect( self.src.side_effect(map.reborrow().into_side_effect_map2(
map.reborrow(), vk::PipelineStageFlags2::TRANSFER,
vk::AccessFlags2::TRANSFER_WRITE, vk::AccessFlags2::TRANSFER_WRITE,
Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL), Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
); ));
} }
} }
@ -249,11 +270,11 @@ pub struct ClearTexture {
impl Command for ClearTexture { impl Command for ClearTexture {
fn side_effects(&self, mut map: SideEffectMap) { fn side_effects(&self, mut map: SideEffectMap) {
self.dst.side_effect( self.dst.side_effect(map.reborrow().into_side_effect_map2(
map.reborrow(), vk::PipelineStageFlags2::TRANSFER,
vk::AccessFlags2::TRANSFER_WRITE, vk::AccessFlags2::TRANSFER_WRITE,
Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL), Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
); ));
} }
fn apply(self, _recorder: &mut CommandRecorder) {} fn apply(self, _recorder: &mut CommandRecorder) {}
@ -266,8 +287,11 @@ pub struct UpdateBuffer {
impl Command for UpdateBuffer { impl Command for UpdateBuffer {
fn side_effects(&self, mut map: SideEffectMap) { fn side_effects(&self, mut map: SideEffectMap) {
self.dst self.dst.side_effect(map.reborrow().into_side_effect_map2(
.side_effect(map.reborrow(), vk::AccessFlags2::TRANSFER_WRITE, None); vk::PipelineStageFlags2::TRANSFER,
vk::AccessFlags2::TRANSFER_WRITE,
None,
));
} }
fn apply(self, _recorder: &mut CommandRecorder) {} fn apply(self, _recorder: &mut CommandRecorder) {}
@ -284,25 +308,26 @@ pub struct BeginRendering {
impl Command for BeginRendering { impl Command for BeginRendering {
fn side_effects(&self, mut map: SideEffectMap) { fn side_effects(&self, mut map: SideEffectMap) {
for attachment in &self.color_attachments { for attachment in &self.color_attachments {
attachment.side_effect( // TODO: consider loadop and storeop?
map.reborrow(), attachment.side_effect(map.reborrow().into_side_effect_map2(
vk::AccessFlags2::COLOR_ATTACHMENT_WRITE, vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT,
vk::AccessFlags2::COLOR_ATTACHMENT_READ,
Some(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL), Some(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL),
); ));
} }
if let Some(depth) = &self.depth_attachment { if let Some(depth) = &self.depth_attachment {
depth.side_effect( depth.side_effect(map.reborrow().into_side_effect_map2(
map.reborrow(), vk::PipelineStageFlags2::EARLY_FRAGMENT_TESTS,
vk::AccessFlags2::DEPTH_STENCIL_ATTACHMENT_WRITE, vk::AccessFlags2::DEPTH_STENCIL_ATTACHMENT_READ,
Some(vk::ImageLayout::DEPTH_ATTACHMENT_OPTIMAL), Some(vk::ImageLayout::DEPTH_ATTACHMENT_OPTIMAL),
); ));
} }
if let Some(stencil) = &self.stencil_attachment { if let Some(stencil) = &self.stencil_attachment {
stencil.side_effect( stencil.side_effect(map.reborrow().into_side_effect_map2(
map.reborrow(), vk::PipelineStageFlags2::EARLY_FRAGMENT_TESTS,
vk::AccessFlags2::DEPTH_STENCIL_ATTACHMENT_WRITE, vk::AccessFlags2::DEPTH_STENCIL_ATTACHMENT_READ,
Some(vk::ImageLayout::STENCIL_ATTACHMENT_OPTIMAL), Some(vk::ImageLayout::STENCIL_ATTACHMENT_OPTIMAL),
); ));
} }
} }
@ -344,11 +369,11 @@ pub struct BindVertexBuffers {
impl Command for BindVertexBuffers { impl Command for BindVertexBuffers {
fn side_effects(&self, mut map: SideEffectMap) { fn side_effects(&self, mut map: SideEffectMap) {
for buffer in &self.buffers { for buffer in &self.buffers {
buffer.side_effect( buffer.side_effect(map.reborrow().into_side_effect_map2(
map.reborrow(), vk::PipelineStageFlags2::VERTEX_ATTRIBUTE_INPUT,
vk::AccessFlags2::VERTEX_ATTRIBUTE_READ, vk::AccessFlags2::VERTEX_ATTRIBUTE_READ,
None, None,
); ));
} }
} }
@ -378,8 +403,11 @@ pub struct BindIndexBuffer(pub BufferSlice, pub IndexFormat);
impl Command for BindIndexBuffer { impl Command for BindIndexBuffer {
fn side_effects(&self, mut map: SideEffectMap) { fn side_effects(&self, mut map: SideEffectMap) {
self.0 self.0.side_effect(map.reborrow().into_side_effect_map2(
.side_effect(map.reborrow(), vk::AccessFlags2::INDEX_READ, None); vk::PipelineStageFlags2::INDEX_INPUT,
vk::AccessFlags2::INDEX_READ,
None,
));
} }
fn apply(self, recorder: &mut CommandRecorder) { fn apply(self, recorder: &mut CommandRecorder) {
@ -532,18 +560,18 @@ impl<T: IsDrawData> Command for Draw<T> {
fn side_effects(&self, mut map: SideEffectMap) { fn side_effects(&self, mut map: SideEffectMap) {
self.data.side_effects(map.reborrow()); self.data.side_effects(map.reborrow());
for vertex_buffer in &self.vertex_buffers { for vertex_buffer in &self.vertex_buffers {
vertex_buffer.side_effect( vertex_buffer.side_effect(map.reborrow().into_side_effect_map2(
map.reborrow(), vk::PipelineStageFlags2::VERTEX_ATTRIBUTE_INPUT,
vk::AccessFlags2::VERTEX_ATTRIBUTE_READ, vk::AccessFlags2::VERTEX_ATTRIBUTE_READ,
None, None,
); ));
} }
if let Some((index_buffer, _)) = &self.index_buffer { if let Some((index_buffer, _)) = &self.index_buffer {
index_buffer.side_effect( index_buffer.side_effect(map.reborrow().into_side_effect_map2(
map.reborrow(), vk::PipelineStageFlags2::INDEX_INPUT,
vk::AccessFlags2::VERTEX_ATTRIBUTE_READ, vk::AccessFlags2::INDEX_READ,
None, None,
); ));
} }
} }
@ -579,20 +607,22 @@ impl IsDrawData for DrawData {}
impl IsDrawData for DrawIndexedData {} impl IsDrawData for DrawIndexedData {}
impl IsDrawData for DrawIndirectData { impl IsDrawData for DrawIndirectData {
fn side_effects(&self, mut map: SideEffectMap) { fn side_effects(&self, mut map: SideEffectMap) {
self.indirect_buffer.side_effect( self.indirect_buffer
map.reborrow(), .side_effect(map.reborrow().into_side_effect_map2(
vk::AccessFlags2::INDIRECT_COMMAND_READ, vk::PipelineStageFlags2::DRAW_INDIRECT,
None, vk::AccessFlags2::INDIRECT_COMMAND_READ,
); None,
));
} }
} }
impl IsDrawData for DrawIndexedIndirectData { impl IsDrawData for DrawIndexedIndirectData {
fn side_effects(&self, mut map: SideEffectMap) { fn side_effects(&self, mut map: SideEffectMap) {
self.indirect_buffer.side_effect( self.indirect_buffer
map.reborrow(), .side_effect(map.reborrow().into_side_effect_map2(
vk::AccessFlags2::INDIRECT_COMMAND_READ, vk::PipelineStageFlags2::DRAW_INDIRECT,
None, vk::AccessFlags2::INDIRECT_COMMAND_READ,
); None,
));
} }
} }

View file

@ -12,7 +12,7 @@ use crate::{
images::ImageDesc, images::ImageDesc,
render_graph::{ render_graph::{
commands::{Command, InsideRenderPass, OutsideRenderPass}, commands::{Command, InsideRenderPass, OutsideRenderPass},
resources::{ResourceAccess, ResourceId, TextureRegion, Write}, resources::{ResourceAccess, ResourceId, ResourceRange, TextureRegion},
}, },
}; };
@ -95,6 +95,56 @@ impl<'a> SideEffectMap<'a> {
pub fn reborrow(&mut self) -> SideEffectMap<'_> { pub fn reborrow(&mut self) -> SideEffectMap<'_> {
SideEffectMap(self.0, self.1) SideEffectMap(self.0, self.1)
} }
pub fn into_side_effect_map2(
self,
stage_flags: vk::PipelineStageFlags2,
access_flags: vk::AccessFlags2,
required_layout: Option<vk::ImageLayout>,
) -> SideEffectMap2<'a> {
SideEffectMap2 {
inner: self.0,
command_index: self.1,
stage_flags,
access_flags,
required_layout,
}
}
}
pub struct SideEffectMap2<'a> {
inner: &'a mut SideEffects,
command_index: u32,
stage_flags: vk::PipelineStageFlags2,
access_flags: vk::AccessFlags2,
required_layout: Option<vk::ImageLayout>,
}
impl<'a> SideEffectMap2<'a> {
pub fn reborrow(&mut self) -> SideEffectMap2<'_> {
SideEffectMap2 {
inner: self.inner,
command_index: self.command_index,
stage_flags: self.stage_flags,
access_flags: self.access_flags,
required_layout: self.required_layout,
}
}
pub fn insert_range<T>(&mut self, id: ResourceId, range: T)
where
(T, vk::ImageLayout): Into<ResourceRange>,
{
self.inner.resources.insert(id);
SideEffectMap(self.inner, self.command_index).insert(
id,
ResourceAccess {
range: (range, self.required_layout.unwrap_or_default()).into(),
stages: self.stage_flags,
access: self.access_flags,
},
);
}
} }
pub struct CommandList<'cmd> { pub struct CommandList<'cmd> {
@ -286,6 +336,7 @@ impl<'cmd> CommandList<'cmd> {
} }
// construct barriers // construct barriers
// TODO: need to know each images aspects at this point
for barrier in barriers { for barrier in barriers {
// stuff // stuff
} }

View file

@ -2,16 +2,11 @@ use std::ops::Deref;
use ash::vk; use ash::vk;
use crate::{images::MipRange, render_graph::recorder::SideEffectMap}; use crate::{images::MipRange, render_graph::recorder::SideEffectMap2};
pub trait Resource: Sized { pub trait Resource: Sized {
fn id(&self) -> ResourceId; fn id(&self) -> ResourceId;
fn side_effect( fn side_effect(&self, map: SideEffectMap2);
&self,
map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
);
} }
mod impls { mod impls {
@ -22,19 +17,8 @@ mod impls {
self.0 self.0
} }
fn side_effect( fn side_effect(&self, mut map: SideEffectMap2) {
&self, map.insert_range(self.id(), BufferRange::full());
mut map: SideEffectMap,
access: vk::AccessFlags2,
_layout: Option<vk::ImageLayout>,
) {
map.insert(
self.id(),
ResourceAccess {
range: BufferRange::full().into(),
access,
},
);
} }
} }
@ -43,19 +27,8 @@ mod impls {
self.buffer.id() self.buffer.id()
} }
fn side_effect( fn side_effect(&self, mut map: SideEffectMap2) {
&self, map.insert_range(self.id(), self.range);
mut map: SideEffectMap,
access: vk::AccessFlags2,
_layout: Option<vk::ImageLayout>,
) {
map.insert(
self.id(),
ResourceAccess {
range: self.range.into(),
access,
},
);
} }
} }
impl Resource for BufferSlices { impl Resource for BufferSlices {
@ -63,43 +36,25 @@ mod impls {
self.buffer.id() self.buffer.id()
} }
fn side_effect( fn side_effect(&self, mut map: SideEffectMap2) {
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
_layout: Option<vk::ImageLayout>,
) {
for range in &self.ranges { for range in &self.ranges {
map.insert( map.insert_range(self.id(), *range);
self.id(),
ResourceAccess {
range: (*range).into(),
access,
},
);
} }
} }
} }
// TODO: the rows are not in bytes, so this is plain wrong. A BufferRowSlice needs to be generic over Buffer/BufferSlice, or commands taking a BufferRowSlice need to take the row parameters separately.
impl Resource for BufferRowSlice { impl Resource for BufferRowSlice {
fn id(&self) -> ResourceId { fn id(&self) -> ResourceId {
self.buffer.id() self.buffer.id()
} }
fn side_effect( fn side_effect(&self, mut map: SideEffectMap2) {
&self, map.insert_range(
mut map: SideEffectMap,
access: vk::AccessFlags2,
_layout: Option<vk::ImageLayout>,
) {
map.insert(
self.id(), self.id(),
ResourceAccess { BufferRange {
range: BufferRange { offset: self.row.offset,
offset: self.row.offset, size: vk::WHOLE_SIZE,
size: (self.row.row_count as u64) * (self.row.row_size as u64),
}
.into(),
access,
}, },
); );
} }
@ -109,22 +64,13 @@ mod impls {
self.buffer.id() self.buffer.id()
} }
fn side_effect( fn side_effect(&self, mut map: SideEffectMap2) {
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
_layout: Option<vk::ImageLayout>,
) {
for row in &self.rows { for row in &self.rows {
map.insert( map.insert_range(
self.id(), self.id(),
ResourceAccess { BufferRange {
range: BufferRange { offset: row.offset,
offset: row.offset, size: vk::WHOLE_SIZE,
size: (row.row_count as u64) * (row.row_size as u64),
}
.into(),
access,
}, },
); );
} }
@ -136,19 +82,8 @@ mod impls {
self.0 self.0
} }
fn side_effect( fn side_effect(&self, mut map: SideEffectMap2) {
&self, map.insert_range(self.id(), TextureRange::full());
mut map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
map.insert(
self.id(),
ResourceAccess {
range: (TextureRange::full(), layout.unwrap_or_default()).into(),
access,
},
);
} }
} }
impl Resource for TextureRegion { impl Resource for TextureRegion {
@ -156,19 +91,8 @@ mod impls {
self.texture.id() self.texture.id()
} }
fn side_effect( fn side_effect(&self, mut map: SideEffectMap2) {
&self, map.insert_range(self.id(), self.range);
mut map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
map.insert(
self.id(),
ResourceAccess {
range: (self.range, layout.unwrap_or_default()).into(),
access,
},
);
} }
} }
impl Resource for TextureRegions { impl Resource for TextureRegions {
@ -176,20 +100,9 @@ mod impls {
self.texture.id() self.texture.id()
} }
fn side_effect( fn side_effect(&self, mut map: SideEffectMap2) {
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
for range in &self.ranges { for range in &self.ranges {
map.insert( map.insert_range(self.id(), *range);
self.id(),
ResourceAccess {
range: (*range, layout.unwrap_or_default()).into(),
access,
},
);
} }
} }
} }
@ -198,19 +111,8 @@ mod impls {
self.texture.id() self.texture.id()
} }
fn side_effect( fn side_effect(&self, mut map: SideEffectMap2) {
&self, map.insert_range(self.id(), self.range);
mut map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
map.insert(
self.id(),
ResourceAccess {
range: (self.range, layout.unwrap_or_default()).into(),
access,
},
);
} }
} }
@ -219,13 +121,8 @@ mod impls {
self.0.id() self.0.id()
} }
fn side_effect( fn side_effect(&self, map: SideEffectMap2) {
&self, self.0.side_effect(map);
map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
self.0.side_effect(map, access, layout);
} }
} }
impl<T: Resource> Resource for Write<T> { impl<T: Resource> Resource for Write<T> {
@ -233,13 +130,8 @@ mod impls {
self.0.id() self.0.id()
} }
fn side_effect( fn side_effect(&self, map: SideEffectMap2) {
&self, self.0.side_effect(map);
map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
self.0.side_effect(map, access, layout);
} }
} }
impl<T: Resource> Resource for ReadWrite<T> { impl<T: Resource> Resource for ReadWrite<T> {
@ -247,37 +139,34 @@ mod impls {
self.0.id() self.0.id()
} }
fn side_effect( fn side_effect(&self, map: SideEffectMap2) {
&self, self.0.side_effect(map);
map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
self.0.side_effect(map, access, layout);
} }
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ResourceId(pub u32); #[repr(transparent)]
pub struct ResourceId(pub u64);
#[derive(Debug, Default, Clone, Copy)] #[derive(Debug, Default, Clone, Copy)]
pub struct ResourceAccess { pub struct ResourceAccess {
pub range: ResourceRange, pub range: ResourceRange,
pub access: vk::AccessFlags2, pub access: vk::AccessFlags2,
pub stages: vk::PipelineStageFlags2,
} }
impl ResourceAccess { impl ResourceAccess {
/// Attempts to fold another ResourceAccess into this one. Returns true if /// Attempts to fold another ResourceAccess into this one. Returns true if
/// successful, false if they are incompatible. /// successful, false if they are incompatible.
pub fn try_fold(&mut self, other: &Self) -> bool { pub fn try_fold(&mut self, other: &Self) -> bool {
if self.access != other.access { // if `other` has access flags that aren't in `self`, we can't fold
// them.
if !self.access.contains(other.access) {
return false; return false;
} }
match (&mut self.range, &other.range) { match (&mut self.range, &other.range) {
(ResourceRange::Buffer { .. }, ResourceRange::Texture { .. }) => false,
(ResourceRange::Texture { .. }, ResourceRange::Buffer { .. }) => false,
( (
ResourceRange::Buffer { offset, size }, ResourceRange::Buffer { offset, size },
ResourceRange::Buffer { ResourceRange::Buffer {
@ -290,6 +179,10 @@ impl ResourceAccess {
return false; return false;
} }
// merge stages: we need the barrier to scope all stages that
// touch the resource.
self.stages |= other.stages;
true true
} }
( (
@ -324,8 +217,14 @@ impl ResourceAccess {
// *origin = lower_left.into(); // *origin = lower_left.into();
// *extent = Extent::from_offset(upper_right - lower_left).into(); // *extent = Extent::from_offset(upper_right - lower_left).into();
// merge stages: we need the barrier to scope all stages that
// touch the resource.
self.stages |= other.stages;
true true
} }
// different resource types can't fold
_ => false,
} }
} }
@ -420,7 +319,7 @@ impl BufferRange {
pub fn full() -> Self { pub fn full() -> Self {
Self { Self {
offset: 0, offset: 0,
size: u64::MAX, size: vk::WHOLE_SIZE,
} }
} }
} }
@ -458,6 +357,15 @@ impl TextureRange {
} }
} }
impl From<(BufferRange, vk::ImageLayout)> for ResourceRange {
fn from((value, _): (BufferRange, vk::ImageLayout)) -> Self {
ResourceRange::Buffer {
offset: value.offset,
size: value.size,
}
}
}
impl From<(TextureRange, vk::ImageLayout)> for ResourceRange { impl From<(TextureRange, vk::ImageLayout)> for ResourceRange {
fn from((value, layout): (TextureRange, vk::ImageLayout)) -> Self { fn from((value, layout): (TextureRange, vk::ImageLayout)) -> Self {
ResourceRange::Texture { ResourceRange::Texture {