diff options
Diffstat (limited to 'src/render_pass/render_pass.rs')
-rw-r--r-- | src/render_pass/render_pass.rs | 911 |
1 files changed, 0 insertions, 911 deletions
diff --git a/src/render_pass/render_pass.rs b/src/render_pass/render_pass.rs deleted file mode 100644 index 629dc8e..0000000 --- a/src/render_pass/render_pass.rs +++ /dev/null @@ -1,911 +0,0 @@ -// 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. - -use crate::check_errors; -use crate::device::Device; -use crate::device::DeviceOwned; -use crate::format::FormatTy; -use crate::image::ImageLayout; -use crate::image::SampleCount; -use crate::pipeline::shader::ShaderInterface; -use crate::render_pass::AttachmentDesc; -use crate::render_pass::LoadOp; -use crate::render_pass::RenderPassDesc; -use crate::render_pass::SubpassDesc; -use crate::Error; -use crate::OomError; -use crate::VulkanObject; -use smallvec::SmallVec; -use std::error; -use std::fmt; -use std::marker::PhantomData; -use std::mem::MaybeUninit; -use std::ptr; -use std::sync::Arc; -use std::sync::Mutex; - -/// An object representing the discrete steps in which rendering is done. -/// -/// A render pass in Vulkan is made up of three parts: -/// - A list of attachments, which are image views that are inputs, outputs or intermediate stages -/// in the rendering process. -/// - One or more subpasses, which are the steps in which the rendering process, takes place, -/// and the attachments that are used for each step. -/// - Dependencies, which describe how the input and output data of each subpass is to be passed -/// from one subpass to the next. -/// -/// In order to create a render pass, you must create a `RenderPassDesc` object that describes the -/// render pass, then pass it to `RenderPass::new`. -/// -/// ``` -/// use vulkano::render_pass::RenderPass; -/// use vulkano::render_pass::RenderPassDesc; -/// -/// # let device: std::sync::Arc<vulkano::device::Device> = return; -/// let desc = RenderPassDesc::empty(); -/// let render_pass = RenderPass::new(device.clone(), desc).unwrap(); -/// ``` -/// -/// This example creates a render pass with no attachment and one single subpass that doesn't draw -/// on anything. While it's sometimes useful, most of the time it's not what you want. -/// -/// The easiest way to create a "real" render pass is to use the `single_pass_renderpass!` macro. -/// -/// ``` -/// # #[macro_use] extern crate vulkano; -/// # fn main() { -/// # let device: std::sync::Arc<vulkano::device::Device> = return; -/// use vulkano::format::Format; -/// -/// let render_pass = single_pass_renderpass!(device.clone(), -/// attachments: { -/// // `foo` is a custom name we give to the first and only attachment. -/// foo: { -/// load: Clear, -/// store: Store, -/// format: Format::R8G8B8A8Unorm, -/// samples: 1, -/// } -/// }, -/// pass: { -/// color: [foo], // Repeat the attachment name here. -/// depth_stencil: {} -/// } -/// ).unwrap(); -/// # } -/// ``` -/// -/// See the documentation of the macro for more details. TODO: put link here -pub struct RenderPass { - // The internal Vulkan object. - render_pass: ash::vk::RenderPass, - - // Device this render pass was created from. - device: Arc<Device>, - - // Description of the render pass. - desc: RenderPassDesc, - - // Cache of the granularity of the render pass. - granularity: Mutex<Option<[u32; 2]>>, -} - -impl RenderPass { - /// Builds a new render pass. - /// - /// # Panic - /// - /// - Can panic if it detects some violations in the restrictions. Only inexpensive checks are - /// performed. `debug_assert!` is used, so some restrictions are only checked in debug - /// mode. - /// - pub fn new( - device: Arc<Device>, - description: RenderPassDesc, - ) -> Result<RenderPass, RenderPassCreationError> { - let fns = device.fns(); - - // If the first use of an attachment in this render pass is as an input attachment, and - // the attachment is not also used as a color or depth/stencil attachment in the same - // subpass, then loadOp must not be VK_ATTACHMENT_LOAD_OP_CLEAR - debug_assert!(description.attachments().into_iter().enumerate().all( - |(atch_num, attachment)| { - if attachment.load != LoadOp::Clear { - return true; - } - - for p in description.subpasses() { - if p.color_attachments - .iter() - .find(|&&(a, _)| a == atch_num) - .is_some() - { - return true; - } - if let Some((a, _)) = p.depth_stencil { - if a == atch_num { - return true; - } - } - if p.input_attachments - .iter() - .find(|&&(a, _)| a == atch_num) - .is_some() - { - return false; - } - } - - true - } - )); - - let attachments = description - .attachments() - .iter() - .map(|attachment| { - ash::vk::AttachmentDescription { - flags: ash::vk::AttachmentDescriptionFlags::empty(), // FIXME: may alias flag - format: attachment.format.into(), - samples: attachment.samples.into(), - load_op: attachment.load.into(), - store_op: attachment.store.into(), - stencil_load_op: attachment.stencil_load.into(), - stencil_store_op: attachment.stencil_store.into(), - initial_layout: attachment.initial_layout.into(), - final_layout: attachment.final_layout.into(), - } - }) - .collect::<SmallVec<[_; 16]>>(); - - // We need to pass pointers to vkAttachmentReference structs when creating the render pass. - // Therefore we need to allocate them in advance. - // - // This block allocates, for each pass, in order, all color attachment references, then all - // input attachment references, then all resolve attachment references, then the depth - // stencil attachment reference. - let attachment_references = description - .subpasses() - .iter() - .flat_map(|pass| { - // Performing some validation with debug asserts. - debug_assert!( - pass.resolve_attachments.is_empty() - || pass.resolve_attachments.len() == pass.color_attachments.len() - ); - debug_assert!(pass - .resolve_attachments - .iter() - .all(|a| attachments[a.0].samples == ash::vk::SampleCountFlags::TYPE_1)); - debug_assert!( - pass.resolve_attachments.is_empty() - || pass - .color_attachments - .iter() - .all(|a| attachments[a.0].samples.as_raw() > 1) - ); - debug_assert!( - pass.resolve_attachments.is_empty() - || pass - .resolve_attachments - .iter() - .zip(pass.color_attachments.iter()) - .all(|(r, c)| { attachments[r.0].format == attachments[c.0].format }) - ); - debug_assert!(pass - .color_attachments - .iter() - .cloned() - .chain(pass.depth_stencil.clone().into_iter()) - .chain(pass.input_attachments.iter().cloned()) - .chain(pass.resolve_attachments.iter().cloned()) - .all(|(a, _)| { - pass.preserve_attachments - .iter() - .find(|&&b| a == b) - .is_none() - })); - debug_assert!(pass - .color_attachments - .iter() - .cloned() - .chain(pass.depth_stencil.clone().into_iter()) - .all(|(atch, layout)| { - if let Some(r) = pass.input_attachments.iter().find(|r| r.0 == atch) { - r.1 == layout - } else { - true - } - })); - - let resolve = pass.resolve_attachments.iter().map(|&(offset, img_la)| { - debug_assert!(offset < attachments.len()); - ash::vk::AttachmentReference { - attachment: offset as u32, - layout: img_la.into(), - } - }); - - let color = pass.color_attachments.iter().map(|&(offset, img_la)| { - debug_assert!(offset < attachments.len()); - ash::vk::AttachmentReference { - attachment: offset as u32, - layout: img_la.into(), - } - }); - - let input = pass.input_attachments.iter().map(|&(offset, img_la)| { - debug_assert!(offset < attachments.len()); - ash::vk::AttachmentReference { - attachment: offset as u32, - layout: img_la.into(), - } - }); - - let depthstencil = if let Some((offset, img_la)) = pass.depth_stencil { - Some(ash::vk::AttachmentReference { - attachment: offset as u32, - layout: img_la.into(), - }) - } else { - None - } - .into_iter(); - - color.chain(input).chain(resolve).chain(depthstencil) - }) - .collect::<SmallVec<[_; 16]>>(); - - // Same as `attachment_references` but only for the preserve attachments. - // This is separate because attachment references are u32s and not `vkAttachmentReference` - // structs. - let preserve_attachments_references = description - .subpasses() - .iter() - .flat_map(|pass| { - pass.preserve_attachments - .iter() - .map(|&offset| offset as u32) - }) - .collect::<SmallVec<[_; 16]>>(); - - // Now iterating over passes. - let passes = unsafe { - // `ref_index` and `preserve_ref_index` are increased during the loop and point to the - // next element to use in respectively `attachment_references` and - // `preserve_attachments_references`. - let mut ref_index = 0usize; - let mut preserve_ref_index = 0usize; - let mut out: SmallVec<[_; 16]> = SmallVec::new(); - - for pass in description.subpasses() { - if pass.color_attachments.len() as u32 - > device - .physical_device() - .properties() - .max_color_attachments - { - return Err(RenderPassCreationError::ColorAttachmentsLimitExceeded); - } - - let color_attachments = attachment_references.as_ptr().offset(ref_index as isize); - ref_index += pass.color_attachments.len(); - let input_attachments = attachment_references.as_ptr().offset(ref_index as isize); - ref_index += pass.input_attachments.len(); - let resolve_attachments = attachment_references.as_ptr().offset(ref_index as isize); - ref_index += pass.resolve_attachments.len(); - let depth_stencil = if pass.depth_stencil.is_some() { - let a = attachment_references.as_ptr().offset(ref_index as isize); - ref_index += 1; - a - } else { - ptr::null() - }; - - let preserve_attachments = preserve_attachments_references - .as_ptr() - .offset(preserve_ref_index as isize); - preserve_ref_index += pass.preserve_attachments.len(); - - out.push(ash::vk::SubpassDescription { - flags: ash::vk::SubpassDescriptionFlags::empty(), - pipeline_bind_point: ash::vk::PipelineBindPoint::GRAPHICS, - input_attachment_count: pass.input_attachments.len() as u32, - p_input_attachments: if pass.input_attachments.is_empty() { - ptr::null() - } else { - input_attachments - }, - color_attachment_count: pass.color_attachments.len() as u32, - p_color_attachments: if pass.color_attachments.is_empty() { - ptr::null() - } else { - color_attachments - }, - p_resolve_attachments: if pass.resolve_attachments.is_empty() { - ptr::null() - } else { - resolve_attachments - }, - p_depth_stencil_attachment: depth_stencil, - preserve_attachment_count: pass.preserve_attachments.len() as u32, - p_preserve_attachments: if pass.preserve_attachments.is_empty() { - ptr::null() - } else { - preserve_attachments - }, - }); - } - - assert!(!out.is_empty()); - // If these assertions fails, there's a serious bug in the code above ^. - debug_assert!(ref_index == attachment_references.len()); - debug_assert!(preserve_ref_index == preserve_attachments_references.len()); - - out - }; - - let dependencies = description - .dependencies() - .iter() - .map(|dependency| { - debug_assert!( - dependency.source_subpass as u32 == ash::vk::SUBPASS_EXTERNAL - || dependency.source_subpass < passes.len() - ); - debug_assert!( - dependency.destination_subpass as u32 == ash::vk::SUBPASS_EXTERNAL - || dependency.destination_subpass < passes.len() - ); - - ash::vk::SubpassDependency { - src_subpass: dependency.source_subpass as u32, - dst_subpass: dependency.destination_subpass as u32, - src_stage_mask: dependency.source_stages.into(), - dst_stage_mask: dependency.destination_stages.into(), - src_access_mask: dependency.source_access.into(), - dst_access_mask: dependency.destination_access.into(), - dependency_flags: if dependency.by_region { - ash::vk::DependencyFlags::BY_REGION - } else { - ash::vk::DependencyFlags::empty() - }, - } - }) - .collect::<SmallVec<[_; 16]>>(); - - let multiview_create_info = match description.multiview() { - Some(multiview) => { - debug_assert!(device.enabled_features().multiview); - debug_assert!( - device - .physical_device() - .properties() - .max_multiview_view_count - .unwrap_or(0) - >= multiview.used_layer_count() - ); - - // each subpass must have a corresponding view mask - // or there are no view masks at all (which is probably a bug because - // nothing will get drawn) - debug_assert!( - multiview.view_masks.len() == passes.len() || multiview.view_masks.is_empty() - ); - - // either all subpasses must have a non-zero view mask or all must be zero - // (multiview is considered to be disabled when all view masks are zero) - debug_assert!( - multiview.view_masks.iter().all(|&mask| mask != 0) - || multiview.view_masks.iter().all(|&mask| mask == 0) - ); - - // one view offset for each dependency - // or no view offsets at all - debug_assert!( - dependencies.len() == multiview.view_offsets.len() - || multiview.view_offsets.is_empty() - ); - - // VUID-VkRenderPassCreateInfo-pNext-02512 - debug_assert!(dependencies.iter().zip(&multiview.view_offsets).all( - |(dependency, &view_offset)| dependency - .dependency_flags - .contains(ash::vk::DependencyFlags::VIEW_LOCAL) - || view_offset == 0 - )); - - // VUID-VkRenderPassCreateInfo-pNext-02514 - debug_assert!( - multiview.view_masks.iter().any(|&view_mask| view_mask != 0) - || dependencies.iter().all(|dependency| !dependency - .dependency_flags - .contains(ash::vk::DependencyFlags::VIEW_LOCAL)) - ); - - // VUID-VkRenderPassCreateInfo-pNext-02515 - debug_assert!( - multiview.view_masks.iter().any(|&view_mask| view_mask != 0) - || multiview.correlation_masks.is_empty() - ); - - // VUID-VkRenderPassMultiviewCreateInfo-pCorrelationMasks-00841 - // ensure that each view index is contained in at most one correlation mask - // by checking for any overlap in all pairs of correlation masks - debug_assert!(multiview - .correlation_masks - .iter() - .enumerate() - .all(|(i, &mask)| multiview.correlation_masks[i + 1..] - .iter() - .all(|&other_mask| other_mask & mask == 0))); - - ash::vk::RenderPassMultiviewCreateInfo { - subpass_count: passes.len() as u32, - p_view_masks: multiview.view_masks.as_ptr(), - dependency_count: dependencies.len() as u32, - p_view_offsets: multiview.view_offsets.as_ptr(), - correlation_mask_count: multiview.correlation_masks.len() as u32, - p_correlation_masks: multiview.correlation_masks.as_ptr(), - ..Default::default() - } - } - None => ash::vk::RenderPassMultiviewCreateInfo::default(), - }; - - let render_pass = unsafe { - let infos = ash::vk::RenderPassCreateInfo { - p_next: if description.multiview().is_none() { - ptr::null() - } else { - &multiview_create_info as *const _ as _ - }, - flags: ash::vk::RenderPassCreateFlags::empty(), - attachment_count: attachments.len() as u32, - p_attachments: if attachments.is_empty() { - ptr::null() - } else { - attachments.as_ptr() - }, - subpass_count: passes.len() as u32, - p_subpasses: if passes.is_empty() { - ptr::null() - } else { - passes.as_ptr() - }, - dependency_count: dependencies.len() as u32, - p_dependencies: if dependencies.is_empty() { - ptr::null() - } else { - dependencies.as_ptr() - }, - ..Default::default() - }; - - let mut output = MaybeUninit::uninit(); - check_errors(fns.v1_0.create_render_pass( - device.internal_object(), - &infos, - ptr::null(), - output.as_mut_ptr(), - ))?; - output.assume_init() - }; - - Ok(RenderPass { - device: device.clone(), - render_pass, - desc: description, - granularity: Mutex::new(None), - }) - } - - /// Builds a render pass with one subpass and no attachment. - /// - /// This method is useful for quick tests. - #[inline] - pub fn empty_single_pass(device: Arc<Device>) -> Result<RenderPass, RenderPassCreationError> { - RenderPass::new(device, RenderPassDesc::empty()) - } - - #[inline] - pub fn inner(&self) -> RenderPassSys { - RenderPassSys(self.render_pass, PhantomData) - } - - /// Returns the granularity of this render pass. - /// - /// If the render area of a render pass in a command buffer is a multiple of this granularity, - /// then the performance will be optimal. Performances are always optimal for render areas - /// that cover the whole framebuffer. - pub fn granularity(&self) -> [u32; 2] { - let mut granularity = self.granularity.lock().unwrap(); - - if let Some(&granularity) = granularity.as_ref() { - return granularity; - } - - unsafe { - let fns = self.device.fns(); - let mut out = MaybeUninit::uninit(); - fns.v1_0.get_render_area_granularity( - self.device.internal_object(), - self.render_pass, - out.as_mut_ptr(), - ); - - let out = out.assume_init(); - debug_assert_ne!(out.width, 0); - debug_assert_ne!(out.height, 0); - let gran = [out.width, out.height]; - *granularity = Some(gran); - gran - } - } - - /// Returns the description of the render pass. - #[inline] - pub fn desc(&self) -> &RenderPassDesc { - &self.desc - } -} - -unsafe impl DeviceOwned for RenderPass { - #[inline] - fn device(&self) -> &Arc<Device> { - &self.device - } -} - -impl fmt::Debug for RenderPass { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - fmt.debug_struct("RenderPass") - .field("raw", &self.render_pass) - .field("device", &self.device) - .field("desc", &self.desc) - .finish() - } -} - -impl Drop for RenderPass { - #[inline] - fn drop(&mut self) { - unsafe { - let fns = self.device.fns(); - fns.v1_0.destroy_render_pass( - self.device.internal_object(), - self.render_pass, - ptr::null(), - ); - } - } -} - -/// Opaque object that represents the render pass' internals. -#[derive(Debug, Copy, Clone)] -pub struct RenderPassSys<'a>(ash::vk::RenderPass, PhantomData<&'a ()>); - -unsafe impl<'a> VulkanObject for RenderPassSys<'a> { - type Object = ash::vk::RenderPass; - - #[inline] - fn internal_object(&self) -> ash::vk::RenderPass { - self.0 - } -} - -/// Error that can happen when creating a compute pipeline. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum RenderPassCreationError { - /// Not enough memory. - OomError(OomError), - /// The maximum number of color attachments has been exceeded. - ColorAttachmentsLimitExceeded, -} - -impl error::Error for RenderPassCreationError { - #[inline] - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match *self { - RenderPassCreationError::OomError(ref err) => Some(err), - _ => None, - } - } -} - -impl fmt::Display for RenderPassCreationError { - #[inline] - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!( - fmt, - "{}", - match *self { - RenderPassCreationError::OomError(_) => "not enough memory available", - RenderPassCreationError::ColorAttachmentsLimitExceeded => { - "the maximum number of color attachments has been exceeded" - } - } - ) - } -} - -impl From<OomError> for RenderPassCreationError { - #[inline] - fn from(err: OomError) -> RenderPassCreationError { - RenderPassCreationError::OomError(err) - } -} - -impl From<Error> for RenderPassCreationError { - #[inline] - fn from(err: Error) -> RenderPassCreationError { - match err { - err @ Error::OutOfHostMemory => RenderPassCreationError::OomError(OomError::from(err)), - err @ Error::OutOfDeviceMemory => { - RenderPassCreationError::OomError(OomError::from(err)) - } - _ => panic!("unexpected error: {:?}", err), - } - } -} - -/// Represents a subpass within a `RenderPass` object. -/// -/// This struct doesn't correspond to anything in Vulkan. It is simply an equivalent to a -/// tuple of a render pass and subpass index. Contrary to a tuple, however, the existence of the -/// subpass is checked when the object is created. When you have a `Subpass` you are guaranteed -/// that the given subpass does exist. -#[derive(Debug, Clone)] -pub struct Subpass { - render_pass: Arc<RenderPass>, - subpass_id: u32, -} - -impl Subpass { - /// Returns a handle that represents a subpass of a render pass. - #[inline] - pub fn from(render_pass: Arc<RenderPass>, id: u32) -> Option<Subpass> { - if (id as usize) < render_pass.desc().subpasses().len() { - Some(Subpass { - render_pass, - subpass_id: id, - }) - } else { - None - } - } - - #[inline] - fn subpass_desc(&self) -> &SubpassDesc { - &self.render_pass.desc().subpasses()[self.subpass_id as usize] - } - - #[inline] - fn attachment_desc(&self, atch_num: usize) -> &AttachmentDesc { - &self.render_pass.desc().attachments()[atch_num] - } - - /// Returns the number of color attachments in this subpass. - #[inline] - pub fn num_color_attachments(&self) -> u32 { - self.subpass_desc().color_attachments.len() as u32 - } - - /// Returns true if the subpass has a depth attachment or a depth-stencil attachment. - #[inline] - pub fn has_depth(&self) -> bool { - let subpass_desc = self.subpass_desc(); - let atch_num = match subpass_desc.depth_stencil { - Some((d, _)) => d, - None => return false, - }; - - match self.attachment_desc(atch_num).format.ty() { - FormatTy::Depth => true, - FormatTy::Stencil => false, - FormatTy::DepthStencil => true, - _ => unreachable!(), - } - } - - /// Returns true if the subpass has a depth attachment or a depth-stencil attachment whose - /// layout is not `DepthStencilReadOnlyOptimal`. - #[inline] - pub fn has_writable_depth(&self) -> bool { - let subpass_desc = self.subpass_desc(); - let atch_num = match subpass_desc.depth_stencil { - Some((d, l)) => { - if l == ImageLayout::DepthStencilReadOnlyOptimal { - return false; - } - d - } - None => return false, - }; - - match self.attachment_desc(atch_num).format.ty() { - FormatTy::Depth => true, - FormatTy::Stencil => false, - FormatTy::DepthStencil => true, - _ => unreachable!(), - } - } - - /// Returns true if the subpass has a stencil attachment or a depth-stencil attachment. - #[inline] - pub fn has_stencil(&self) -> bool { - let subpass_desc = self.subpass_desc(); - let atch_num = match subpass_desc.depth_stencil { - Some((d, _)) => d, - None => return false, - }; - - match self.attachment_desc(atch_num).format.ty() { - FormatTy::Depth => false, - FormatTy::Stencil => true, - FormatTy::DepthStencil => true, - _ => unreachable!(), - } - } - - /// Returns true if the subpass has a stencil attachment or a depth-stencil attachment whose - /// layout is not `DepthStencilReadOnlyOptimal`. - #[inline] - pub fn has_writable_stencil(&self) -> bool { - let subpass_desc = self.subpass_desc(); - - let atch_num = match subpass_desc.depth_stencil { - Some((d, l)) => { - if l == ImageLayout::DepthStencilReadOnlyOptimal { - return false; - } - d - } - None => return false, - }; - - match self.attachment_desc(atch_num).format.ty() { - FormatTy::Depth => false, - FormatTy::Stencil => true, - FormatTy::DepthStencil => true, - _ => unreachable!(), - } - } - - /// Returns true if the subpass has any color or depth/stencil attachment. - #[inline] - pub fn has_color_or_depth_stencil_attachment(&self) -> bool { - if self.num_color_attachments() >= 1 { - return true; - } - - let subpass_desc = self.subpass_desc(); - match subpass_desc.depth_stencil { - Some((d, _)) => true, - None => false, - } - } - - /// Returns the number of samples in the color and/or depth/stencil attachments. Returns `None` - /// if there is no such attachment in this subpass. - #[inline] - pub fn num_samples(&self) -> Option<SampleCount> { - let subpass_desc = self.subpass_desc(); - - // TODO: chain input attachments as well? - subpass_desc - .color_attachments - .iter() - .cloned() - .chain(subpass_desc.depth_stencil.clone().into_iter()) - .filter_map(|a| self.render_pass.desc().attachments().get(a.0)) - .next() - .map(|a| a.samples) - } - - /// Returns the render pass of this subpass. - #[inline] - pub fn render_pass(&self) -> &Arc<RenderPass> { - &self.render_pass - } - - /// Returns the index of this subpass within the renderpass. - #[inline] - pub fn index(&self) -> u32 { - self.subpass_id - } - - /// Returns `true` if this subpass is compatible with the fragment output definition. - // TODO: return proper error - pub fn is_compatible_with(&self, shader_interface: &ShaderInterface) -> bool { - self.render_pass - .desc() - .is_compatible_with_shader(self.subpass_id, shader_interface) - } -} - -impl From<Subpass> for (Arc<RenderPass>, u32) { - #[inline] - fn from(value: Subpass) -> (Arc<RenderPass>, u32) { - (value.render_pass, value.subpass_id) - } -} - -#[cfg(test)] -mod tests { - use crate::format::Format; - use crate::render_pass::RenderPass; - use crate::render_pass::RenderPassCreationError; - - #[test] - fn empty() { - let (device, _) = gfx_dev_and_queue!(); - let _ = RenderPass::empty_single_pass(device).unwrap(); - } - - #[test] - fn too_many_color_atch() { - let (device, _) = gfx_dev_and_queue!(); - - if device - .physical_device() - .properties() - .max_color_attachments - >= 10 - { - return; // test ignored - } - - let rp = single_pass_renderpass! { - device.clone(), - attachments: { - a1: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, }, - a2: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, }, - a3: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, }, - a4: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, }, - a5: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, }, - a6: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, }, - a7: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, }, - a8: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, }, - a9: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, }, - a10: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, } - }, - pass: { - color: [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10], - depth_stencil: {} - } - }; - - match rp { - Err(RenderPassCreationError::ColorAttachmentsLimitExceeded) => (), - _ => panic!(), - } - } - - #[test] - fn non_zero_granularity() { - let (device, _) = gfx_dev_and_queue!(); - - let rp = single_pass_renderpass! { - device.clone(), - attachments: { - a: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, } - }, - pass: { - color: [a], - depth_stencil: {} - } - } - .unwrap(); - - let granularity = rp.granularity(); - assert_ne!(granularity[0], 0); - assert_ne!(granularity[1], 0); - } -} |