diff --git a/crates/renderer/src/render_graph/commands.rs b/crates/renderer/src/render_graph/commands.rs index 7b921ef..df93dae 100644 --- a/crates/renderer/src/render_graph/commands.rs +++ b/crates/renderer/src/render_graph/commands.rs @@ -14,12 +14,33 @@ use crate::{ device::DeviceOwned, - pipeline::Pipeline, render_graph::recorder::{CommandRecorder, SideEffectMap}, }; use super::resources::*; +pub struct ImportResource { + pub resource: T, + pub access: vk::AccessFlags2, + pub stage: vk::PipelineStageFlags2, + pub layout: Option, +} + +impl Command for ImportResource { + 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, // pub dst: Write, @@ -46,16 +67,16 @@ pub struct Copy { } impl Copy { 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 Command for Draw { 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, + )); } } diff --git a/crates/renderer/src/render_graph/recorder.rs b/crates/renderer/src/render_graph/recorder.rs index 68c1d4c..6e83079 100644 --- a/crates/renderer/src/render_graph/recorder.rs +++ b/crates/renderer/src/render_graph/recorder.rs @@ -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, + ) -> 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, +} + +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(&mut self, id: ResourceId, range: T) + where + (T, vk::ImageLayout): Into, + { + 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 } diff --git a/crates/renderer/src/render_graph/resources.rs b/crates/renderer/src/render_graph/resources.rs index 65f4d06..34e54fd 100644 --- a/crates/renderer/src/render_graph/resources.rs +++ b/crates/renderer/src/render_graph/resources.rs @@ -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, - ); + 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, - ) { - 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, - ) { - 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, - ) { + 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, - ) { - 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, - ) { + 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, - ) { - 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, - ) { - 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, - ) { + 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, - ) { - 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, - ) { - self.0.side_effect(map, access, layout); + fn side_effect(&self, map: SideEffectMap2) { + self.0.side_effect(map); } } impl Resource for Write { @@ -233,13 +130,8 @@ mod impls { self.0.id() } - fn side_effect( - &self, - map: SideEffectMap, - access: vk::AccessFlags2, - layout: Option, - ) { - self.0.side_effect(map, access, layout); + fn side_effect(&self, map: SideEffectMap2) { + self.0.side_effect(map); } } impl Resource for ReadWrite { @@ -247,37 +139,34 @@ mod impls { self.0.id() } - fn side_effect( - &self, - map: SideEffectMap, - access: vk::AccessFlags2, - layout: Option, - ) { - 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 {