#[macro_export]
macro_rules! single_pass_renderpass {
(
$device:expr,
attachments: { $($a:tt)* },
pass: {
color: [$($color_atch:ident),*],
depth_stencil: {$($depth_atch:ident)*}$(,)*
$(resolve: [$($resolve_atch:ident),*])*$(,)*
}
) => (
$crate::ordered_passes_renderpass!(
$device,
attachments: { $($a)* },
passes: [
{
color: [$($color_atch),*],
depth_stencil: {$($depth_atch)*},
input: [],
resolve: [$($($resolve_atch),*)*]
}
]
)
)
}
#[macro_export]
macro_rules! ordered_passes_renderpass {
(
$device:expr,
attachments: {
$(
$atch_name:ident: {
load: $load:ident,
store: $store:ident,
format: $format:expr,
samples: $samples:expr,
$(initial_layout: $init_layout:expr,)*
$(final_layout: $final_layout:expr,)*
}
),*
},
passes: [
$(
{
color: [$($color_atch:ident),*],
depth_stencil: {$($depth_atch:ident)*},
input: [$($input_atch:ident),*]$(,)*
$(resolve: [$($resolve_atch:ident),*])*$(,)*
}
),*
]
) => ({
use $crate::render_pass::RenderPass;
let create_info = {
#[allow(unused)]
let mut attachment_num = 0;
$(
let $atch_name = attachment_num;
attachment_num += 1;
)*
#[allow(unused)]
let mut layouts: Vec<(
Option<$crate::image::ImageLayout>,
Option<$crate::image::ImageLayout>
)> = vec![(None, None); attachment_num as usize];
let subpasses = vec![
$({
let desc = $crate::render_pass::SubpassDescription {
color_attachments: vec![
$({
let layout = &mut layouts[$color_atch as usize];
layout.0 = layout.0.or(Some($crate::image::ImageLayout::ColorAttachmentOptimal));
layout.1 = Some($crate::image::ImageLayout::ColorAttachmentOptimal);
Some($crate::render_pass::AttachmentReference {
attachment: $color_atch,
layout: $crate::image::ImageLayout::ColorAttachmentOptimal,
..Default::default()
})
}),*
],
depth_stencil_attachment: {
let depth: Option<$crate::render_pass::AttachmentReference> = None;
$(
let layout = &mut layouts[$depth_atch as usize];
layout.1 = Some($crate::image::ImageLayout::DepthStencilAttachmentOptimal);
layout.0 = layout.0.or(layout.1);
let depth = Some($crate::render_pass::AttachmentReference {
attachment: $depth_atch,
layout: $crate::image::ImageLayout::DepthStencilAttachmentOptimal,
..Default::default()
});
)*
depth
},
input_attachments: vec![
$({
let layout = &mut layouts[$input_atch as usize];
layout.1 = Some($crate::image::ImageLayout::ShaderReadOnlyOptimal);
layout.0 = layout.0.or(layout.1);
Some($crate::render_pass::AttachmentReference {
attachment: $input_atch,
layout: $crate::image::ImageLayout::ShaderReadOnlyOptimal,
..Default::default()
})
}),*
],
resolve_attachments: vec![
$($({
let layout = &mut layouts[$resolve_atch as usize];
layout.1 = Some($crate::image::ImageLayout::TransferDstOptimal);
layout.0 = layout.0.or(layout.1);
Some($crate::render_pass::AttachmentReference {
attachment: $resolve_atch,
layout: $crate::image::ImageLayout::TransferDstOptimal,
..Default::default()
})
}),*)*
],
preserve_attachments: (0 .. attachment_num).filter(|&a| {
$(if a == $color_atch { return false; })*
$(if a == $depth_atch { return false; })*
$(if a == $input_atch { return false; })*
$($(if a == $resolve_atch { return false; })*)*
true
}).collect(),
..Default::default()
};
assert!(desc.resolve_attachments.is_empty() ||
desc.resolve_attachments.len() == desc.color_attachments.len());
desc
}),*
];
let dependencies: Vec<_> = (0..subpasses.len().saturating_sub(1) as u32)
.map(|id| {
let src_stages = $crate::sync::PipelineStages {
all_graphics: true,
..$crate::sync::PipelineStages::empty()
};
let dst_stages = $crate::sync::PipelineStages {
all_graphics: true,
..$crate::sync::PipelineStages::empty()
};
let src_access = $crate::sync::AccessFlags {
memory_read: true,
memory_write: true,
..$crate::sync::AccessFlags::empty()
};
let dst_access = $crate::sync::AccessFlags {
memory_read: true,
memory_write: true,
..$crate::sync::AccessFlags::empty()
};
$crate::render_pass::SubpassDependency {
src_subpass: id.into(),
dst_subpass: (id + 1).into(),
src_stages,
dst_stages,
src_access,
dst_access,
by_region: true, ..Default::default()
}
})
.collect();
let attachments = vec![
$({
let layout = &mut layouts[$atch_name as usize];
$(layout.0 = Some($init_layout);)*
$(layout.1 = Some($final_layout);)*
$crate::render_pass::AttachmentDescription {
format: Some($format),
samples: $crate::image::SampleCount::try_from($samples).unwrap(),
load_op: $crate::render_pass::LoadOp::$load,
store_op: $crate::render_pass::StoreOp::$store,
stencil_load_op: $crate::render_pass::LoadOp::$load,
stencil_store_op: $crate::render_pass::StoreOp::$store,
initial_layout: layout.0.expect(
format!(
"Attachment {} is missing initial_layout, this is normally \
automatically determined but you can manually specify it for an individual \
attachment in the single_pass_renderpass! macro",
attachment_num
)
.as_ref(),
),
final_layout: layout.1.expect(
format!(
"Attachment {} is missing final_layout, this is normally \
automatically determined but you can manually specify it for an individual \
attachment in the single_pass_renderpass! macro",
attachment_num
)
.as_ref(),
),
..Default::default()
}
}),*
];
$crate::render_pass::RenderPassCreateInfo {
attachments,
subpasses,
dependencies,
..Default::default()
}
};
RenderPass::new($device, create_info)
});
}
#[cfg(test)]
mod tests {
use crate::format::Format;
#[test]
fn single_pass_resolve() {
let (device, _) = gfx_dev_and_queue!();
let _ = single_pass_renderpass!(device,
attachments: {
a: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8_UNORM,
samples: 4,
},
b: {
load: DontCare,
store: Store,
format: Format::R8G8B8A8_UNORM,
samples: 1,
}
},
pass: {
color: [a],
depth_stencil: {},
resolve: [b],
}
)
.unwrap();
}
}