blob: 86f6631d7344c16147f9ca50da6fbf4a0b84feea [file] [log] [blame]
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
#[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),*)*]
}
]
)
)
}
/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
#[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| {
// TODO: correct values
let src_stages = $crate::sync::PipelineStages::ALL_GRAPHICS;
let dst_stages = $crate::sync::PipelineStages::ALL_GRAPHICS;
let src_access = $crate::sync::AccessFlags::MEMORY_READ
| $crate::sync::AccessFlags::MEMORY_WRITE;
let dst_access = $crate::sync::AccessFlags::MEMORY_READ
| $crate::sync::AccessFlags::MEMORY_WRITE;
$crate::render_pass::SubpassDependency {
src_subpass: id.into(),
dst_subpass: (id + 1).into(),
src_stages,
dst_stages,
src_access,
dst_access,
// TODO: correct values
dependency_flags: $crate::sync::DependencyFlags::BY_REGION,
..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();
}
}