Add option to reuse renderpass in rendertarget

This commit is contained in:
hodasemi 2023-01-21 11:11:48 +01:00
parent dca9ab20be
commit 358c3c5182
5 changed files with 217 additions and 246 deletions

View file

@ -9,6 +9,7 @@ pub mod sub_pass;
use sub_pass::{AttachmentInfo, AttachmentInfoUsage, SubPass}; use sub_pass::{AttachmentInfo, AttachmentInfoUsage, SubPass};
pub struct RenderTargetBuilder { pub struct RenderTargetBuilder {
old_render_target: Option<RenderTarget>,
sub_passes: Vec<SubPass>, sub_passes: Vec<SubPass>,
} }
@ -19,6 +20,12 @@ impl RenderTargetBuilder {
self 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<Device>) -> Result<RenderTarget> { pub fn build(self, device: &Arc<Device>) -> Result<RenderTarget> {
#[cfg(debug_assertions)] #[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<SubPassAttachmentReferences> = 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<Vec<Arc<Framebuffer>>> = (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(); let mut clear_values = Vec::new();
self.map_attachment(|attachment| { self.map_attachment(|attachment| {
clear_values.push(attachment.clear_value.clone()); 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<SubPassAttachmentReferences> = 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 { Ok(RenderTarget {
render_pass, render_pass,
framebuffers: framebuffers?, framebuffers,
clear_values, clear_values,
extent, extent: self.sub_passes[0].extent(),
sub_passes: self.sub_passes, sub_passes: self.sub_passes,
@ -195,17 +185,56 @@ impl RenderTargetBuilder {
}) })
} }
fn create_framebuffers(
render_pass: &Arc<RenderPass>,
sub_passes: &[SubPass],
) -> Result<Vec<Arc<Framebuffer>>> {
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] #[inline]
fn max_images(&self) -> usize { fn max_images(sub_passes: &[SubPass]) -> usize {
let mut max_images = 0; 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 = max_images.max(sub_pass.max_images_per_attachment());
} }
max_images 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] #[inline]
fn map_attachment<'a, F>(&'a self, mut f: F) fn map_attachment<'a, F>(&'a self, mut f: F)
where where
@ -247,6 +276,7 @@ pub struct RenderTarget {
impl RenderTarget { impl RenderTarget {
pub fn builder() -> RenderTargetBuilder { pub fn builder() -> RenderTargetBuilder {
RenderTargetBuilder { RenderTargetBuilder {
old_render_target: None,
sub_passes: Vec::new(), sub_passes: Vec::new(),
} }
} }
@ -315,99 +345,3 @@ impl RenderTarget {
buffer_recorder.end_render_pass(); buffer_recorder.end_render_pass();
} }
} }
// impl<'a> RenderTargetBuilder<'a> {
// fn create_images_and_renderpass(&self, device: &Arc<Device>) -> Result<Arc<RenderPass>> {
// 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)
// }
// }

View file

@ -157,7 +157,7 @@ impl<'a> From<&'a Vec<Arc<Image>>> for ResolveTarget {
} }
} }
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
pub struct InputAttachmentInfo { pub struct InputAttachmentInfo {
pub sub_pass_index: usize, pub sub_pass_index: usize,
pub input_indices: Vec<usize>, pub input_indices: Vec<usize>,
@ -383,6 +383,13 @@ impl AttachmentInfo {
&self.images[index] &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)] #[derive(Debug)]
@ -439,4 +446,34 @@ impl SubPass {
max_images 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
}
} }

View file

@ -1,7 +1,7 @@
use crate::prelude::*; use crate::prelude::*;
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct VkAttachmentDescription { pub struct VkAttachmentDescription {
pub flags: VkAttachmentDescriptionFlagBits, pub flags: VkAttachmentDescriptionFlagBits,
pub format: VkFormat, pub format: VkFormat,

View file

@ -1,7 +1,7 @@
use std::mem; use std::mem;
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct VkClearColorValue([u32; 4]); pub struct VkClearColorValue([u32; 4]);
impl VkClearColorValue { impl VkClearColorValue {

View file

@ -3,7 +3,7 @@ use crate::prelude::*;
use std::mem; use std::mem;
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct VkClearValue(VkClearColorValue); pub struct VkClearValue(VkClearColorValue);
impl VkClearValue { impl VkClearValue {