1 // Copyright (c) 2016 The vulkano developers 2 // Licensed under the Apache License, Version 2.0 3 // <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, 6 // at your option. All files in the project carrying such 7 // notice may not be copied, modified, or distributed except 8 // according to those terms. 9 10 //! Description of the steps of the rendering process, and the images used as input or output. 11 //! 12 //! # Render passes and framebuffers 13 //! 14 //! There are two concepts in Vulkan: 15 //! 16 //! - A *render pass* describes the overall process of drawing a frame. It is subdivided into one 17 //! or more subpasses. 18 //! - A *framebuffer* contains the list of image views that are attached during the drawing of 19 //! each subpass. 20 //! 21 //! Render passes are typically created at initialization only (for example during a loading 22 //! screen) because they can be costly, while framebuffers can be created and destroyed either at 23 //! initialization or during the frame. 24 //! 25 //! Consequently you can create graphics pipelines from a render pass object alone. 26 //! A `Framebuffer` object is only needed when you actually add draw commands to a command buffer. 27 28 pub use self::{ 29 create::RenderPassCreationError, 30 framebuffer::{Framebuffer, FramebufferCreateInfo, FramebufferCreationError}, 31 }; 32 use crate::{ 33 device::{Device, DeviceOwned}, 34 format::Format, 35 image::{ImageAspects, ImageLayout, SampleCount}, 36 macros::{impl_id_counter, vulkan_bitflags_enum, vulkan_enum}, 37 shader::ShaderInterface, 38 sync::{AccessFlags, DependencyFlags, PipelineStages}, 39 Version, VulkanObject, 40 }; 41 use std::{cmp::max, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc}; 42 43 #[macro_use] 44 mod macros; 45 mod create; 46 mod framebuffer; 47 48 /// An object representing the discrete steps in which rendering is done. 49 /// 50 /// A render pass in Vulkan is made up of three parts: 51 /// - A list of attachments, which are image views that are inputs, outputs or intermediate stages 52 /// in the rendering process. 53 /// - One or more subpasses, which are the steps in which the rendering process, takes place, 54 /// and the attachments that are used for each step. 55 /// - Dependencies, which describe how the input and output data of each subpass is to be passed 56 /// from one subpass to the next. 57 /// 58 /// ``` 59 /// use vulkano::render_pass::{RenderPass, RenderPassCreateInfo, SubpassDescription}; 60 /// 61 /// # let device: std::sync::Arc<vulkano::device::Device> = return; 62 /// let render_pass = RenderPass::new( 63 /// device.clone(), 64 /// RenderPassCreateInfo { 65 /// subpasses: vec![SubpassDescription::default()], 66 /// ..Default::default() 67 /// }, 68 /// ).unwrap(); 69 /// ``` 70 /// 71 /// This example creates a render pass with no attachment and one single subpass that doesn't draw 72 /// on anything. While it's sometimes useful, most of the time it's not what you want. 73 /// 74 /// The easiest way to create a "real" render pass is to use the `single_pass_renderpass!` macro. 75 /// 76 /// ``` 77 /// # #[macro_use] extern crate vulkano; 78 /// # fn main() { 79 /// # let device: std::sync::Arc<vulkano::device::Device> = return; 80 /// use vulkano::format::Format; 81 /// 82 /// let render_pass = single_pass_renderpass!( 83 /// device.clone(), 84 /// attachments: { 85 /// // `foo` is a custom name we give to the first and only attachment. 86 /// foo: { 87 /// load: Clear, 88 /// store: Store, 89 /// format: Format::R8G8B8A8_UNORM, 90 /// samples: 1, 91 /// }, 92 /// }, 93 /// pass: { 94 /// color: [foo], // Repeat the attachment name here. 95 /// depth_stencil: {}, 96 /// }, 97 /// ) 98 /// .unwrap(); 99 /// # } 100 /// ``` 101 /// 102 /// See the documentation of the macro for more details. TODO: put link here 103 #[derive(Debug)] 104 pub struct RenderPass { 105 handle: ash::vk::RenderPass, 106 device: Arc<Device>, 107 id: NonZeroU64, 108 109 attachments: Vec<AttachmentDescription>, 110 subpasses: Vec<SubpassDescription>, 111 dependencies: Vec<SubpassDependency>, 112 correlated_view_masks: Vec<u32>, 113 114 attachment_uses: Vec<Option<AttachmentUse>>, 115 granularity: [u32; 2], 116 views_used: u32, 117 } 118 119 impl RenderPass { 120 /// Creates a new `RenderPass`. 121 /// 122 /// # Panics 123 /// 124 /// - Panics if `create_info.subpasses` is empty. 125 /// - Panics if any element of `create_info.attachments` has a `format` of `None`. new( device: Arc<Device>, mut create_info: RenderPassCreateInfo, ) -> Result<Arc<RenderPass>, RenderPassCreationError>126 pub fn new( 127 device: Arc<Device>, 128 mut create_info: RenderPassCreateInfo, 129 ) -> Result<Arc<RenderPass>, RenderPassCreationError> { 130 Self::validate(&device, &mut create_info)?; 131 132 let handle = unsafe { 133 if device.api_version() >= Version::V1_2 134 || device.enabled_extensions().khr_create_renderpass2 135 { 136 Self::create_v2(&device, &create_info)? 137 } else { 138 Self::create_v1(&device, &create_info)? 139 } 140 }; 141 142 unsafe { Ok(Self::from_handle(device, handle, create_info)) } 143 } 144 145 /// Builds a render pass with one subpass and no attachment. 146 /// 147 /// This method is useful for quick tests. 148 #[inline] empty_single_pass( device: Arc<Device>, ) -> Result<Arc<RenderPass>, RenderPassCreationError>149 pub fn empty_single_pass( 150 device: Arc<Device>, 151 ) -> Result<Arc<RenderPass>, RenderPassCreationError> { 152 RenderPass::new( 153 device, 154 RenderPassCreateInfo { 155 subpasses: vec![SubpassDescription::default()], 156 ..Default::default() 157 }, 158 ) 159 } 160 161 /// Creates a new `RenderPass` from a raw object handle. 162 /// 163 /// # Safety 164 /// 165 /// - `handle` must be a valid Vulkan object handle created from `device`. 166 /// - `create_info` must match the info used to create the object. 167 #[inline] from_handle( device: Arc<Device>, handle: ash::vk::RenderPass, create_info: RenderPassCreateInfo, ) -> Arc<RenderPass>168 pub unsafe fn from_handle( 169 device: Arc<Device>, 170 handle: ash::vk::RenderPass, 171 create_info: RenderPassCreateInfo, 172 ) -> Arc<RenderPass> { 173 let RenderPassCreateInfo { 174 attachments, 175 subpasses, 176 dependencies, 177 correlated_view_masks, 178 _ne: _, 179 } = create_info; 180 181 let granularity = Self::get_granularity(&device, handle); 182 let mut attachment_uses: Vec<Option<AttachmentUse>> = vec![None; attachments.len()]; 183 let mut views_used = 0; 184 185 for (index, subpass_desc) in subpasses.iter().enumerate() { 186 let index = index as u32; 187 let &SubpassDescription { 188 view_mask, 189 ref input_attachments, 190 ref color_attachments, 191 ref resolve_attachments, 192 ref depth_stencil_attachment, 193 .. 194 } = subpass_desc; 195 196 for atch_ref in (input_attachments.iter().flatten()) 197 .chain(color_attachments.iter().flatten()) 198 .chain(resolve_attachments.iter().flatten()) 199 .chain(depth_stencil_attachment.iter()) 200 { 201 match &mut attachment_uses[atch_ref.attachment as usize] { 202 Some(attachment_use) => attachment_use.last_use_subpass = index, 203 attachment_use @ None => { 204 *attachment_use = Some(AttachmentUse { 205 first_use_subpass: index, 206 last_use_subpass: index, 207 }) 208 } 209 } 210 } 211 212 views_used = max(views_used, u32::BITS - view_mask.leading_zeros()); 213 } 214 215 Arc::new(RenderPass { 216 handle, 217 device, 218 id: Self::next_id(), 219 220 attachments, 221 subpasses, 222 dependencies, 223 correlated_view_masks, 224 225 attachment_uses, 226 granularity, 227 views_used, 228 }) 229 } 230 get_granularity(device: &Arc<Device>, handle: ash::vk::RenderPass) -> [u32; 2]231 unsafe fn get_granularity(device: &Arc<Device>, handle: ash::vk::RenderPass) -> [u32; 2] { 232 let fns = device.fns(); 233 let mut out = MaybeUninit::uninit(); 234 (fns.v1_0.get_render_area_granularity)(device.handle(), handle, out.as_mut_ptr()); 235 236 let out = out.assume_init(); 237 debug_assert_ne!(out.width, 0); 238 debug_assert_ne!(out.height, 0); 239 [out.width, out.height] 240 } 241 242 /// Returns the attachments of the render pass. 243 #[inline] attachments(&self) -> &[AttachmentDescription]244 pub fn attachments(&self) -> &[AttachmentDescription] { 245 &self.attachments 246 } 247 248 /// Returns the subpasses of the render pass. 249 #[inline] subpasses(&self) -> &[SubpassDescription]250 pub fn subpasses(&self) -> &[SubpassDescription] { 251 &self.subpasses 252 } 253 254 /// Returns the dependencies of the render pass. 255 #[inline] dependencies(&self) -> &[SubpassDependency]256 pub fn dependencies(&self) -> &[SubpassDependency] { 257 &self.dependencies 258 } 259 260 /// Returns the correlated view masks of the render pass. 261 #[inline] correlated_view_masks(&self) -> &[u32]262 pub fn correlated_view_masks(&self) -> &[u32] { 263 &self.correlated_view_masks 264 } 265 266 /// If the render pass has multiview enabled, returns the number of views used by the render 267 /// pass. Returns 0 if multiview is not enabled. 268 #[inline] views_used(&self) -> u32269 pub fn views_used(&self) -> u32 { 270 self.views_used 271 } 272 273 /// Returns the granularity of this render pass. 274 /// 275 /// If the render area of a render pass in a command buffer is a multiple of this granularity, 276 /// then the performance will be optimal. Performances are always optimal for render areas 277 /// that cover the whole framebuffer. 278 #[inline] granularity(&self) -> [u32; 2]279 pub fn granularity(&self) -> [u32; 2] { 280 self.granularity 281 } 282 283 /// Returns the first subpass of the render pass. 284 #[inline] first_subpass(self: Arc<Self>) -> Subpass285 pub fn first_subpass(self: Arc<Self>) -> Subpass { 286 Subpass { 287 render_pass: self, 288 subpass_id: 0, // Guaranteed to exist 289 } 290 } 291 292 /// Returns `true` if this render pass is compatible with the other render pass, 293 /// as defined in the [`Render Pass Compatibility` section of the Vulkan specs](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap8.html#renderpass-compatibility). is_compatible_with(&self, other: &RenderPass) -> bool294 pub fn is_compatible_with(&self, other: &RenderPass) -> bool { 295 if self == other { 296 return true; 297 } 298 299 let Self { 300 handle: _, 301 device: _, 302 id: _, 303 attachments: attachments1, 304 subpasses: subpasses1, 305 dependencies: dependencies1, 306 correlated_view_masks: correlated_view_masks1, 307 attachment_uses: _, 308 granularity: _, 309 views_used: _, 310 } = self; 311 let Self { 312 handle: _, 313 device: _, 314 id: _, 315 attachments: attachments2, 316 subpasses: subpasses2, 317 dependencies: dependencies2, 318 attachment_uses: _, 319 correlated_view_masks: correlated_view_masks2, 320 granularity: _, 321 views_used: _, 322 } = other; 323 324 if attachments1.len() != attachments2.len() { 325 return false; 326 } 327 328 if !attachments1 329 .iter() 330 .zip(attachments2) 331 .all(|(attachment_desc1, attachment_desc2)| { 332 let AttachmentDescription { 333 format: format1, 334 samples: samples1, 335 load_op: _, 336 store_op: _, 337 stencil_load_op: _, 338 stencil_store_op: _, 339 initial_layout: _, 340 final_layout: _, 341 _ne: _, 342 } = attachment_desc1; 343 let AttachmentDescription { 344 format: format2, 345 samples: samples2, 346 load_op: _, 347 store_op: _, 348 stencil_load_op: _, 349 stencil_store_op: _, 350 initial_layout: _, 351 final_layout: _, 352 _ne: _, 353 } = attachment_desc2; 354 355 format1 == format2 && samples1 == samples2 356 }) 357 { 358 return false; 359 } 360 361 let are_atch_refs_compatible = |atch_ref1, atch_ref2| match (atch_ref1, atch_ref2) { 362 (None, None) => true, 363 (Some(atch_ref1), Some(atch_ref2)) => { 364 let &AttachmentReference { 365 attachment: attachment1, 366 layout: _, 367 aspects: aspects1, 368 _ne: _, 369 } = atch_ref1; 370 let AttachmentDescription { 371 format: format1, 372 samples: samples1, 373 load_op: _, 374 store_op: _, 375 stencil_load_op: _, 376 stencil_store_op: _, 377 initial_layout: _, 378 final_layout: _, 379 _ne: _, 380 } = &attachments1[attachment1 as usize]; 381 382 let &AttachmentReference { 383 attachment: attachment2, 384 layout: _, 385 aspects: aspects2, 386 _ne: _, 387 } = atch_ref2; 388 let AttachmentDescription { 389 format: format2, 390 samples: samples2, 391 load_op: _, 392 store_op: _, 393 stencil_load_op: _, 394 stencil_store_op: _, 395 initial_layout: _, 396 final_layout: _, 397 _ne: _, 398 } = &attachments2[attachment2 as usize]; 399 400 format1 == format2 && samples1 == samples2 && aspects1 == aspects2 401 } 402 _ => false, 403 }; 404 405 if subpasses1.len() != subpasses2.len() { 406 return false; 407 } 408 409 if !(subpasses1.iter()) 410 .zip(subpasses2.iter()) 411 .all(|(subpass1, subpass2)| { 412 let SubpassDescription { 413 view_mask: view_mask1, 414 input_attachments: input_attachments1, 415 color_attachments: color_attachments1, 416 resolve_attachments: resolve_attachments1, 417 depth_stencil_attachment: depth_stencil_attachment1, 418 preserve_attachments: _, 419 _ne: _, 420 } = subpass1; 421 let SubpassDescription { 422 view_mask: view_mask2, 423 input_attachments: input_attachments2, 424 color_attachments: color_attachments2, 425 resolve_attachments: resolve_attachments2, 426 depth_stencil_attachment: depth_stencil_attachment2, 427 preserve_attachments: _, 428 _ne: _, 429 } = subpass2; 430 431 if !(0..max(input_attachments1.len(), input_attachments2.len())).all(|i| { 432 are_atch_refs_compatible( 433 input_attachments1.get(i).and_then(|x| x.as_ref()), 434 input_attachments2.get(i).and_then(|x| x.as_ref()), 435 ) 436 }) { 437 return false; 438 } 439 440 if !(0..max(color_attachments1.len(), color_attachments2.len())).all(|i| { 441 are_atch_refs_compatible( 442 color_attachments1.get(i).and_then(|x| x.as_ref()), 443 color_attachments2.get(i).and_then(|x| x.as_ref()), 444 ) 445 }) { 446 return false; 447 } 448 449 if subpasses1.len() > 1 450 && !(0..max(resolve_attachments1.len(), resolve_attachments2.len())).all(|i| { 451 are_atch_refs_compatible( 452 resolve_attachments1.get(i).and_then(|x| x.as_ref()), 453 resolve_attachments2.get(i).and_then(|x| x.as_ref()), 454 ) 455 }) 456 { 457 return false; 458 } 459 460 if !are_atch_refs_compatible( 461 depth_stencil_attachment1.as_ref(), 462 depth_stencil_attachment2.as_ref(), 463 ) { 464 return false; 465 } 466 467 if view_mask1 != view_mask2 { 468 return false; 469 } 470 471 true 472 }) 473 { 474 return false; 475 } 476 477 if dependencies1 != dependencies2 { 478 return false; 479 } 480 481 if correlated_view_masks1 != correlated_view_masks2 { 482 return false; 483 } 484 485 true 486 } 487 488 /// Returns `true` if the subpass of this description is compatible with the shader's fragment 489 /// output definition. is_compatible_with_shader( &self, subpass: u32, shader_interface: &ShaderInterface, ) -> bool490 pub fn is_compatible_with_shader( 491 &self, 492 subpass: u32, 493 shader_interface: &ShaderInterface, 494 ) -> bool { 495 let subpass_descr = match self.subpasses.get(subpass as usize) { 496 Some(s) => s, 497 None => return false, 498 }; 499 500 for element in shader_interface.elements() { 501 assert!(!element.ty.is_64bit); // TODO: implement 502 let location_range = element.location..element.location + element.ty.num_locations(); 503 504 for location in location_range { 505 let attachment_id = match subpass_descr.color_attachments.get(location as usize) { 506 Some(Some(atch_ref)) => atch_ref.attachment, 507 _ => return false, 508 }; 509 510 let _attachment_desc = &self.attachments[attachment_id as usize]; 511 512 // FIXME: compare formats depending on the number of components and data type 513 /*if attachment_desc.format != element.format { 514 return false; 515 }*/ 516 } 517 } 518 519 true 520 } 521 } 522 523 impl Drop for RenderPass { 524 #[inline] drop(&mut self)525 fn drop(&mut self) { 526 unsafe { 527 let fns = self.device.fns(); 528 (fns.v1_0.destroy_render_pass)(self.device.handle(), self.handle, ptr::null()); 529 } 530 } 531 } 532 533 unsafe impl VulkanObject for RenderPass { 534 type Handle = ash::vk::RenderPass; 535 536 #[inline] handle(&self) -> Self::Handle537 fn handle(&self) -> Self::Handle { 538 self.handle 539 } 540 } 541 542 unsafe impl DeviceOwned for RenderPass { 543 #[inline] device(&self) -> &Arc<Device>544 fn device(&self) -> &Arc<Device> { 545 &self.device 546 } 547 } 548 549 impl_id_counter!(RenderPass); 550 551 /// Represents a subpass within a `RenderPass` object. 552 /// 553 /// This struct doesn't correspond to anything in Vulkan. It is simply an equivalent to a 554 /// tuple of a render pass and subpass index. Contrary to a tuple, however, the existence of the 555 /// subpass is checked when the object is created. When you have a `Subpass` you are guaranteed 556 /// that the given subpass does exist. 557 #[derive(Debug, Clone)] 558 pub struct Subpass { 559 render_pass: Arc<RenderPass>, 560 subpass_id: u32, 561 } 562 563 impl Subpass { 564 /// Returns a handle that represents a subpass of a render pass. 565 #[inline] from(render_pass: Arc<RenderPass>, id: u32) -> Option<Subpass>566 pub fn from(render_pass: Arc<RenderPass>, id: u32) -> Option<Subpass> { 567 if (id as usize) < render_pass.subpasses().len() { 568 Some(Subpass { 569 render_pass, 570 subpass_id: id, 571 }) 572 } else { 573 None 574 } 575 } 576 577 /// Returns the render pass of this subpass. 578 #[inline] render_pass(&self) -> &Arc<RenderPass>579 pub fn render_pass(&self) -> &Arc<RenderPass> { 580 &self.render_pass 581 } 582 583 /// Returns the index of this subpass within the renderpass. 584 #[inline] index(&self) -> u32585 pub fn index(&self) -> u32 { 586 self.subpass_id 587 } 588 589 /// Returns the subpass description for this subpass. 590 #[inline] subpass_desc(&self) -> &SubpassDescription591 pub fn subpass_desc(&self) -> &SubpassDescription { 592 &self.render_pass.subpasses()[self.subpass_id as usize] 593 } 594 595 /// Returns whether this subpass is the last one in the render pass. If `true` is returned, 596 /// calling `next_subpass` will panic. 597 #[inline] is_last_subpass(&self) -> bool598 pub fn is_last_subpass(&self) -> bool { 599 self.subpass_id as usize == self.render_pass.subpasses().len() - 1 600 } 601 602 /// Advances to the next subpass after this one. 603 /// 604 /// # Panics 605 /// 606 /// - Panics if there are no more render passes. 607 #[inline] next_subpass(&mut self)608 pub fn next_subpass(&mut self) { 609 let next_id = self.subpass_id + 1; 610 assert!((next_id as usize) < self.render_pass.subpasses().len()); 611 self.subpass_id = next_id; 612 } 613 614 #[inline] attachment_desc(&self, atch_num: u32) -> &AttachmentDescription615 fn attachment_desc(&self, atch_num: u32) -> &AttachmentDescription { 616 &self.render_pass.attachments()[atch_num as usize] 617 } 618 619 /// Returns the number of color attachments in this subpass. 620 #[inline] num_color_attachments(&self) -> u32621 pub fn num_color_attachments(&self) -> u32 { 622 self.subpass_desc().color_attachments.len() as u32 623 } 624 625 /// Returns true if the subpass has a depth attachment or a depth-stencil attachment. 626 #[inline] has_depth(&self) -> bool627 pub fn has_depth(&self) -> bool { 628 let subpass_desc = self.subpass_desc(); 629 let atch_num = match &subpass_desc.depth_stencil_attachment { 630 Some(atch_ref) => atch_ref.attachment, 631 None => return false, 632 }; 633 634 self.attachment_desc(atch_num) 635 .format 636 .map_or(false, |f| f.aspects().intersects(ImageAspects::DEPTH)) 637 } 638 639 /// Returns true if the subpass has a depth attachment or a depth-stencil attachment whose 640 /// layout does not have a read-only depth layout. 641 #[inline] has_writable_depth(&self) -> bool642 pub fn has_writable_depth(&self) -> bool { 643 let subpass_desc = self.subpass_desc(); 644 let atch_num = match &subpass_desc.depth_stencil_attachment { 645 Some(atch_ref) => { 646 if matches!( 647 atch_ref.layout, 648 ImageLayout::DepthStencilReadOnlyOptimal 649 | ImageLayout::DepthReadOnlyStencilAttachmentOptimal 650 ) { 651 return false; 652 } 653 atch_ref.attachment 654 } 655 None => return false, 656 }; 657 658 self.attachment_desc(atch_num) 659 .format 660 .map_or(false, |f| f.aspects().intersects(ImageAspects::DEPTH)) 661 } 662 663 /// Returns true if the subpass has a stencil attachment or a depth-stencil attachment. 664 #[inline] has_stencil(&self) -> bool665 pub fn has_stencil(&self) -> bool { 666 let subpass_desc = self.subpass_desc(); 667 let atch_num = match &subpass_desc.depth_stencil_attachment { 668 Some(atch_ref) => atch_ref.attachment, 669 None => return false, 670 }; 671 672 self.attachment_desc(atch_num) 673 .format 674 .map_or(false, |f| f.aspects().intersects(ImageAspects::STENCIL)) 675 } 676 677 /// Returns true if the subpass has a stencil attachment or a depth-stencil attachment whose 678 /// layout does not have a read-only stencil layout. 679 #[inline] has_writable_stencil(&self) -> bool680 pub fn has_writable_stencil(&self) -> bool { 681 let subpass_desc = self.subpass_desc(); 682 683 let atch_num = match &subpass_desc.depth_stencil_attachment { 684 Some(atch_ref) => { 685 if matches!( 686 atch_ref.layout, 687 ImageLayout::DepthStencilReadOnlyOptimal 688 | ImageLayout::DepthAttachmentStencilReadOnlyOptimal 689 ) { 690 return false; 691 } 692 atch_ref.attachment 693 } 694 None => return false, 695 }; 696 697 self.attachment_desc(atch_num) 698 .format 699 .map_or(false, |f| f.aspects().intersects(ImageAspects::STENCIL)) 700 } 701 702 /// Returns the number of samples in the color and/or depth/stencil attachments. Returns `None` 703 /// if there is no such attachment in this subpass. 704 #[inline] num_samples(&self) -> Option<SampleCount>705 pub fn num_samples(&self) -> Option<SampleCount> { 706 let subpass_desc = self.subpass_desc(); 707 708 // TODO: chain input attachments as well? 709 subpass_desc 710 .color_attachments 711 .iter() 712 .flatten() 713 .chain(subpass_desc.depth_stencil_attachment.iter()) 714 .filter_map(|atch_ref| { 715 self.render_pass 716 .attachments() 717 .get(atch_ref.attachment as usize) 718 }) 719 .next() 720 .map(|atch_desc| atch_desc.samples) 721 } 722 723 /// Returns `true` if this subpass is compatible with the fragment output definition. 724 // TODO: return proper error 725 #[inline] is_compatible_with(&self, shader_interface: &ShaderInterface) -> bool726 pub fn is_compatible_with(&self, shader_interface: &ShaderInterface) -> bool { 727 self.render_pass 728 .is_compatible_with_shader(self.subpass_id, shader_interface) 729 } 730 load_op(&self, attachment_index: u32) -> Option<LoadOp>731 pub(crate) fn load_op(&self, attachment_index: u32) -> Option<LoadOp> { 732 self.render_pass.attachment_uses[attachment_index as usize] 733 .as_ref() 734 .and_then(|attachment_use| { 735 (attachment_use.first_use_subpass == self.subpass_id) 736 .then(|| self.render_pass.attachments[attachment_index as usize].load_op) 737 }) 738 } 739 store_op(&self, attachment_index: u32) -> Option<StoreOp>740 pub(crate) fn store_op(&self, attachment_index: u32) -> Option<StoreOp> { 741 self.render_pass.attachment_uses[attachment_index as usize] 742 .as_ref() 743 .and_then(|attachment_use| { 744 (attachment_use.last_use_subpass == self.subpass_id) 745 .then(|| self.render_pass.attachments[attachment_index as usize].store_op) 746 }) 747 } 748 stencil_load_op(&self, attachment_index: u32) -> Option<LoadOp>749 pub(crate) fn stencil_load_op(&self, attachment_index: u32) -> Option<LoadOp> { 750 self.render_pass.attachment_uses[attachment_index as usize] 751 .as_ref() 752 .and_then(|attachment_use| { 753 (attachment_use.first_use_subpass == self.subpass_id).then(|| { 754 self.render_pass.attachments[attachment_index as usize].stencil_load_op 755 }) 756 }) 757 } 758 stencil_store_op(&self, attachment_index: u32) -> Option<StoreOp>759 pub(crate) fn stencil_store_op(&self, attachment_index: u32) -> Option<StoreOp> { 760 self.render_pass.attachment_uses[attachment_index as usize] 761 .as_ref() 762 .and_then(|attachment_use| { 763 (attachment_use.last_use_subpass == self.subpass_id).then(|| { 764 self.render_pass.attachments[attachment_index as usize].stencil_store_op 765 }) 766 }) 767 } 768 } 769 770 impl From<Subpass> for (Arc<RenderPass>, u32) { 771 #[inline] from(value: Subpass) -> (Arc<RenderPass>, u32)772 fn from(value: Subpass) -> (Arc<RenderPass>, u32) { 773 (value.render_pass, value.subpass_id) 774 } 775 } 776 777 /// Parameters to create a new `RenderPass`. 778 #[derive(Clone, Debug)] 779 pub struct RenderPassCreateInfo { 780 /// The attachments available for the render pass. 781 /// 782 /// The default value is empty. 783 pub attachments: Vec<AttachmentDescription>, 784 785 /// The subpasses that make up this render pass. 786 /// 787 /// A render pass must contain at least one subpass. 788 /// 789 /// The default value is empty, which must be overridden. 790 pub subpasses: Vec<SubpassDescription>, 791 792 /// The dependencies between subpasses. 793 /// 794 /// The default value is empty. 795 pub dependencies: Vec<SubpassDependency>, 796 797 /// If multiview rendering is being used (the subpasses have a nonzero `view_mask`), 798 /// this specifies sets of views that may be more efficient to render concurrently, for example 799 /// because they show the same geometry from almost the same perspective. This is an 800 /// optimization hint to the implementation, and does not affect the final result. 801 /// 802 /// The value is a bitmask, so that that for example `0b11` means that the first two views are 803 /// highly correlated, and `0b101` means the first and third view are highly correlated. Each 804 /// view bit must appear in at most one element of the list. 805 /// 806 /// If multiview rendering is not being used, the value must be empty. 807 /// 808 /// The default value is empty. 809 pub correlated_view_masks: Vec<u32>, 810 811 pub _ne: crate::NonExhaustive, 812 } 813 814 impl Default for RenderPassCreateInfo { 815 #[inline] default() -> Self816 fn default() -> Self { 817 Self { 818 attachments: Vec::new(), 819 subpasses: Vec::new(), 820 dependencies: Vec::new(), 821 correlated_view_masks: Vec::new(), 822 _ne: crate::NonExhaustive(()), 823 } 824 } 825 } 826 827 /// Describes an attachment that will be used in a render pass. 828 #[derive(Clone, Copy, Debug)] 829 pub struct AttachmentDescription { 830 /// The format of the image that is going to be bound. 831 /// 832 /// The default value is `None`, which must be overridden. 833 pub format: Option<Format>, 834 835 /// The number of samples of the image that is going to be bound. 836 /// 837 /// The default value is [`SampleCount::Sample1`]. 838 pub samples: SampleCount, 839 840 /// What the implementation should do with the attachment at the start of the subpass that first 841 /// uses it. 842 /// 843 /// The default value is [`LoadOp::DontCare`]. 844 pub load_op: LoadOp, 845 846 /// What the implementation should do with the attachment at the end of the subpass that last 847 /// uses it. 848 /// 849 /// The default value is [`StoreOp::DontCare`]. 850 pub store_op: StoreOp, 851 852 /// The equivalent of `load_op` for the stencil component of the attachment, if any. Irrelevant 853 /// if there is no stencil component. 854 /// 855 /// The default value is [`LoadOp::DontCare`]. 856 pub stencil_load_op: LoadOp, 857 858 /// The equivalent of `store_op` for the stencil component of the attachment, if any. Irrelevant 859 /// if there is no stencil component. 860 /// 861 /// The default value is [`StoreOp::DontCare`]. 862 pub stencil_store_op: StoreOp, 863 864 /// The layout that the image must in at the start of the render pass. 865 /// 866 /// The vulkano library will automatically switch to the correct layout if necessary, but it 867 /// is more efficient to set this to the correct value. 868 /// 869 /// The default value is [`ImageLayout::Undefined`], which must be overridden. 870 pub initial_layout: ImageLayout, 871 872 /// The layout that the image will be transitioned to at the end of the render pass. 873 /// 874 /// The default value is [`ImageLayout::Undefined`], which must be overridden. 875 pub final_layout: ImageLayout, 876 877 pub _ne: crate::NonExhaustive, 878 } 879 880 impl Default for AttachmentDescription { 881 #[inline] default() -> Self882 fn default() -> Self { 883 Self { 884 format: None, 885 samples: SampleCount::Sample1, 886 load_op: LoadOp::DontCare, 887 store_op: StoreOp::DontCare, 888 stencil_load_op: LoadOp::DontCare, 889 stencil_store_op: StoreOp::DontCare, 890 initial_layout: ImageLayout::Undefined, 891 final_layout: ImageLayout::Undefined, 892 _ne: crate::NonExhaustive(()), 893 } 894 } 895 } 896 897 /// Describes one of the subpasses of a render pass. 898 /// 899 /// A subpass can use zero or more attachments of various types. Attachment types of which there can 900 /// be multiple are listed in a `Vec` in this structure. The index in these `Vec`s corresponds to 901 /// the index used for that attachment type in the shader. 902 /// 903 /// If a particular index is not used in the shader, it can be set to `None` in this structure. 904 /// This is useful if an unused index needs to be skipped but a higher index needs to be specified. 905 /// 906 /// If an attachment is used more than once, i.e. a given `AttachmentReference::attachment` occurs 907 /// more than once in the `SubpassDescription`, then their `AttachmentReference::layout` must be 908 /// the same as well. 909 #[derive(Debug, Clone)] 910 pub struct SubpassDescription { 911 /// If not `0`, enables multiview rendering, and specifies the view indices that are rendered to 912 /// in this subpass. The value is a bitmask, so that that for example `0b11` will draw to the 913 /// first two views and `0b101` will draw to the first and third view. 914 /// 915 /// If set to a nonzero value, it must be nonzero for all subpasses in the render pass, and the 916 /// [`multiview`](crate::device::Features::multiview) feature must be enabled on the device. 917 /// 918 /// The default value is `0`. 919 pub view_mask: u32, 920 921 /// The attachments of the render pass that are to be used as input attachments in this subpass. 922 /// 923 /// If an attachment is used here for the first time in this render pass, and it's is not also 924 /// used as a color or depth/stencil attachment in this subpass, then the attachment's `load_op` 925 /// must not be [`LoadOp::Clear`]. 926 /// 927 /// The default value is empty. 928 pub input_attachments: Vec<Option<AttachmentReference>>, 929 930 /// The attachments of the render pass that are to be used as color attachments in this subpass. 931 /// 932 /// The number of color attachments must be less than the 933 /// [`max_color_attachments`](crate::device::Properties::max_color_attachments) limit of the 934 /// physical device. All color attachments must have the same `samples` value. 935 /// 936 /// The default value is empty. 937 pub color_attachments: Vec<Option<AttachmentReference>>, 938 939 /// The attachments of the render pass that are to be used as resolve attachments in this 940 /// subpass. 941 /// 942 /// This list must either be empty or have the same length as `color_attachments`. If it's not 943 /// empty, then each resolve attachment is paired with the color attachment of the same index. 944 /// The resolve attachments must all have a `samples` value of [`SampleCount::Sample1`], while 945 /// the color attachments must have a `samples` value other than [`SampleCount::Sample1`]. 946 /// Each resolve attachment must have the same `format` as the corresponding color attachment. 947 /// 948 /// The default value is empty. 949 pub resolve_attachments: Vec<Option<AttachmentReference>>, 950 951 /// The single attachment of the render pass that is to be used as depth-stencil attachment in 952 /// this subpass. 953 /// 954 /// If set to `Some`, the referenced attachment must have the same `samples` value as those in 955 /// `color_attachments`. 956 /// 957 /// The default value is `None`. 958 pub depth_stencil_attachment: Option<AttachmentReference>, 959 960 /// The indices of attachments of the render pass that will be preserved during this subpass. 961 /// 962 /// The referenced attachments must not be used as any other attachment type in the subpass. 963 /// 964 /// The default value is empty. 965 pub preserve_attachments: Vec<u32>, 966 967 pub _ne: crate::NonExhaustive, 968 } 969 970 impl Default for SubpassDescription { 971 #[inline] default() -> Self972 fn default() -> Self { 973 Self { 974 view_mask: 0, 975 color_attachments: Vec::new(), 976 depth_stencil_attachment: None, 977 input_attachments: Vec::new(), 978 resolve_attachments: Vec::new(), 979 preserve_attachments: Vec::new(), 980 _ne: crate::NonExhaustive(()), 981 } 982 } 983 } 984 985 /// A reference in a subpass description to a particular attachment of the render pass. 986 #[derive(Clone, Debug)] 987 pub struct AttachmentReference { 988 /// The number of the attachment being referred to. 989 /// 990 /// The default value is `0`. 991 pub attachment: u32, 992 993 /// The image layout that the attachment should be transitioned to at the start of the subpass. 994 /// 995 /// The layout is restricted by the type of attachment that an attachment is being used as. A 996 /// full listing of allowed layouts per type can be found in 997 /// [the Vulkan specification](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap8.html#attachment-type-imagelayout). 998 /// 999 /// The default value is [`ImageLayout::Undefined`], which must be overridden. 1000 pub layout: ImageLayout, 1001 1002 /// For references to input attachments, the aspects of the image that should be selected. 1003 /// For attachment types other than input attachments, the value must be empty. 1004 /// 1005 /// If empty, all aspects available in the input attachment's `format` will be selected. 1006 /// If any fields are set, they must be aspects that are available in the `format` of the 1007 /// attachment. 1008 /// 1009 /// If the value is neither empty nor identical to the aspects of the `format`, the device API 1010 /// version must be at least 1.1, or either the 1011 /// [`khr_create_renderpass2`](crate::device::DeviceExtensions::khr_create_renderpass2) or the 1012 /// [`khr_maintenance2`](crate::device::DeviceExtensions::khr_maintenance2) extensions must be 1013 /// enabled on the device. 1014 /// 1015 /// The default value is [`ImageAspects::empty()`]. 1016 pub aspects: ImageAspects, 1017 1018 pub _ne: crate::NonExhaustive, 1019 } 1020 1021 impl Default for AttachmentReference { 1022 #[inline] default() -> Self1023 fn default() -> Self { 1024 Self { 1025 attachment: 0, 1026 layout: ImageLayout::Undefined, 1027 aspects: ImageAspects::empty(), 1028 _ne: crate::NonExhaustive(()), 1029 } 1030 } 1031 } 1032 1033 /// A dependency between two subpasses of a render pass. 1034 /// 1035 /// The implementation is allowed to change the order of the subpasses within a render pass, unless 1036 /// you specify that there exists a dependency between two subpasses (ie. the result of one will be 1037 /// used as the input of another one). Subpass dependencies work similar to pipeline barriers, 1038 /// except that they operate on whole subpasses instead of individual images. 1039 /// 1040 /// If `src_subpass` and `dst_subpass` are equal, then this specifies a 1041 /// [subpass self-dependency](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-pipeline-barriers-subpass-self-dependencies). 1042 /// The `src_stages` must all be 1043 /// [logically earlier in the pipeline](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-pipeline-stages-order) 1044 /// than the `dst_stages`, and if they both contain a 1045 /// [framebuffer-space stage](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-framebuffer-regions), 1046 /// then `by_region` must be activated. 1047 /// 1048 /// If `src_subpass` or `dst_subpass` are set to `None`, this specifies an external 1049 /// dependency. An external dependency specifies a dependency on commands that were submitted before 1050 /// the render pass instance began (for `src_subpass`), or on commands that will be submitted 1051 /// after the render pass instance ends (for `dst_subpass`). The values must not both be 1052 /// `None`. 1053 #[derive(Clone, Debug, PartialEq, Eq)] 1054 pub struct SubpassDependency { 1055 /// The index of the subpass that writes the data that `dst_subpass` is going to use. 1056 /// 1057 /// `None` specifies an external dependency. 1058 /// 1059 /// The default value is `None`. 1060 pub src_subpass: Option<u32>, 1061 1062 /// The index of the subpass that reads the data that `src_subpass` wrote. 1063 /// 1064 /// `None` specifies an external dependency. 1065 /// 1066 /// The default value is `None`. 1067 pub dst_subpass: Option<u32>, 1068 1069 /// The pipeline stages that must be finished on `src_subpass` before the 1070 /// `dst_stages` of `dst_subpass` can start. 1071 /// 1072 /// The default value is [`PipelineStages::empty()`]. 1073 pub src_stages: PipelineStages, 1074 1075 /// The pipeline stages of `dst_subpass` that must wait for the `src_stages` of 1076 /// `src_subpass` to be finished. Stages that are earlier than the stages specified here can 1077 /// start before the `src_stages` are finished. 1078 /// 1079 /// The default value is [`PipelineStages::empty()`]. 1080 pub dst_stages: PipelineStages, 1081 1082 /// The way `src_subpass` accesses the attachments on which we depend. 1083 /// 1084 /// The default value is [`AccessFlags::empty()`]. 1085 pub src_access: AccessFlags, 1086 1087 /// The way `dst_subpass` accesses the attachments on which we depend. 1088 /// 1089 /// The default value is [`AccessFlags::empty()`]. 1090 pub dst_access: AccessFlags, 1091 1092 /// Dependency flags that modify behavior of the subpass dependency. 1093 /// 1094 /// If a `src_subpass` equals `dst_subpass`, then: 1095 /// - If `src_stages` and `dst_stages` both contain framebuffer-space stages, 1096 /// this must include [`BY_REGION`]. 1097 /// - If the subpass's `view_mask` has more than one view, 1098 /// this must include [`VIEW_LOCAL`]. 1099 /// 1100 /// The default value is [`DependencyFlags::empty()`]. 1101 /// 1102 /// [`BY_REGION`]: crate::sync::DependencyFlags::BY_REGION 1103 /// [`VIEW_LOCAL`]: crate::sync::DependencyFlags::VIEW_LOCAL 1104 pub dependency_flags: DependencyFlags, 1105 1106 /// If multiview rendering is being used (the subpasses have a nonzero `view_mask`), and 1107 /// `dependency_flags` includes [`VIEW_LOCAL`], specifies an offset relative to the view index 1108 /// of `dst_subpass`: each view `d` in `dst_subpass` depends on view `d + view_offset` in 1109 /// `src_subpass`. If the source view index does not exist, the dependency is ignored for 1110 /// that view. 1111 /// 1112 /// If `dependency_flags` does not include [`VIEW_LOCAL`], or if `src_subpass` and 1113 /// `dst_subpass` are the same, the value must be `0`. 1114 /// 1115 /// The default value is `0`. 1116 /// 1117 /// [`VIEW_LOCAL`]: crate::sync::DependencyFlags::VIEW_LOCAL 1118 pub view_offset: i32, 1119 1120 pub _ne: crate::NonExhaustive, 1121 } 1122 1123 impl Default for SubpassDependency { 1124 #[inline] default() -> Self1125 fn default() -> Self { 1126 Self { 1127 src_subpass: None, 1128 dst_subpass: None, 1129 src_stages: PipelineStages::empty(), 1130 dst_stages: PipelineStages::empty(), 1131 src_access: AccessFlags::empty(), 1132 dst_access: AccessFlags::empty(), 1133 dependency_flags: DependencyFlags::empty(), 1134 view_offset: 0, 1135 _ne: crate::NonExhaustive(()), 1136 } 1137 } 1138 } 1139 1140 vulkan_enum! { 1141 #[non_exhaustive] 1142 1143 /// Describes what the implementation should do with an attachment at the start of the subpass. 1144 LoadOp = AttachmentLoadOp(i32); 1145 1146 /// The content of the attachment will be loaded from memory. This is what you want if you want 1147 /// to draw over something existing. 1148 /// 1149 /// While this is the most intuitive option, it is also the slowest because it uses a lot of 1150 /// memory bandwidth. 1151 Load = LOAD, 1152 1153 /// The content of the attachment will be filled by the implementation with a uniform value 1154 /// that you must provide when you start drawing. 1155 /// 1156 /// This is what you usually use at the start of a frame, in order to reset the content of 1157 /// the color, depth and/or stencil buffers. 1158 Clear = CLEAR, 1159 1160 /// The attachment will have undefined content. 1161 /// 1162 /// This is what you should use for attachments that you intend to entirely cover with draw 1163 /// commands. 1164 /// If you are going to fill the attachment with a uniform value, it is better to use `Clear` 1165 /// instead. 1166 DontCare = DONT_CARE, 1167 1168 /* TODO: enable 1169 // TODO: document 1170 None = NONE_EXT { 1171 device_extensions: [ext_load_store_op_none], 1172 },*/ 1173 } 1174 1175 vulkan_enum! { 1176 #[non_exhaustive] 1177 1178 /// Describes what the implementation should do with an attachment after all the subpasses have 1179 /// completed. 1180 StoreOp = AttachmentStoreOp(i32); 1181 1182 /// The attachment will be stored. This is what you usually want. 1183 /// 1184 /// While this is the most intuitive option, it is also slower than `DontCare` because it can 1185 /// take time to write the data back to memory. 1186 Store = STORE, 1187 1188 /// What happens is implementation-specific. 1189 /// 1190 /// This is purely an optimization compared to `Store`. The implementation doesn't need to copy 1191 /// from the internal cache to the memory, which saves memory bandwidth. 1192 /// 1193 /// This doesn't mean that the data won't be copied, as an implementation is also free to not 1194 /// use a cache and write the output directly in memory. In other words, the content of the 1195 /// image will be undefined. 1196 DontCare = DONT_CARE, 1197 1198 /* TODO: enable 1199 // TODO: document 1200 None = NONE { 1201 api_version: V1_3, 1202 device_extensions: [khr_dynamic_rendering, ext_load_store_op_none, qcom_render_pass_store_ops], 1203 },*/ 1204 } 1205 1206 vulkan_bitflags_enum! { 1207 #[non_exhaustive] 1208 1209 /// A set of [`ResolveMode`] values. 1210 ResolveModes, 1211 1212 /// Possible resolve modes for attachments. 1213 ResolveMode, 1214 1215 = ResolveModeFlags(u32); 1216 1217 /// The resolved sample is taken from sample number zero, the other samples are ignored. 1218 /// 1219 /// This mode is supported for depth and stencil formats, and for color images with an integer 1220 /// format. 1221 SAMPLE_ZERO, SampleZero = SAMPLE_ZERO, 1222 1223 /// The resolved sample is calculated from the average of the samples. 1224 /// 1225 /// This mode is supported for depth formats, and for color images with a non-integer format. 1226 AVERAGE, Average = AVERAGE, 1227 1228 /// The resolved sample is calculated from the minimum of the samples. 1229 /// 1230 /// This mode is supported for depth and stencil formats only. 1231 MIN, Min = MIN, 1232 1233 /// The resolved sample is calculated from the maximum of the samples. 1234 /// 1235 /// This mode is supported for depth and stencil formats only. 1236 MAX, Max = MAX, 1237 } 1238 1239 #[derive(Clone, Copy, Debug)] 1240 pub(crate) struct AttachmentUse { 1241 first_use_subpass: u32, 1242 last_use_subpass: u32, 1243 } 1244 1245 #[cfg(test)] 1246 mod tests { 1247 use crate::{ 1248 format::Format, 1249 render_pass::{RenderPass, RenderPassCreationError}, 1250 }; 1251 1252 #[test] empty()1253 fn empty() { 1254 let (device, _) = gfx_dev_and_queue!(); 1255 let _ = RenderPass::empty_single_pass(device).unwrap(); 1256 } 1257 1258 #[test] too_many_color_atch()1259 fn too_many_color_atch() { 1260 let (device, _) = gfx_dev_and_queue!(); 1261 1262 if device.physical_device().properties().max_color_attachments >= 10 { 1263 return; // test ignored 1264 } 1265 1266 let rp = single_pass_renderpass!( 1267 device, 1268 attachments: { 1269 a1: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, }, 1270 a2: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, }, 1271 a3: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, }, 1272 a4: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, }, 1273 a5: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, }, 1274 a6: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, }, 1275 a7: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, }, 1276 a8: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, }, 1277 a9: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, }, 1278 a10: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, }, 1279 }, 1280 pass: { 1281 color: [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10], 1282 depth_stencil: {}, 1283 }, 1284 ); 1285 1286 match rp { 1287 Err(RenderPassCreationError::SubpassMaxColorAttachmentsExceeded { .. }) => (), 1288 _ => panic!(), 1289 } 1290 } 1291 1292 #[test] non_zero_granularity()1293 fn non_zero_granularity() { 1294 let (device, _) = gfx_dev_and_queue!(); 1295 1296 let rp = single_pass_renderpass!( 1297 device, 1298 attachments: { 1299 a: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, }, 1300 }, 1301 pass: { 1302 color: [a], 1303 depth_stencil: {}, 1304 }, 1305 ) 1306 .unwrap(); 1307 1308 let granularity = rp.granularity(); 1309 assert_ne!(granularity[0], 0); 1310 assert_ne!(granularity[1], 0); 1311 } 1312 } 1313