From 358c3c518260c9b5488601463efa28d751a091d2 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Sat, 21 Jan 2023 11:11:48 +0100 Subject: [PATCH] Add option to reuse renderpass in rendertarget --- vulkan-rs/src/render_target/mod.rs | 418 ++++++++---------- vulkan-rs/src/render_target/sub_pass.rs | 39 +- .../src/structs/core/attachmentdescription.rs | 2 +- .../src/structs/core/clearcolorvalue.rs | 2 +- vulkan-sys/src/structs/core/clearvalue.rs | 2 +- 5 files changed, 217 insertions(+), 246 deletions(-) diff --git a/vulkan-rs/src/render_target/mod.rs b/vulkan-rs/src/render_target/mod.rs index b72efe5..19f14f0 100644 --- a/vulkan-rs/src/render_target/mod.rs +++ b/vulkan-rs/src/render_target/mod.rs @@ -9,6 +9,7 @@ pub mod sub_pass; use sub_pass::{AttachmentInfo, AttachmentInfoUsage, SubPass}; pub struct RenderTargetBuilder { + old_render_target: Option, sub_passes: Vec, } @@ -19,6 +20,12 @@ impl RenderTargetBuilder { self } + pub fn preserve_old_render_pass(mut self, render_target: RenderTarget) -> Self { + self.old_render_target = Some(render_target); + + self + } + pub fn build(self, device: &Arc) -> Result { #[cfg(debug_assertions)] { @@ -33,160 +40,143 @@ impl RenderTargetBuilder { } } - // create render pass - - // gather attachment descriptions - let mut attachments = Vec::new(); - - self.map_attachment(|attachment| { - attachments.push(attachment.description.clone()); - }); - - // create attachment references - let mut attachment_references: Vec = Vec::new(); - let mut attachment_index = 0; - - // gather all color, depth and resolve attachment and add input attachments from previous sup passes - for sub_pass in self.sub_passes.iter() { - let mut references = SubPassAttachmentReferences::default(); - references.offset = attachment_index as usize; - - for attachment in sub_pass.attachments().iter() { - let attachment_reference = VkAttachmentReference { - attachment: attachment_index, - layout: attachment.layout, - }; - - match attachment.usage { - AttachmentInfoUsage::Output => { - references.color_attachments.push(attachment_reference); - } - AttachmentInfoUsage::Resolve => { - references.resolve_attachments.push(attachment_reference); - } - AttachmentInfoUsage::Depth => { - // make sure only 1 depth attachment is used per subpass - debug_assert!( - references.depth_stencil_attachment.is_none(), - "only 1 depth attachment per sub pass allowed" - ); - - references.depth_stencil_attachment = Some(attachment_reference); - } - } - - attachment_index += 1; - } - - // check if input infos are set - if let Some(input_info) = sub_pass.inputs() { - debug_assert!(input_info.sub_pass_index < attachment_references.len()); - - let input_pass_references = &attachment_references[input_info.sub_pass_index]; - - for input_index in input_info.input_indices.iter() { - references.input_attachments.push(VkAttachmentReference { - attachment: (input_index + input_pass_references.offset) as u32, - layout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - }); - } - } - - attachment_references.push(references); - } - - // gather sub pass descriptions - let mut descriptions = Vec::new(); - - for attachment_reference in attachment_references.iter() { - descriptions.push(VkSubpassDescription::new( - 0, - &attachment_reference.input_attachments, - &attachment_reference.color_attachments, - &attachment_reference.resolve_attachments, - attachment_reference.depth_stencil_attachment.as_ref(), - &[], - )); - } - - // gather sub pass dependencies - let mut dependencies = Vec::new(); - - dependencies.push(VkSubpassDependency::new( - VK_SUBPASS_EXTERNAL, - 0, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_MEMORY_READ_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_DEPENDENCY_BY_REGION_BIT, - )); - - for (index, sub_pass) in self.sub_passes.iter().enumerate() { - dependencies.push(VkSubpassDependency::new( - index as u32, - index as u32 + 1, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - CommandBuffer::access_to_stage(sub_pass.output_usage()), - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - sub_pass.output_usage(), - VK_DEPENDENCY_BY_REGION_BIT, - )); - } - - if let Some(last_dependency) = dependencies.last_mut() { - last_dependency.dstSubpass = VK_SUBPASS_EXTERNAL; - last_dependency.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT.into(); - last_dependency.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT.into(); - } - - // dependencies.push(VkSubpassDependency::new( - // self.sub_passes.len() as u32 - 1, - // VK_SUBPASS_EXTERNAL, - // VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - // VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - // VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - // VK_ACCESS_MEMORY_READ_BIT, - // VK_DEPENDENCY_BY_REGION_BIT, - // )); - - let render_pass = - RenderPass::new(device.clone(), &descriptions, &attachments, &dependencies)?; - - // create frame buffers - let max_images = self.max_images(); - let extent = self.sub_passes[0].extent(); - - let framebuffers: Result>> = (0..max_images) - .map(|i| { - let mut framebuffer_builder = Framebuffer::builder() - .set_render_pass(&render_pass) - .set_width(extent.width) - .set_height(extent.height); - - for sub_pass in self.sub_passes.iter() { - for attachment in sub_pass.attachments().iter() { - framebuffer_builder = - framebuffer_builder.add_attachment(attachment.image(i)); - } - } - - framebuffer_builder.build(render_pass.device().clone()) - }) - .collect(); - let mut clear_values = Vec::new(); self.map_attachment(|attachment| { clear_values.push(attachment.clear_value.clone()); }); + // create render pass + let render_pass = match self.old_render_target { + Some(old_render_target) => { + if !Self::verify_setups(&old_render_target.sub_passes, &self.sub_passes) { + return Err(anyhow::anyhow!( + "Can't preserve old RenderPass if subpasses don't match!" + )); + } + + old_render_target.render_pass + } + None => { + // gather attachment descriptions + let mut attachments = Vec::new(); + + self.map_attachment(|attachment| { + attachments.push(attachment.description.clone()); + }); + + // create attachment references + let mut attachment_references: Vec = Vec::new(); + let mut attachment_index = 0; + + // gather all color, depth and resolve attachment and add input attachments from previous sup passes + for sub_pass in self.sub_passes.iter() { + let mut references = SubPassAttachmentReferences::default(); + references.offset = attachment_index as usize; + + for attachment in sub_pass.attachments().iter() { + let attachment_reference = VkAttachmentReference { + attachment: attachment_index, + layout: attachment.layout, + }; + + match attachment.usage { + AttachmentInfoUsage::Output => { + references.color_attachments.push(attachment_reference); + } + AttachmentInfoUsage::Resolve => { + references.resolve_attachments.push(attachment_reference); + } + AttachmentInfoUsage::Depth => { + // make sure only 1 depth attachment is used per subpass + debug_assert!( + references.depth_stencil_attachment.is_none(), + "only 1 depth attachment per sub pass allowed" + ); + + references.depth_stencil_attachment = Some(attachment_reference); + } + } + + attachment_index += 1; + } + + // check if input infos are set + if let Some(input_info) = sub_pass.inputs() { + debug_assert!(input_info.sub_pass_index < attachment_references.len()); + + let input_pass_references = + &attachment_references[input_info.sub_pass_index]; + + for input_index in input_info.input_indices.iter() { + references.input_attachments.push(VkAttachmentReference { + attachment: (input_index + input_pass_references.offset) as u32, + layout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }); + } + } + + attachment_references.push(references); + } + + // gather sub pass descriptions + let mut descriptions = Vec::new(); + + for attachment_reference in attachment_references.iter() { + descriptions.push(VkSubpassDescription::new( + 0, + &attachment_reference.input_attachments, + &attachment_reference.color_attachments, + &attachment_reference.resolve_attachments, + attachment_reference.depth_stencil_attachment.as_ref(), + &[], + )); + } + + // gather sub pass dependencies + let mut dependencies = Vec::new(); + + dependencies.push(VkSubpassDependency::new( + VK_SUBPASS_EXTERNAL, + 0, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_MEMORY_READ_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_DEPENDENCY_BY_REGION_BIT, + )); + + for (index, sub_pass) in self.sub_passes.iter().enumerate() { + dependencies.push(VkSubpassDependency::new( + index as u32, + index as u32 + 1, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + CommandBuffer::access_to_stage(sub_pass.output_usage()), + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + sub_pass.output_usage(), + VK_DEPENDENCY_BY_REGION_BIT, + )); + } + + if let Some(last_dependency) = dependencies.last_mut() { + last_dependency.dstSubpass = VK_SUBPASS_EXTERNAL; + last_dependency.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT.into(); + last_dependency.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT.into(); + } + + RenderPass::new(device.clone(), &descriptions, &attachments, &dependencies)? + } + }; + + // create frame buffers + let framebuffers = Self::create_framebuffers(&render_pass, &self.sub_passes)?; + Ok(RenderTarget { render_pass, - framebuffers: framebuffers?, + framebuffers, clear_values, - extent, + extent: self.sub_passes[0].extent(), sub_passes: self.sub_passes, @@ -195,17 +185,56 @@ impl RenderTargetBuilder { }) } + fn create_framebuffers( + render_pass: &Arc, + sub_passes: &[SubPass], + ) -> Result>> { + let extent = sub_passes[0].extent(); + + (0..Self::max_images(sub_passes)) + .map(|i| { + let mut framebuffer_builder = Framebuffer::builder() + .set_render_pass(render_pass) + .set_width(extent.width) + .set_height(extent.height); + + for sub_pass in sub_passes.iter() { + for attachment in sub_pass.attachments().iter() { + framebuffer_builder = + framebuffer_builder.add_attachment(attachment.image(i)); + } + } + + framebuffer_builder.build(render_pass.device().clone()) + }) + .collect() + } + #[inline] - fn max_images(&self) -> usize { + fn max_images(sub_passes: &[SubPass]) -> usize { let mut max_images = 0; - for sub_pass in self.sub_passes.iter() { + for sub_pass in sub_passes.iter() { max_images = max_images.max(sub_pass.max_images_per_attachment()); } max_images } + fn verify_setups(old_sub_passes: &[SubPass], new_sub_passes: &[SubPass]) -> bool { + if old_sub_passes.len() != new_sub_passes.len() { + return false; + } + + for (new_sub_pass, old_sub_pass) in old_sub_passes.iter().zip(new_sub_passes.iter()) { + if !new_sub_pass.verify_setup(old_sub_pass) { + return false; + } + } + + true + } + #[inline] fn map_attachment<'a, F>(&'a self, mut f: F) where @@ -247,6 +276,7 @@ pub struct RenderTarget { impl RenderTarget { pub fn builder() -> RenderTargetBuilder { RenderTargetBuilder { + old_render_target: None, sub_passes: Vec::new(), } } @@ -315,99 +345,3 @@ impl RenderTarget { buffer_recorder.end_render_pass(); } } - -// impl<'a> RenderTargetBuilder<'a> { -// fn create_images_and_renderpass(&self, device: &Arc) -> Result> { -// let subpass_descriptions = [match resolve_reference { -// Some(resvole_ref) => VkSubpassDescription::new( -// 0, -// &[], -// color_references.as_slice(), -// &[resvole_ref], -// match depth_reference { -// Some(ref depth_ref) => Some(depth_ref), -// None => None, -// }, -// &[], -// ), -// None => VkSubpassDescription::new( -// 0, -// &[], -// color_references.as_slice(), -// &[], -// match depth_reference { -// Some(ref depth_ref) => Some(depth_ref), -// None => None, -// }, -// &[], -// ), -// }]; - -// let dependencies = if color_references.is_empty() { -// // assume, that when no color references are given, -// // we want to store the depth information for later -// if depth_reference.is_some() { -// for attachment in &mut attachments { -// if attachment.format == VK_FORMAT_D16_UNORM { -// attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; -// attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; -// break; -// } -// } -// } - -// [ -// VkSubpassDependency::new( -// VK_SUBPASS_EXTERNAL, -// 0, -// VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, -// VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, -// 0, -// VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT -// | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, -// VK_DEPENDENCY_BY_REGION_BIT, -// ), -// VkSubpassDependency::new( -// 0, -// VK_SUBPASS_EXTERNAL, -// VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, -// VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, -// VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT -// | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, -// VK_ACCESS_SHADER_READ_BIT, -// VK_DEPENDENCY_BY_REGION_BIT, -// ), -// ] -// } else { -// [ -// VkSubpassDependency::new( -// VK_SUBPASS_EXTERNAL, -// 0, -// VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, -// VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, -// VK_ACCESS_MEMORY_READ_BIT, -// VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, -// VK_DEPENDENCY_BY_REGION_BIT, -// ), -// VkSubpassDependency::new( -// 0, -// VK_SUBPASS_EXTERNAL, -// VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, -// VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, -// VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, -// VK_ACCESS_MEMORY_READ_BIT, -// VK_DEPENDENCY_BY_REGION_BIT, -// ), -// ] -// }; - -// let renderpass = RenderPass::new( -// device.clone(), -// &subpass_descriptions, -// attachments.as_slice(), -// &dependencies, -// )?; - -// Ok(renderpass) -// } -// } diff --git a/vulkan-rs/src/render_target/sub_pass.rs b/vulkan-rs/src/render_target/sub_pass.rs index 8fc90bb..d58af88 100644 --- a/vulkan-rs/src/render_target/sub_pass.rs +++ b/vulkan-rs/src/render_target/sub_pass.rs @@ -157,7 +157,7 @@ impl<'a> From<&'a Vec>> for ResolveTarget { } } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub struct InputAttachmentInfo { pub sub_pass_index: usize, pub input_indices: Vec, @@ -383,6 +383,13 @@ impl AttachmentInfo { &self.images[index] } + + fn verify_setup(&self, other: &Self) -> bool { + self.clear_value == other.clear_value + && self.layout == other.layout + && self.description == other.description + && self.usage == other.usage + } } #[derive(Debug)] @@ -439,4 +446,34 @@ impl SubPass { max_images } + + pub(crate) fn verify_setup(&self, other: &Self) -> bool { + if self.output_usage != other.output_usage { + return false; + } + + match (&self.input_info, &other.input_info) { + (None, None) => (), + (Some(self_input_info), Some(other_input_info)) => { + if self_input_info != other_input_info { + return false; + } + } + (None, Some(_)) | (Some(_), None) => return false, + } + + if self.attachments.len() != other.attachments.len() { + return false; + } + + for (self_attachment, other_attachment) in + self.attachments.iter().zip(other.attachments.iter()) + { + if !self_attachment.verify_setup(other_attachment) { + return false; + } + } + + true + } } diff --git a/vulkan-sys/src/structs/core/attachmentdescription.rs b/vulkan-sys/src/structs/core/attachmentdescription.rs index f43004b..8f75229 100644 --- a/vulkan-sys/src/structs/core/attachmentdescription.rs +++ b/vulkan-sys/src/structs/core/attachmentdescription.rs @@ -1,7 +1,7 @@ use crate::prelude::*; #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct VkAttachmentDescription { pub flags: VkAttachmentDescriptionFlagBits, pub format: VkFormat, diff --git a/vulkan-sys/src/structs/core/clearcolorvalue.rs b/vulkan-sys/src/structs/core/clearcolorvalue.rs index 68118ce..2ca3f54 100644 --- a/vulkan-sys/src/structs/core/clearcolorvalue.rs +++ b/vulkan-sys/src/structs/core/clearcolorvalue.rs @@ -1,7 +1,7 @@ use std::mem; #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct VkClearColorValue([u32; 4]); impl VkClearColorValue { diff --git a/vulkan-sys/src/structs/core/clearvalue.rs b/vulkan-sys/src/structs/core/clearvalue.rs index f2dfe2e..b4d9a45 100644 --- a/vulkan-sys/src/structs/core/clearvalue.rs +++ b/vulkan-sys/src/structs/core/clearvalue.rs @@ -3,7 +3,7 @@ use crate::prelude::*; use std::mem; #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct VkClearValue(VkClearColorValue); impl VkClearValue {