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::{
device::DeviceOwned,
pipeline::Pipeline,
render_graph::recorder::{CommandRecorder, SideEffectMap},
};
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 src: Read<BufferSlice>,
// pub dst: Write<BufferSlice>,
@ -46,16 +67,16 @@ pub struct Copy<T: Resource, U: Resource> {
}
impl<T: Resource, U: Resource> Copy<T, U> {
fn side_effects_inner(&self, mut map: SideEffectMap) {
self.src.side_effect(
map.reborrow(),
self.src.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::TRANSFER,
vk::AccessFlags2::TRANSFER_READ,
Some(vk::ImageLayout::TRANSFER_SRC_OPTIMAL),
);
self.dst.side_effect(
map.reborrow(),
));
self.src.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::TRANSFER,
vk::AccessFlags2::TRANSFER_WRITE,
Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
);
));
}
}
@ -249,11 +270,11 @@ pub struct ClearTexture {
impl Command for ClearTexture {
fn side_effects(&self, mut map: SideEffectMap) {
self.dst.side_effect(
map.reborrow(),
self.dst.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::TRANSFER,
vk::AccessFlags2::TRANSFER_WRITE,
Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
);
));
}
fn apply(self, _recorder: &mut CommandRecorder) {}
@ -266,8 +287,11 @@ pub struct UpdateBuffer {
impl Command for UpdateBuffer {
fn side_effects(&self, mut map: SideEffectMap) {
self.dst
.side_effect(map.reborrow(), vk::AccessFlags2::TRANSFER_WRITE, None);
self.dst.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::TRANSFER,
vk::AccessFlags2::TRANSFER_WRITE,
None,
));
}
fn apply(self, _recorder: &mut CommandRecorder) {}
@ -284,25 +308,26 @@ pub struct BeginRendering {
impl Command for BeginRendering {
fn side_effects(&self, mut map: SideEffectMap) {
for attachment in &self.color_attachments {
attachment.side_effect(
map.reborrow(),
vk::AccessFlags2::COLOR_ATTACHMENT_WRITE,
// TODO: consider loadop and storeop?
attachment.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT,
vk::AccessFlags2::COLOR_ATTACHMENT_READ,
Some(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL),
);
));
}
if let Some(depth) = &self.depth_attachment {
depth.side_effect(
map.reborrow(),
vk::AccessFlags2::DEPTH_STENCIL_ATTACHMENT_WRITE,
depth.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::EARLY_FRAGMENT_TESTS,
vk::AccessFlags2::DEPTH_STENCIL_ATTACHMENT_READ,
Some(vk::ImageLayout::DEPTH_ATTACHMENT_OPTIMAL),
);
));
}
if let Some(stencil) = &self.stencil_attachment {
stencil.side_effect(
map.reborrow(),
vk::AccessFlags2::DEPTH_STENCIL_ATTACHMENT_WRITE,
stencil.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::EARLY_FRAGMENT_TESTS,
vk::AccessFlags2::DEPTH_STENCIL_ATTACHMENT_READ,
Some(vk::ImageLayout::STENCIL_ATTACHMENT_OPTIMAL),
);
));
}
}
@ -344,11 +369,11 @@ pub struct BindVertexBuffers {
impl Command for BindVertexBuffers {
fn side_effects(&self, mut map: SideEffectMap) {
for buffer in &self.buffers {
buffer.side_effect(
map.reborrow(),
buffer.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::VERTEX_ATTRIBUTE_INPUT,
vk::AccessFlags2::VERTEX_ATTRIBUTE_READ,
None,
);
));
}
}
@ -378,8 +403,11 @@ pub struct BindIndexBuffer(pub BufferSlice, pub IndexFormat);
impl Command for BindIndexBuffer {
fn side_effects(&self, mut map: SideEffectMap) {
self.0
.side_effect(map.reborrow(), vk::AccessFlags2::INDEX_READ, None);
self.0.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::INDEX_INPUT,
vk::AccessFlags2::INDEX_READ,
None,
));
}
fn apply(self, recorder: &mut CommandRecorder) {
@ -532,18 +560,18 @@ impl<T: IsDrawData> Command for Draw<T> {
fn side_effects(&self, mut map: SideEffectMap) {
self.data.side_effects(map.reborrow());
for vertex_buffer in &self.vertex_buffers {
vertex_buffer.side_effect(
map.reborrow(),
vertex_buffer.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::VERTEX_ATTRIBUTE_INPUT,
vk::AccessFlags2::VERTEX_ATTRIBUTE_READ,
None,
);
));
}
if let Some((index_buffer, _)) = &self.index_buffer {
index_buffer.side_effect(
map.reborrow(),
vk::AccessFlags2::VERTEX_ATTRIBUTE_READ,
index_buffer.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::INDEX_INPUT,
vk::AccessFlags2::INDEX_READ,
None,
);
));
}
}
@ -579,20 +607,22 @@ impl IsDrawData for DrawData {}
impl IsDrawData for DrawIndexedData {}
impl IsDrawData for DrawIndirectData {
fn side_effects(&self, mut map: SideEffectMap) {
self.indirect_buffer.side_effect(
map.reborrow(),
vk::AccessFlags2::INDIRECT_COMMAND_READ,
None,
);
self.indirect_buffer
.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::DRAW_INDIRECT,
vk::AccessFlags2::INDIRECT_COMMAND_READ,
None,
));
}
}
impl IsDrawData for DrawIndexedIndirectData {
fn side_effects(&self, mut map: SideEffectMap) {
self.indirect_buffer.side_effect(
map.reborrow(),
vk::AccessFlags2::INDIRECT_COMMAND_READ,
None,
);
self.indirect_buffer
.side_effect(map.reborrow().into_side_effect_map2(
vk::PipelineStageFlags2::DRAW_INDIRECT,
vk::AccessFlags2::INDIRECT_COMMAND_READ,
None,
));
}
}

View file

@ -12,7 +12,7 @@ use crate::{
images::ImageDesc,
render_graph::{
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<'_> {
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> {
@ -286,6 +336,7 @@ impl<'cmd> CommandList<'cmd> {
}
// construct barriers
// TODO: need to know each images aspects at this point
for barrier in barriers {
// stuff
}

View file

@ -2,16 +2,11 @@ use std::ops::Deref;
use ash::vk;
use crate::{images::MipRange, render_graph::recorder::SideEffectMap};
use crate::{images::MipRange, render_graph::recorder::SideEffectMap2};
pub trait Resource: Sized {
fn id(&self) -> ResourceId;
fn side_effect(
&self,
map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
);
fn side_effect(&self, map: SideEffectMap2);
}
mod impls {
@ -22,19 +17,8 @@ mod impls {
self.0
}
fn side_effect(
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
_layout: Option<vk::ImageLayout>,
) {
map.insert(
self.id(),
ResourceAccess {
range: BufferRange::full().into(),
access,
},
);
fn side_effect(&self, mut map: SideEffectMap2) {
map.insert_range(self.id(), BufferRange::full());
}
}
@ -43,19 +27,8 @@ mod impls {
self.buffer.id()
}
fn side_effect(
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
_layout: Option<vk::ImageLayout>,
) {
map.insert(
self.id(),
ResourceAccess {
range: self.range.into(),
access,
},
);
fn side_effect(&self, mut map: SideEffectMap2) {
map.insert_range(self.id(), self.range);
}
}
impl Resource for BufferSlices {
@ -63,43 +36,25 @@ mod impls {
self.buffer.id()
}
fn side_effect(
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
_layout: Option<vk::ImageLayout>,
) {
fn side_effect(&self, mut map: SideEffectMap2) {
for range in &self.ranges {
map.insert(
self.id(),
ResourceAccess {
range: (*range).into(),
access,
},
);
map.insert_range(self.id(), *range);
}
}
}
// 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 {
fn id(&self) -> ResourceId {
self.buffer.id()
}
fn side_effect(
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
_layout: Option<vk::ImageLayout>,
) {
map.insert(
fn side_effect(&self, mut map: SideEffectMap2) {
map.insert_range(
self.id(),
ResourceAccess {
range: BufferRange {
offset: self.row.offset,
size: (self.row.row_count as u64) * (self.row.row_size as u64),
}
.into(),
access,
BufferRange {
offset: self.row.offset,
size: vk::WHOLE_SIZE,
},
);
}
@ -109,22 +64,13 @@ mod impls {
self.buffer.id()
}
fn side_effect(
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
_layout: Option<vk::ImageLayout>,
) {
fn side_effect(&self, mut map: SideEffectMap2) {
for row in &self.rows {
map.insert(
map.insert_range(
self.id(),
ResourceAccess {
range: BufferRange {
offset: row.offset,
size: (row.row_count as u64) * (row.row_size as u64),
}
.into(),
access,
BufferRange {
offset: row.offset,
size: vk::WHOLE_SIZE,
},
);
}
@ -136,19 +82,8 @@ mod impls {
self.0
}
fn side_effect(
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
map.insert(
self.id(),
ResourceAccess {
range: (TextureRange::full(), layout.unwrap_or_default()).into(),
access,
},
);
fn side_effect(&self, mut map: SideEffectMap2) {
map.insert_range(self.id(), TextureRange::full());
}
}
impl Resource for TextureRegion {
@ -156,19 +91,8 @@ mod impls {
self.texture.id()
}
fn side_effect(
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
map.insert(
self.id(),
ResourceAccess {
range: (self.range, layout.unwrap_or_default()).into(),
access,
},
);
fn side_effect(&self, mut map: SideEffectMap2) {
map.insert_range(self.id(), self.range);
}
}
impl Resource for TextureRegions {
@ -176,20 +100,9 @@ mod impls {
self.texture.id()
}
fn side_effect(
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
fn side_effect(&self, mut map: SideEffectMap2) {
for range in &self.ranges {
map.insert(
self.id(),
ResourceAccess {
range: (*range, layout.unwrap_or_default()).into(),
access,
},
);
map.insert_range(self.id(), *range);
}
}
}
@ -198,19 +111,8 @@ mod impls {
self.texture.id()
}
fn side_effect(
&self,
mut map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
map.insert(
self.id(),
ResourceAccess {
range: (self.range, layout.unwrap_or_default()).into(),
access,
},
);
fn side_effect(&self, mut map: SideEffectMap2) {
map.insert_range(self.id(), self.range);
}
}
@ -219,13 +121,8 @@ mod impls {
self.0.id()
}
fn side_effect(
&self,
map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
self.0.side_effect(map, access, layout);
fn side_effect(&self, map: SideEffectMap2) {
self.0.side_effect(map);
}
}
impl<T: Resource> Resource for Write<T> {
@ -233,13 +130,8 @@ mod impls {
self.0.id()
}
fn side_effect(
&self,
map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
self.0.side_effect(map, access, layout);
fn side_effect(&self, map: SideEffectMap2) {
self.0.side_effect(map);
}
}
impl<T: Resource> Resource for ReadWrite<T> {
@ -247,37 +139,34 @@ mod impls {
self.0.id()
}
fn side_effect(
&self,
map: SideEffectMap,
access: vk::AccessFlags2,
layout: Option<vk::ImageLayout>,
) {
self.0.side_effect(map, access, layout);
fn side_effect(&self, map: SideEffectMap2) {
self.0.side_effect(map);
}
}
}
#[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)]
pub struct ResourceAccess {
pub range: ResourceRange,
pub access: vk::AccessFlags2,
pub stages: vk::PipelineStageFlags2,
}
impl ResourceAccess {
/// Attempts to fold another ResourceAccess into this one. Returns true if
/// successful, false if they are incompatible.
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;
}
match (&mut self.range, &other.range) {
(ResourceRange::Buffer { .. }, ResourceRange::Texture { .. }) => false,
(ResourceRange::Texture { .. }, ResourceRange::Buffer { .. }) => false,
(
ResourceRange::Buffer { offset, size },
ResourceRange::Buffer {
@ -290,6 +179,10 @@ impl ResourceAccess {
return false;
}
// merge stages: we need the barrier to scope all stages that
// touch the resource.
self.stages |= other.stages;
true
}
(
@ -324,8 +217,14 @@ impl ResourceAccess {
// *origin = 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
}
// different resource types can't fold
_ => false,
}
}
@ -420,7 +319,7 @@ impl BufferRange {
pub fn full() -> Self {
Self {
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 {
fn from((value, layout): (TextureRange, vk::ImageLayout)) -> Self {
ResourceRange::Texture {