aboutsummaryrefslogtreecommitdiff
path: root/src/render_pass/render_pass.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/render_pass/render_pass.rs')
-rw-r--r--src/render_pass/render_pass.rs911
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);
- }
-}