// Copyright (c) 2016 The vulkano developers // Licensed under the Apache License, Version 2.0 // or the MIT // license , // 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(); } }