1 // Copyright (c) 2022 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 use super::{ 11 AttachmentDescription, AttachmentReference, LoadOp, RenderPass, RenderPassCreateInfo, 12 SubpassDependency, SubpassDescription, 13 }; 14 use crate::{ 15 device::Device, 16 format::FormatFeatures, 17 image::{ImageAspects, ImageLayout, SampleCount}, 18 sync::{AccessFlags, DependencyFlags, PipelineStages}, 19 OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject, 20 }; 21 use smallvec::SmallVec; 22 use std::{ 23 error::Error, 24 fmt::{Display, Error as FmtError, Formatter}, 25 mem::MaybeUninit, 26 ptr, 27 }; 28 29 impl RenderPass { validate( device: &Device, create_info: &mut RenderPassCreateInfo, ) -> Result<(), RenderPassCreationError>30 pub(super) fn validate( 31 device: &Device, 32 create_info: &mut RenderPassCreateInfo, 33 ) -> Result<(), RenderPassCreationError> { 34 let properties = device.physical_device().properties(); 35 36 let RenderPassCreateInfo { 37 attachments, 38 subpasses, 39 dependencies, 40 correlated_view_masks, 41 _ne: _, 42 } = create_info; 43 44 /* 45 Attachments 46 */ 47 48 let mut attachment_potential_format_features = Vec::with_capacity(attachments.len()); 49 50 for (atch_num, attachment) in attachments.iter().enumerate() { 51 let &AttachmentDescription { 52 format, 53 samples, 54 load_op, 55 store_op, 56 stencil_load_op, 57 stencil_store_op, 58 initial_layout, 59 final_layout, 60 _ne: _, 61 } = attachment; 62 let atch_num = atch_num as u32; 63 64 // VUID-VkAttachmentDescription2-finalLayout-03061 65 if matches!( 66 final_layout, 67 ImageLayout::Undefined | ImageLayout::Preinitialized 68 ) { 69 return Err(RenderPassCreationError::AttachmentLayoutInvalid { 70 attachment: atch_num, 71 }); 72 } 73 74 let format = format.unwrap(); 75 let aspects = format.aspects(); 76 77 // VUID-VkAttachmentDescription2-format-parameter 78 format.validate_device(device)?; 79 80 // VUID-VkAttachmentDescription2-samples-parameter 81 samples.validate_device(device)?; 82 83 for load_op in [load_op, stencil_load_op] { 84 // VUID-VkAttachmentDescription2-loadOp-parameter 85 // VUID-VkAttachmentDescription2-stencilLoadOp-parameter 86 load_op.validate_device(device)?; 87 } 88 89 for store_op in [store_op, stencil_store_op] { 90 // VUID-VkAttachmentDescription2-storeOp-parameter 91 // VUID-VkAttachmentDescription2-stencilStoreOp-parameter 92 store_op.validate_device(device)?; 93 } 94 95 for layout in [initial_layout, final_layout] { 96 // VUID-VkAttachmentDescription2-initialLayout-parameter 97 // VUID-VkAttachmentDescription2-finalLayout-parameter 98 layout.validate_device(device)?; 99 100 if aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) { 101 // VUID-VkAttachmentDescription2-format-03281 102 // VUID-VkAttachmentDescription2-format-03283 103 if matches!(layout, ImageLayout::ColorAttachmentOptimal) { 104 return Err(RenderPassCreationError::AttachmentLayoutInvalid { 105 attachment: atch_num, 106 }); 107 } 108 } else { 109 // VUID-VkAttachmentDescription2-format-03280 110 // VUID-VkAttachmentDescription2-format-03282 111 // VUID-VkAttachmentDescription2-format-06487 112 // VUID-VkAttachmentDescription2-format-06488 113 if matches!( 114 layout, 115 ImageLayout::DepthStencilAttachmentOptimal 116 | ImageLayout::DepthStencilReadOnlyOptimal 117 | ImageLayout::DepthAttachmentStencilReadOnlyOptimal 118 | ImageLayout::DepthReadOnlyStencilAttachmentOptimal 119 ) { 120 return Err(RenderPassCreationError::AttachmentLayoutInvalid { 121 attachment: atch_num, 122 }); 123 } 124 } 125 } 126 127 // Use unchecked, because all validation has been done above. 128 attachment_potential_format_features.push(unsafe { 129 device 130 .physical_device() 131 .format_properties_unchecked(format) 132 .potential_format_features() 133 }); 134 } 135 136 /* 137 Subpasses 138 */ 139 140 // VUID-VkRenderPassCreateInfo2-subpassCount-arraylength 141 assert!(!subpasses.is_empty()); 142 143 let is_multiview = subpasses[0].view_mask != 0; 144 145 // VUID-VkSubpassDescription2-multiview-06558 146 if is_multiview && !device.enabled_features().multiview { 147 return Err(RenderPassCreationError::RequirementNotMet { 148 required_for: "`create_info.subpasses[0].view_mask` is not `0`", 149 requires_one_of: RequiresOneOf { 150 features: &["multiview"], 151 ..Default::default() 152 }, 153 }); 154 } 155 156 let mut attachment_used = vec![false; attachments.len()]; 157 158 for (subpass_num, subpass) in subpasses.iter_mut().enumerate() { 159 let &mut SubpassDescription { 160 view_mask, 161 ref mut input_attachments, 162 ref color_attachments, 163 ref resolve_attachments, 164 ref depth_stencil_attachment, 165 ref preserve_attachments, 166 _ne: _, 167 } = subpass; 168 let subpass_num = subpass_num as u32; 169 170 // VUID-VkRenderPassCreateInfo2-viewMask-03058 171 if (view_mask != 0) != is_multiview { 172 return Err(RenderPassCreationError::SubpassMultiviewMismatch { 173 subpass: subpass_num, 174 multiview: subpass.view_mask != 0, 175 first_subpass_multiview: is_multiview, 176 }); 177 } 178 179 let view_count = u32::BITS - view_mask.leading_zeros(); 180 181 // VUID-VkSubpassDescription2-viewMask-06706 182 if view_count > properties.max_multiview_view_count.unwrap_or(0) { 183 return Err( 184 RenderPassCreationError::SubpassMaxMultiviewViewCountExceeded { 185 subpass: subpass_num, 186 view_count, 187 max: properties.max_multiview_view_count.unwrap_or(0), 188 }, 189 ); 190 } 191 192 // VUID-VkSubpassDescription2-colorAttachmentCount-03063 193 if color_attachments.len() as u32 > properties.max_color_attachments { 194 return Err( 195 RenderPassCreationError::SubpassMaxColorAttachmentsExceeded { 196 subpass: subpass_num, 197 color_attachment_count: color_attachments.len() as u32, 198 max: properties.max_color_attachments, 199 }, 200 ); 201 } 202 203 // Track the layout of each attachment used in this subpass 204 let mut layouts = vec![None; attachments.len()]; 205 206 // Common checks for all attachment types 207 let mut check_attachment = |atch_ref: &AttachmentReference| { 208 // VUID-VkAttachmentReference2-layout-parameter 209 atch_ref.layout.validate_device(device)?; 210 211 // VUID? 212 atch_ref.aspects.validate_device(device)?; 213 214 // VUID-VkRenderPassCreateInfo2-attachment-03051 215 let atch = attachments.get(atch_ref.attachment as usize).ok_or( 216 RenderPassCreationError::SubpassAttachmentOutOfRange { 217 subpass: subpass_num, 218 attachment: atch_ref.attachment, 219 }, 220 )?; 221 222 // VUID-VkSubpassDescription2-layout-02528 223 match &mut layouts[atch_ref.attachment as usize] { 224 Some(layout) if *layout == atch_ref.layout => (), 225 Some(_) => { 226 return Err(RenderPassCreationError::SubpassAttachmentLayoutMismatch { 227 subpass: subpass_num, 228 attachment: atch_ref.attachment, 229 }) 230 } 231 layout @ None => *layout = Some(atch_ref.layout), 232 } 233 234 let first_use = 235 !std::mem::replace(&mut attachment_used[atch_ref.attachment as usize], true); 236 237 if first_use { 238 // VUID-VkRenderPassCreateInfo2-pAttachments-02522 239 if atch.load_op == LoadOp::Clear 240 && matches!( 241 atch_ref.layout, 242 ImageLayout::ShaderReadOnlyOptimal 243 | ImageLayout::DepthStencilReadOnlyOptimal 244 | ImageLayout::DepthReadOnlyStencilAttachmentOptimal 245 ) 246 { 247 return Err(RenderPassCreationError::AttachmentFirstUseLoadOpInvalid { 248 attachment: atch_ref.attachment, 249 first_use_subpass: subpass_num, 250 }); 251 } 252 253 // VUID-VkRenderPassCreateInfo2-pAttachments-02523 254 if atch.stencil_load_op == LoadOp::Clear 255 && matches!( 256 atch_ref.layout, 257 ImageLayout::ShaderReadOnlyOptimal 258 | ImageLayout::DepthStencilReadOnlyOptimal 259 | ImageLayout::DepthAttachmentStencilReadOnlyOptimal 260 ) 261 { 262 return Err(RenderPassCreationError::AttachmentFirstUseLoadOpInvalid { 263 attachment: atch_ref.attachment, 264 first_use_subpass: subpass_num, 265 }); 266 } 267 } 268 269 let potential_format_features = 270 &attachment_potential_format_features[atch_ref.attachment as usize]; 271 272 Ok((atch, potential_format_features, first_use)) 273 }; 274 275 /* 276 Check color attachments 277 */ 278 279 let mut color_samples = None; 280 281 for atch_ref in color_attachments.iter().flatten() { 282 let (atch, features, _first_use) = check_attachment(atch_ref)?; 283 284 // VUID-VkSubpassDescription2-pColorAttachments-02898 285 if !features.intersects(FormatFeatures::COLOR_ATTACHMENT) { 286 return Err( 287 RenderPassCreationError::SubpassAttachmentFormatUsageNotSupported { 288 subpass: subpass_num, 289 attachment: atch_ref.attachment, 290 usage: "color", 291 }, 292 ); 293 } 294 295 // VUID-VkAttachmentReference2-layout-03077 296 // VUID-VkSubpassDescription2-attachment-06913 297 // VUID-VkSubpassDescription2-attachment-06916 298 if matches!( 299 atch_ref.layout, 300 ImageLayout::Undefined 301 | ImageLayout::Preinitialized 302 | ImageLayout::PresentSrc 303 | ImageLayout::DepthStencilAttachmentOptimal 304 | ImageLayout::ShaderReadOnlyOptimal 305 | ImageLayout::DepthAttachmentStencilReadOnlyOptimal 306 | ImageLayout::DepthReadOnlyStencilAttachmentOptimal 307 ) { 308 return Err(RenderPassCreationError::SubpassAttachmentLayoutInvalid { 309 subpass: subpass_num, 310 attachment: atch_ref.attachment, 311 usage: "color", 312 }); 313 } 314 315 // Not required by spec, but enforced by Vulkano for sanity. 316 if !atch_ref.aspects.is_empty() { 317 return Err(RenderPassCreationError::SubpassAttachmentAspectsNotEmpty { 318 subpass: subpass_num, 319 attachment: atch_ref.attachment, 320 }); 321 } 322 323 // VUID-VkSubpassDescription2-pColorAttachments-03069 324 match &mut color_samples { 325 Some(samples) if *samples == atch.samples => (), 326 Some(samples) => { 327 return Err( 328 RenderPassCreationError::SubpassColorDepthStencilAttachmentSamplesMismatch { 329 subpass: subpass_num, 330 attachment: atch_ref.attachment, 331 samples: atch.samples, 332 first_samples: *samples, 333 }, 334 ) 335 } 336 samples @ None => *samples = Some(atch.samples), 337 } 338 } 339 340 /* 341 Check depth/stencil attachment 342 */ 343 344 if let Some(atch_ref) = depth_stencil_attachment.as_ref() { 345 let (atch, features, _first_use) = check_attachment(atch_ref)?; 346 347 // VUID-VkSubpassDescription2-pDepthStencilAttachment-02900 348 if !features.intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) { 349 return Err( 350 RenderPassCreationError::SubpassAttachmentFormatUsageNotSupported { 351 subpass: subpass_num, 352 attachment: atch_ref.attachment, 353 usage: "depth/stencil", 354 }, 355 ); 356 } 357 358 // VUID-VkAttachmentReference2-layout-03077 359 // VUID-VkSubpassDescription2-attachment-06915 360 if matches!( 361 atch_ref.layout, 362 ImageLayout::Undefined 363 | ImageLayout::Preinitialized 364 | ImageLayout::PresentSrc 365 | ImageLayout::ColorAttachmentOptimal 366 | ImageLayout::ShaderReadOnlyOptimal 367 ) { 368 return Err(RenderPassCreationError::SubpassAttachmentLayoutInvalid { 369 subpass: subpass_num, 370 attachment: atch_ref.attachment, 371 usage: "depth/stencil", 372 }); 373 } 374 375 // Not required by spec, but enforced by Vulkano for sanity. 376 if !atch_ref.aspects.is_empty() { 377 return Err(RenderPassCreationError::SubpassAttachmentAspectsNotEmpty { 378 subpass: subpass_num, 379 attachment: atch_ref.attachment, 380 }); 381 } 382 383 // VUID-VkSubpassDescription2-pDepthStencilAttachment-04440 384 if color_attachments 385 .iter() 386 .flatten() 387 .any(|color_atch_ref| color_atch_ref.attachment == atch_ref.attachment) 388 { 389 return Err( 390 RenderPassCreationError::SubpassAttachmentUsageColorDepthStencil { 391 subpass: subpass_num, 392 attachment: atch_ref.attachment, 393 }, 394 ); 395 } 396 397 // VUID-VkSubpassDescription2-pDepthStencilAttachment-03071 398 if let Some(samples) = color_samples.filter(|samples| *samples != atch.samples) { 399 return Err( 400 RenderPassCreationError::SubpassColorDepthStencilAttachmentSamplesMismatch { 401 subpass: subpass_num, 402 attachment: atch_ref.attachment, 403 samples: atch.samples, 404 first_samples: samples, 405 }, 406 ); 407 } 408 } 409 410 /* 411 Check input attachments 412 This must be placed after color and depth/stencil checks so that `first_use` 413 will be true for VUID-VkSubpassDescription2-loadOp-03064. 414 */ 415 416 for atch_ref in input_attachments.iter_mut().flatten() { 417 let (atch, features, first_use) = check_attachment(atch_ref)?; 418 419 // VUID-VkSubpassDescription2-pInputAttachments-02897 420 if !features.intersects( 421 FormatFeatures::COLOR_ATTACHMENT | FormatFeatures::DEPTH_STENCIL_ATTACHMENT, 422 ) { 423 return Err( 424 RenderPassCreationError::SubpassAttachmentFormatUsageNotSupported { 425 subpass: subpass_num, 426 attachment: atch_ref.attachment, 427 usage: "input", 428 }, 429 ); 430 } 431 432 // VUID-VkAttachmentReference2-layout-03077 433 // VUID-VkSubpassDescription2-attachment-06912 434 if matches!( 435 atch_ref.layout, 436 ImageLayout::Undefined 437 | ImageLayout::Preinitialized 438 | ImageLayout::PresentSrc 439 | ImageLayout::ColorAttachmentOptimal 440 | ImageLayout::DepthStencilAttachmentOptimal 441 ) { 442 return Err(RenderPassCreationError::SubpassAttachmentLayoutInvalid { 443 subpass: subpass_num, 444 attachment: atch_ref.attachment, 445 usage: "input", 446 }); 447 } 448 449 let atch_aspects = atch.format.unwrap().aspects(); 450 451 if atch_ref.aspects.is_empty() { 452 // VUID-VkSubpassDescription2-attachment-02800 453 atch_ref.aspects = atch_aspects; 454 } else if atch_ref.aspects != atch_aspects { 455 if !(device.api_version() >= Version::V1_1 456 || device.enabled_extensions().khr_create_renderpass2 457 || device.enabled_extensions().khr_maintenance2) 458 { 459 return Err(RenderPassCreationError::RequirementNotMet { 460 required_for: "`create_info.subpasses` has an element, where \ 461 `input_attachments` has an element that is `Some(atch_ref)`, \ 462 where `atch_ref.aspects` does not match the aspects of the \ 463 attachment itself", 464 requires_one_of: RequiresOneOf { 465 api_version: Some(Version::V1_1), 466 device_extensions: &["khr_create_renderpass2", "khr_maintenance2"], 467 ..Default::default() 468 }, 469 }); 470 } 471 472 // VUID-VkSubpassDescription2-attachment-02801 473 // VUID-VkSubpassDescription2-attachment-04563 474 // VUID-VkRenderPassCreateInfo2-attachment-02525 475 if !atch_aspects.contains(atch_ref.aspects) { 476 return Err( 477 RenderPassCreationError::SubpassInputAttachmentAspectsNotCompatible { 478 subpass: subpass_num, 479 attachment: atch_ref.attachment, 480 }, 481 ); 482 } 483 } 484 485 // VUID-VkSubpassDescription2-loadOp-03064 486 if first_use && atch.load_op == LoadOp::Clear { 487 return Err(RenderPassCreationError::AttachmentFirstUseLoadOpInvalid { 488 attachment: atch_ref.attachment, 489 first_use_subpass: subpass_num, 490 }); 491 } 492 } 493 494 /* 495 Check resolve attachments 496 */ 497 498 // VUID-VkSubpassDescription2-pResolveAttachments-parameter 499 if !(resolve_attachments.is_empty() 500 || resolve_attachments.len() == color_attachments.len()) 501 { 502 return Err( 503 RenderPassCreationError::SubpassResolveAttachmentsColorAttachmentsLenMismatch { 504 subpass: subpass_num, 505 }, 506 ); 507 } 508 509 for (atch_ref, color_atch_ref) in resolve_attachments 510 .iter() 511 .zip(subpass.color_attachments.iter()) 512 .filter_map(|(r, c)| r.as_ref().map(|r| (r, c.as_ref()))) 513 { 514 let (atch, features, _first_use) = check_attachment(atch_ref)?; 515 516 // VUID-VkSubpassDescription2-pResolveAttachments-02899 517 if !features.intersects(FormatFeatures::COLOR_ATTACHMENT) { 518 return Err( 519 RenderPassCreationError::SubpassAttachmentFormatUsageNotSupported { 520 subpass: subpass_num, 521 attachment: atch_ref.attachment, 522 usage: "resolve", 523 }, 524 ); 525 } 526 527 // VUID-VkAttachmentReference2-layout-03077 528 // VUID-VkSubpassDescription2-attachment-06914 529 // VUID-VkSubpassDescription2-attachment-06917 530 if matches!( 531 atch_ref.layout, 532 ImageLayout::Undefined 533 | ImageLayout::Preinitialized 534 | ImageLayout::PresentSrc 535 | ImageLayout::DepthStencilAttachmentOptimal 536 | ImageLayout::ShaderReadOnlyOptimal 537 | ImageLayout::DepthAttachmentStencilReadOnlyOptimal 538 | ImageLayout::DepthReadOnlyStencilAttachmentOptimal 539 ) { 540 return Err(RenderPassCreationError::SubpassAttachmentLayoutInvalid { 541 subpass: subpass_num, 542 attachment: atch_ref.attachment, 543 usage: "resolve", 544 }); 545 } 546 547 // Not required by spec, but enforced by Vulkano for sanity. 548 if !atch_ref.aspects.is_empty() { 549 return Err(RenderPassCreationError::SubpassAttachmentAspectsNotEmpty { 550 subpass: subpass_num, 551 attachment: atch_ref.attachment, 552 }); 553 } 554 555 // VUID-VkSubpassDescription2-pResolveAttachments-03065 556 let color_atch_ref = color_atch_ref.ok_or({ 557 RenderPassCreationError::SubpassResolveAttachmentWithoutColorAttachment { 558 subpass: subpass_num, 559 } 560 })?; 561 let color_atch = &attachments[color_atch_ref.attachment as usize]; 562 563 // VUID-VkSubpassDescription2-pResolveAttachments-03067 564 if atch.samples != SampleCount::Sample1 { 565 return Err( 566 RenderPassCreationError::SubpassResolveAttachmentMultisampled { 567 subpass: subpass_num, 568 attachment: atch_ref.attachment, 569 }, 570 ); 571 } 572 573 // VUID-VkSubpassDescription2-pResolveAttachments-03066 574 if color_atch.samples == SampleCount::Sample1 { 575 return Err( 576 RenderPassCreationError::SubpassColorAttachmentWithResolveNotMultisampled { 577 subpass: subpass_num, 578 attachment: atch_ref.attachment, 579 }, 580 ); 581 } 582 583 // VUID-VkSubpassDescription2-pResolveAttachments-03068 584 if atch.format != color_atch.format { 585 return Err( 586 RenderPassCreationError::SubpassResolveAttachmentFormatMismatch { 587 subpass: subpass_num, 588 resolve_attachment: atch_ref.attachment, 589 color_attachment: color_atch_ref.attachment, 590 }, 591 ); 592 } 593 } 594 595 /* 596 Check preserve attachments 597 */ 598 599 for &atch in preserve_attachments { 600 // VUID-VkRenderPassCreateInfo2-attachment-03051 601 if atch as usize >= attachments.len() { 602 return Err(RenderPassCreationError::SubpassAttachmentOutOfRange { 603 subpass: subpass_num, 604 attachment: atch, 605 }); 606 } 607 608 // VUID-VkSubpassDescription2-pPreserveAttachments-03074 609 if layouts[atch as usize].is_some() { 610 return Err( 611 RenderPassCreationError::SubpassPreserveAttachmentUsedElsewhere { 612 subpass: subpass_num, 613 attachment: atch, 614 }, 615 ); 616 } 617 } 618 } 619 620 /* 621 Dependencies 622 */ 623 624 for (dependency_num, dependency) in dependencies.iter().enumerate() { 625 let &SubpassDependency { 626 src_subpass, 627 dst_subpass, 628 src_stages, 629 dst_stages, 630 src_access, 631 dst_access, 632 dependency_flags, 633 view_offset, 634 _ne: _, 635 } = dependency; 636 let dependency_num = dependency_num as u32; 637 638 for (stages, access) in [(src_stages, src_access), (dst_stages, dst_access)] { 639 if !device.enabled_features().synchronization2 { 640 if stages.is_2() { 641 return Err(RenderPassCreationError::RequirementNotMet { 642 required_for: "`create_info.dependencies` has an element where \ 643 `src_stages` or `dst_stages` contains flags from \ 644 `VkPipelineStageFlagBits2`", 645 requires_one_of: RequiresOneOf { 646 features: &["synchronization2"], 647 ..Default::default() 648 }, 649 }); 650 } 651 652 if access.is_2() { 653 return Err(RenderPassCreationError::RequirementNotMet { 654 required_for: "`create_info.dependencies` has an element where \ 655 `src_access` or `dst_access` contains flags from \ 656 `VkAccessFlagBits2`", 657 requires_one_of: RequiresOneOf { 658 features: &["synchronization2"], 659 ..Default::default() 660 }, 661 }); 662 } 663 } else if !(device.api_version() >= Version::V1_2 664 || device.enabled_extensions().khr_create_renderpass2) 665 { 666 // If synchronization2 is enabled but we don't have create_renderpass2, 667 // we are unable to use extension structs, so we can't use the 668 // extra flag bits. 669 670 if stages.is_2() { 671 return Err(RenderPassCreationError::RequirementNotMet { 672 required_for: "`create_info.dependencies` has an element where \ 673 `src_stages` or `dst_stages` contains flags from \ 674 `VkPipelineStageFlagBits2`", 675 requires_one_of: RequiresOneOf { 676 api_version: Some(Version::V1_2), 677 device_extensions: &["khr_create_renderpass2"], 678 ..Default::default() 679 }, 680 }); 681 } 682 683 if access.is_2() { 684 return Err(RenderPassCreationError::RequirementNotMet { 685 required_for: "`create_info.dependencies` has an element where \ 686 `src_access` or `dst_access` contains flags from \ 687 `VkAccessFlagBits2`", 688 requires_one_of: RequiresOneOf { 689 api_version: Some(Version::V1_2), 690 device_extensions: &["khr_create_renderpass2"], 691 ..Default::default() 692 }, 693 }); 694 } 695 } 696 697 // VUID-VkMemoryBarrier2-srcStageMask-parameter 698 // VUID-VkMemoryBarrier2-dstStageMask-parameter 699 stages.validate_device(device)?; 700 701 // VUID-VkMemoryBarrier2-srcAccessMask-parameter 702 // VUID-VkMemoryBarrier2-dstAccessMask-parameter 703 access.validate_device(device)?; 704 705 // VUID-VkMemoryBarrier2-srcStageMask-03929 706 // VUID-VkMemoryBarrier2-dstStageMask-03929 707 if stages.intersects(PipelineStages::GEOMETRY_SHADER) 708 && !device.enabled_features().geometry_shader 709 { 710 return Err(RenderPassCreationError::RequirementNotMet { 711 required_for: "`create_info.dependencies` has an element where `stages` \ 712 contains `PipelineStages::GEOMETRY_SHADER`", 713 requires_one_of: RequiresOneOf { 714 features: &["geometry_shader"], 715 ..Default::default() 716 }, 717 }); 718 } 719 720 // VUID-VkMemoryBarrier2-srcStageMask-03930 721 // VUID-VkMemoryBarrier2-dstStageMask-03930 722 if stages.intersects( 723 PipelineStages::TESSELLATION_CONTROL_SHADER 724 | PipelineStages::TESSELLATION_EVALUATION_SHADER, 725 ) && !device.enabled_features().tessellation_shader 726 { 727 return Err(RenderPassCreationError::RequirementNotMet { 728 required_for: "`create_info.dependencies` has an element where `stages` \ 729 contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \ 730 `PipelineStages::TESSELLATION_EVALUATION_SHADER`", 731 requires_one_of: RequiresOneOf { 732 features: &["tessellation_shader"], 733 ..Default::default() 734 }, 735 }); 736 } 737 738 // VUID-VkMemoryBarrier2-srcStageMask-03931 739 // VUID-VkMemoryBarrier2-dstStageMask-03931 740 if stages.intersects(PipelineStages::CONDITIONAL_RENDERING) 741 && !device.enabled_features().conditional_rendering 742 { 743 return Err(RenderPassCreationError::RequirementNotMet { 744 required_for: "`create_info.dependencies` has an element where `stages` \ 745 contains `PipelineStages::CONDITIONAL_RENDERING`", 746 requires_one_of: RequiresOneOf { 747 features: &["conditional_rendering"], 748 ..Default::default() 749 }, 750 }); 751 } 752 753 // VUID-VkMemoryBarrier2-srcStageMask-03932 754 // VUID-VkMemoryBarrier2-dstStageMask-03932 755 if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS) 756 && !device.enabled_features().fragment_density_map 757 { 758 return Err(RenderPassCreationError::RequirementNotMet { 759 required_for: "`create_info.dependencies` has an element where `stages` \ 760 contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`", 761 requires_one_of: RequiresOneOf { 762 features: &["fragment_density_map"], 763 ..Default::default() 764 }, 765 }); 766 } 767 768 // VUID-VkMemoryBarrier2-srcStageMask-03933 769 // VUID-VkMemoryBarrier2-dstStageMask-03933 770 if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK) 771 && !device.enabled_features().transform_feedback 772 { 773 return Err(RenderPassCreationError::RequirementNotMet { 774 required_for: "`create_info.dependencies` has an element where `stages` \ 775 contains `PipelineStages::TRANSFORM_FEEDBACK`", 776 requires_one_of: RequiresOneOf { 777 features: &["transform_feedback"], 778 ..Default::default() 779 }, 780 }); 781 } 782 783 // VUID-VkMemoryBarrier2-srcStageMask-03934 784 // VUID-VkMemoryBarrier2-dstStageMask-03934 785 if stages.intersects(PipelineStages::MESH_SHADER) 786 && !device.enabled_features().mesh_shader 787 { 788 return Err(RenderPassCreationError::RequirementNotMet { 789 required_for: "`create_info.dependencies` has an element where `stages` \ 790 contains `PipelineStages::MESH_SHADER`", 791 requires_one_of: RequiresOneOf { 792 features: &["mesh_shader"], 793 ..Default::default() 794 }, 795 }); 796 } 797 798 // VUID-VkMemoryBarrier2-srcStageMask-03935 799 // VUID-VkMemoryBarrier2-dstStageMask-03935 800 if stages.intersects(PipelineStages::TASK_SHADER) 801 && !device.enabled_features().task_shader 802 { 803 return Err(RenderPassCreationError::RequirementNotMet { 804 required_for: "`create_info.dependencies` has an element where `stages` \ 805 contains `PipelineStages::TASK_SHADER`", 806 requires_one_of: RequiresOneOf { 807 features: &["task_shader"], 808 ..Default::default() 809 }, 810 }); 811 } 812 813 // VUID-VkMemoryBarrier2-shadingRateImage-07316 814 // VUID-VkMemoryBarrier2-shadingRateImage-07316 815 if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT) 816 && !(device.enabled_features().attachment_fragment_shading_rate 817 || device.enabled_features().shading_rate_image) 818 { 819 return Err(RenderPassCreationError::RequirementNotMet { 820 required_for: "`create_info.dependencies` has an element where `stages` \ 821 contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`", 822 requires_one_of: RequiresOneOf { 823 features: &["attachment_fragment_shading_rate", "shading_rate_image"], 824 ..Default::default() 825 }, 826 }); 827 } 828 829 // VUID-VkMemoryBarrier2-srcStageMask-04957 830 // VUID-VkMemoryBarrier2-dstStageMask-04957 831 if stages.intersects(PipelineStages::SUBPASS_SHADING) 832 && !device.enabled_features().subpass_shading 833 { 834 return Err(RenderPassCreationError::RequirementNotMet { 835 required_for: "`create_info.dependencies` has an element where `stages` \ 836 contains `PipelineStages::SUBPASS_SHADING`", 837 requires_one_of: RequiresOneOf { 838 features: &["subpass_shading"], 839 ..Default::default() 840 }, 841 }); 842 } 843 844 // VUID-VkMemoryBarrier2-srcStageMask-04995 845 // VUID-VkMemoryBarrier2-dstStageMask-04995 846 if stages.intersects(PipelineStages::INVOCATION_MASK) 847 && !device.enabled_features().invocation_mask 848 { 849 return Err(RenderPassCreationError::RequirementNotMet { 850 required_for: "`create_info.dependencies` has an element where `stages` \ 851 contains `PipelineStages::INVOCATION_MASK`", 852 requires_one_of: RequiresOneOf { 853 features: &["invocation_mask"], 854 ..Default::default() 855 }, 856 }); 857 } 858 859 // VUID-VkSubpassDependency2-srcStageMask-03937 860 // VUID-VkSubpassDependency2-dstStageMask-03937 861 if stages.is_empty() && !device.enabled_features().synchronization2 { 862 return Err(RenderPassCreationError::RequirementNotMet { 863 required_for: "`create_info.dependencies` has an element where `stages` \ 864 is empty", 865 requires_one_of: RequiresOneOf { 866 features: &["synchronization2"], 867 ..Default::default() 868 }, 869 }); 870 } 871 872 // VUID-VkSubpassDependency2-srcAccessMask-03088 873 // VUID-VkSubpassDependency2-dstAccessMask-03089 874 if !AccessFlags::from(stages).contains(access) { 875 return Err( 876 RenderPassCreationError::DependencyAccessNotSupportedByStages { 877 dependency: dependency_num, 878 }, 879 ); 880 } 881 } 882 883 if dependency_flags.intersects(DependencyFlags::VIEW_LOCAL) { 884 // VUID-VkRenderPassCreateInfo2-viewMask-03059 885 if !is_multiview { 886 return Err( 887 RenderPassCreationError::DependencyViewLocalMultiviewNotEnabled { 888 dependency: dependency_num, 889 }, 890 ); 891 } 892 } else { 893 // VUID-VkSubpassDependency2-dependencyFlags-03092 894 if view_offset != 0 { 895 return Err( 896 RenderPassCreationError::DependencyViewOffzetNonzeroWithoutViewLocal { 897 dependency: dependency_num, 898 }, 899 ); 900 } 901 } 902 903 // VUID-VkSubpassDependency2-srcSubpass-03085 904 if src_subpass.is_none() && dst_subpass.is_none() { 905 return Err(RenderPassCreationError::DependencyBothSubpassesExternal { 906 dependency: dependency_num, 907 }); 908 } 909 910 for (subpass, stages) in [(src_subpass, src_stages), (dst_subpass, dst_stages)] { 911 if let Some(subpass) = subpass { 912 // VUID-VkRenderPassCreateInfo2-srcSubpass-02526 913 // VUID-VkRenderPassCreateInfo2-dstSubpass-02527 914 if subpass as usize >= subpasses.len() { 915 return Err(RenderPassCreationError::DependencySubpassOutOfRange { 916 dependency: dependency_num, 917 subpass, 918 }); 919 } 920 921 let remaining_stages = stages 922 - (PipelineStages::DRAW_INDIRECT 923 | PipelineStages::INDEX_INPUT 924 | PipelineStages::VERTEX_ATTRIBUTE_INPUT 925 | PipelineStages::VERTEX_SHADER 926 | PipelineStages::TESSELLATION_CONTROL_SHADER 927 | PipelineStages::TESSELLATION_EVALUATION_SHADER 928 | PipelineStages::GEOMETRY_SHADER 929 | PipelineStages::TRANSFORM_FEEDBACK 930 | PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT 931 | PipelineStages::EARLY_FRAGMENT_TESTS 932 | PipelineStages::FRAGMENT_SHADER 933 | PipelineStages::LATE_FRAGMENT_TESTS 934 | PipelineStages::COLOR_ATTACHMENT_OUTPUT 935 | PipelineStages::ALL_GRAPHICS); 936 937 // VUID-VkRenderPassCreateInfo2-pDependencies-03054 938 // VUID-VkRenderPassCreateInfo2-pDependencies-03055 939 if !remaining_stages.is_empty() { 940 return Err(RenderPassCreationError::DependencyStageNotSupported { 941 dependency: dependency_num, 942 }); 943 } 944 } else { 945 // VUID-VkSubpassDependency2-dependencyFlags-03090 946 // VUID-VkSubpassDependency2-dependencyFlags-03091 947 if dependency_flags.intersects(DependencyFlags::VIEW_LOCAL) { 948 return Err( 949 RenderPassCreationError::DependencyViewLocalExternalDependency { 950 dependency: dependency_num, 951 }, 952 ); 953 } 954 } 955 } 956 957 if let (Some(src_subpass), Some(dst_subpass)) = (src_subpass, dst_subpass) { 958 // VUID-VkSubpassDependency2-srcSubpass-03084 959 if src_subpass > dst_subpass { 960 return Err( 961 RenderPassCreationError::DependencySourceSubpassAfterDestinationSubpass { 962 dependency: dependency_num, 963 }, 964 ); 965 } 966 967 if src_subpass == dst_subpass { 968 let framebuffer_stages = PipelineStages::EARLY_FRAGMENT_TESTS 969 | PipelineStages::FRAGMENT_SHADER 970 | PipelineStages::LATE_FRAGMENT_TESTS 971 | PipelineStages::COLOR_ATTACHMENT_OUTPUT; 972 973 // VUID-VkSubpassDependency2-srcSubpass-06810 974 if src_stages.intersects(framebuffer_stages) 975 && !(dst_stages - framebuffer_stages).is_empty() 976 { 977 return Err( 978 RenderPassCreationError::DependencySelfDependencySourceStageAfterDestinationStage { 979 dependency: dependency_num, 980 }, 981 ); 982 } 983 984 // VUID-VkSubpassDependency2-srcSubpass-02245 985 if src_stages.intersects(framebuffer_stages) 986 && dst_stages.intersects(framebuffer_stages) 987 && !dependency_flags.intersects(DependencyFlags::BY_REGION) 988 { 989 return Err( 990 RenderPassCreationError::DependencySelfDependencyFramebufferStagesWithoutByRegion { 991 dependency: dependency_num, 992 }, 993 ); 994 } 995 996 if dependency_flags.intersects(DependencyFlags::VIEW_LOCAL) { 997 // VUID-VkSubpassDependency2-viewOffset-02530 998 if view_offset != 0 { 999 return Err( 1000 RenderPassCreationError::DependencySelfDependencyViewLocalNonzeroViewOffset { 1001 dependency: dependency_num, 1002 }, 1003 ); 1004 } 1005 } else { 1006 // VUID-VkRenderPassCreateInfo2-pDependencies-03060 1007 if subpasses[src_subpass as usize].view_mask.count_ones() > 1 { 1008 return Err( 1009 RenderPassCreationError::DependencySelfDependencyViewMaskMultiple { 1010 dependency: dependency_num, 1011 subpass: src_subpass, 1012 }, 1013 ); 1014 } 1015 } 1016 } 1017 } 1018 } 1019 1020 /* 1021 Correlated view masks 1022 */ 1023 1024 // VUID-VkRenderPassCreateInfo2-viewMask-03057 1025 if !correlated_view_masks.is_empty() { 1026 if !is_multiview { 1027 return Err(RenderPassCreationError::CorrelatedViewMasksMultiviewNotEnabled); 1028 } 1029 1030 // VUID-VkRenderPassCreateInfo2-pCorrelatedViewMasks-03056 1031 correlated_view_masks.iter().try_fold(0, |total, &mask| { 1032 if total & mask != 0 { 1033 Err(RenderPassCreationError::CorrelatedViewMasksOverlapping) 1034 } else { 1035 Ok(total | mask) 1036 } 1037 })?; 1038 } 1039 1040 Ok(()) 1041 } 1042 create_v2( device: &Device, create_info: &RenderPassCreateInfo, ) -> Result<ash::vk::RenderPass, RenderPassCreationError>1043 pub(super) unsafe fn create_v2( 1044 device: &Device, 1045 create_info: &RenderPassCreateInfo, 1046 ) -> Result<ash::vk::RenderPass, RenderPassCreationError> { 1047 let RenderPassCreateInfo { 1048 attachments, 1049 subpasses, 1050 dependencies, 1051 correlated_view_masks, 1052 _ne: _, 1053 } = create_info; 1054 1055 let attachments_vk = attachments 1056 .iter() 1057 .map(|attachment| ash::vk::AttachmentDescription2 { 1058 flags: ash::vk::AttachmentDescriptionFlags::empty(), 1059 format: attachment 1060 .format 1061 .map_or(ash::vk::Format::UNDEFINED, |f| f.into()), 1062 samples: attachment.samples.into(), 1063 load_op: attachment.load_op.into(), 1064 store_op: attachment.store_op.into(), 1065 stencil_load_op: attachment.stencil_load_op.into(), 1066 stencil_store_op: attachment.stencil_store_op.into(), 1067 initial_layout: attachment.initial_layout.into(), 1068 final_layout: attachment.final_layout.into(), 1069 ..Default::default() 1070 }) 1071 .collect::<SmallVec<[_; 4]>>(); 1072 1073 let attachment_references_vk = subpasses 1074 .iter() 1075 .flat_map(|subpass| { 1076 (subpass.input_attachments.iter()) 1077 .chain(subpass.color_attachments.iter()) 1078 .chain(subpass.resolve_attachments.iter()) 1079 .map(Option::as_ref) 1080 .chain(subpass.depth_stencil_attachment.iter().map(Some)) 1081 .map(|atch_ref| { 1082 if let Some(atch_ref) = atch_ref { 1083 ash::vk::AttachmentReference2 { 1084 attachment: atch_ref.attachment, 1085 layout: atch_ref.layout.into(), 1086 aspect_mask: atch_ref.aspects.into(), 1087 ..Default::default() 1088 } 1089 } else { 1090 ash::vk::AttachmentReference2 { 1091 attachment: ash::vk::ATTACHMENT_UNUSED, 1092 ..Default::default() 1093 } 1094 } 1095 }) 1096 }) 1097 .collect::<SmallVec<[_; 8]>>(); 1098 1099 let subpasses_vk = { 1100 // `ref_index` is increased during the loop and points to the next element to use 1101 // in `attachment_references_vk`. 1102 let mut ref_index = 0usize; 1103 let out: SmallVec<[_; 4]> = subpasses 1104 .iter() 1105 .map(|subpass| { 1106 let input_attachments = attachment_references_vk.as_ptr().add(ref_index); 1107 ref_index += subpass.input_attachments.len(); 1108 let color_attachments = attachment_references_vk.as_ptr().add(ref_index); 1109 ref_index += subpass.color_attachments.len(); 1110 let resolve_attachments = attachment_references_vk.as_ptr().add(ref_index); 1111 ref_index += subpass.resolve_attachments.len(); 1112 let depth_stencil = if subpass.depth_stencil_attachment.is_some() { 1113 let a = attachment_references_vk.as_ptr().add(ref_index); 1114 ref_index += 1; 1115 a 1116 } else { 1117 ptr::null() 1118 }; 1119 1120 ash::vk::SubpassDescription2 { 1121 flags: ash::vk::SubpassDescriptionFlags::empty(), 1122 pipeline_bind_point: ash::vk::PipelineBindPoint::GRAPHICS, // TODO: any need to make this user-specifiable? 1123 view_mask: subpass.view_mask, 1124 input_attachment_count: subpass.input_attachments.len() as u32, 1125 p_input_attachments: if subpass.input_attachments.is_empty() { 1126 ptr::null() 1127 } else { 1128 input_attachments 1129 }, 1130 color_attachment_count: subpass.color_attachments.len() as u32, 1131 p_color_attachments: if subpass.color_attachments.is_empty() { 1132 ptr::null() 1133 } else { 1134 color_attachments 1135 }, 1136 p_resolve_attachments: if subpass.resolve_attachments.is_empty() { 1137 ptr::null() 1138 } else { 1139 resolve_attachments 1140 }, 1141 p_depth_stencil_attachment: depth_stencil, 1142 preserve_attachment_count: subpass.preserve_attachments.len() as u32, 1143 p_preserve_attachments: if subpass.preserve_attachments.is_empty() { 1144 ptr::null() 1145 } else { 1146 subpass.preserve_attachments.as_ptr() 1147 }, 1148 ..Default::default() 1149 } 1150 }) 1151 .collect(); 1152 1153 // If this assertion fails, there's a serious bug in the code above ^. 1154 debug_assert!(ref_index == attachment_references_vk.len()); 1155 1156 out 1157 }; 1158 1159 let memory_barriers_vk: SmallVec<[_; 4]> = if device.enabled_features().synchronization2 { 1160 debug_assert!( 1161 device.api_version() >= Version::V1_3 1162 || device.enabled_extensions().khr_synchronization2 1163 ); 1164 dependencies 1165 .iter() 1166 .map(|dependency| ash::vk::MemoryBarrier2 { 1167 src_stage_mask: dependency.src_stages.into(), 1168 src_access_mask: dependency.src_access.into(), 1169 dst_stage_mask: dependency.dst_stages.into(), 1170 dst_access_mask: dependency.dst_access.into(), 1171 ..Default::default() 1172 }) 1173 .collect() 1174 } else { 1175 SmallVec::new() 1176 }; 1177 1178 let dependencies_vk = dependencies 1179 .iter() 1180 .enumerate() 1181 .map(|(index, dependency)| { 1182 ash::vk::SubpassDependency2 { 1183 p_next: memory_barriers_vk 1184 .get(index) 1185 .map_or(ptr::null(), |mb| mb as *const _ as *const _), 1186 src_subpass: dependency.src_subpass.unwrap_or(ash::vk::SUBPASS_EXTERNAL), 1187 dst_subpass: dependency.dst_subpass.unwrap_or(ash::vk::SUBPASS_EXTERNAL), 1188 src_stage_mask: dependency.src_stages.into(), 1189 dst_stage_mask: dependency.dst_stages.into(), 1190 src_access_mask: dependency.src_access.into(), 1191 dst_access_mask: dependency.dst_access.into(), 1192 dependency_flags: dependency.dependency_flags.into(), 1193 // VUID-VkSubpassDependency2-dependencyFlags-03092 1194 view_offset: dependency.view_offset, 1195 ..Default::default() 1196 } 1197 }) 1198 .collect::<SmallVec<[_; 4]>>(); 1199 1200 let create_info = ash::vk::RenderPassCreateInfo2 { 1201 flags: ash::vk::RenderPassCreateFlags::empty(), 1202 attachment_count: attachments_vk.len() as u32, 1203 p_attachments: if attachments_vk.is_empty() { 1204 ptr::null() 1205 } else { 1206 attachments_vk.as_ptr() 1207 }, 1208 subpass_count: subpasses_vk.len() as u32, 1209 p_subpasses: if subpasses_vk.is_empty() { 1210 ptr::null() 1211 } else { 1212 subpasses_vk.as_ptr() 1213 }, 1214 dependency_count: dependencies_vk.len() as u32, 1215 p_dependencies: if dependencies_vk.is_empty() { 1216 ptr::null() 1217 } else { 1218 dependencies_vk.as_ptr() 1219 }, 1220 correlated_view_mask_count: correlated_view_masks.len() as u32, 1221 p_correlated_view_masks: correlated_view_masks.as_ptr(), 1222 ..Default::default() 1223 }; 1224 1225 Ok({ 1226 let fns = device.fns(); 1227 let mut output = MaybeUninit::uninit(); 1228 1229 if device.api_version() >= Version::V1_2 { 1230 (fns.v1_2.create_render_pass2)( 1231 device.handle(), 1232 &create_info, 1233 ptr::null(), 1234 output.as_mut_ptr(), 1235 ) 1236 } else { 1237 (fns.khr_create_renderpass2.create_render_pass2_khr)( 1238 device.handle(), 1239 &create_info, 1240 ptr::null(), 1241 output.as_mut_ptr(), 1242 ) 1243 } 1244 .result() 1245 .map_err(VulkanError::from)?; 1246 1247 output.assume_init() 1248 }) 1249 } 1250 create_v1( device: &Device, create_info: &RenderPassCreateInfo, ) -> Result<ash::vk::RenderPass, RenderPassCreationError>1251 pub(super) unsafe fn create_v1( 1252 device: &Device, 1253 create_info: &RenderPassCreateInfo, 1254 ) -> Result<ash::vk::RenderPass, RenderPassCreationError> { 1255 let RenderPassCreateInfo { 1256 attachments, 1257 subpasses, 1258 dependencies, 1259 correlated_view_masks, 1260 _ne: _, 1261 } = create_info; 1262 1263 let attachments_vk = attachments 1264 .iter() 1265 .map(|attachment| ash::vk::AttachmentDescription { 1266 flags: ash::vk::AttachmentDescriptionFlags::empty(), 1267 format: attachment 1268 .format 1269 .map_or(ash::vk::Format::UNDEFINED, |f| f.into()), 1270 samples: attachment.samples.into(), 1271 load_op: attachment.load_op.into(), 1272 store_op: attachment.store_op.into(), 1273 stencil_load_op: attachment.stencil_load_op.into(), 1274 stencil_store_op: attachment.stencil_store_op.into(), 1275 initial_layout: attachment.initial_layout.into(), 1276 final_layout: attachment.final_layout.into(), 1277 }) 1278 .collect::<SmallVec<[_; 4]>>(); 1279 1280 let attachment_references_vk = subpasses 1281 .iter() 1282 .flat_map(|subpass| { 1283 (subpass.input_attachments.iter()) 1284 .chain(subpass.color_attachments.iter()) 1285 .chain(subpass.resolve_attachments.iter()) 1286 .map(Option::as_ref) 1287 .chain(subpass.depth_stencil_attachment.iter().map(Some)) 1288 .map(|atch_ref| { 1289 if let Some(atch_ref) = atch_ref { 1290 ash::vk::AttachmentReference { 1291 attachment: atch_ref.attachment, 1292 layout: atch_ref.layout.into(), 1293 } 1294 } else { 1295 ash::vk::AttachmentReference { 1296 attachment: ash::vk::ATTACHMENT_UNUSED, 1297 layout: Default::default(), 1298 } 1299 } 1300 }) 1301 }) 1302 .collect::<SmallVec<[_; 8]>>(); 1303 1304 let subpasses_vk = { 1305 // `ref_index` is increased during the loop and points to the next element to use 1306 // in `attachment_references_vk`. 1307 let mut ref_index = 0usize; 1308 let out: SmallVec<[_; 4]> = subpasses 1309 .iter() 1310 .map(|subpass| { 1311 let input_attachments = attachment_references_vk.as_ptr().add(ref_index); 1312 ref_index += subpass.input_attachments.len(); 1313 let color_attachments = attachment_references_vk.as_ptr().add(ref_index); 1314 ref_index += subpass.color_attachments.len(); 1315 let resolve_attachments = attachment_references_vk.as_ptr().add(ref_index); 1316 ref_index += subpass.resolve_attachments.len(); 1317 let depth_stencil = if subpass.depth_stencil_attachment.is_some() { 1318 let a = attachment_references_vk.as_ptr().add(ref_index); 1319 ref_index += 1; 1320 a 1321 } else { 1322 ptr::null() 1323 }; 1324 1325 ash::vk::SubpassDescription { 1326 flags: ash::vk::SubpassDescriptionFlags::empty(), 1327 pipeline_bind_point: ash::vk::PipelineBindPoint::GRAPHICS, 1328 input_attachment_count: subpass.input_attachments.len() as u32, 1329 p_input_attachments: if subpass.input_attachments.is_empty() { 1330 ptr::null() 1331 } else { 1332 input_attachments 1333 }, 1334 color_attachment_count: subpass.color_attachments.len() as u32, 1335 p_color_attachments: if subpass.color_attachments.is_empty() { 1336 ptr::null() 1337 } else { 1338 color_attachments 1339 }, 1340 p_resolve_attachments: if subpass.resolve_attachments.is_empty() { 1341 ptr::null() 1342 } else { 1343 resolve_attachments 1344 }, 1345 p_depth_stencil_attachment: depth_stencil, 1346 preserve_attachment_count: subpass.preserve_attachments.len() as u32, 1347 p_preserve_attachments: if subpass.preserve_attachments.is_empty() { 1348 ptr::null() 1349 } else { 1350 subpass.preserve_attachments.as_ptr() 1351 }, 1352 } 1353 }) 1354 .collect(); 1355 1356 // If this assertion fails, there's a serious bug in the code above ^. 1357 debug_assert!(ref_index == attachment_references_vk.len()); 1358 1359 out 1360 }; 1361 1362 let dependencies_vk = dependencies 1363 .iter() 1364 .map(|dependency| ash::vk::SubpassDependency { 1365 src_subpass: dependency.src_subpass.unwrap_or(ash::vk::SUBPASS_EXTERNAL), 1366 dst_subpass: dependency.dst_subpass.unwrap_or(ash::vk::SUBPASS_EXTERNAL), 1367 src_stage_mask: dependency.src_stages.into(), 1368 dst_stage_mask: dependency.dst_stages.into(), 1369 src_access_mask: dependency.src_access.into(), 1370 dst_access_mask: dependency.dst_access.into(), 1371 dependency_flags: dependency.dependency_flags.into(), 1372 }) 1373 .collect::<SmallVec<[_; 4]>>(); 1374 1375 /* Input attachment aspect */ 1376 1377 let input_attachment_aspect_references: SmallVec<[_; 8]> = if device.api_version() 1378 >= Version::V1_1 1379 || device.enabled_extensions().khr_maintenance2 1380 { 1381 subpasses 1382 .iter() 1383 .enumerate() 1384 .flat_map(|(subpass_num, subpass)| { 1385 subpass.input_attachments.iter().enumerate().flat_map( 1386 move |(atch_num, atch_ref)| { 1387 atch_ref.as_ref().map(|atch_ref| { 1388 ash::vk::InputAttachmentAspectReference { 1389 subpass: subpass_num as u32, 1390 input_attachment_index: atch_num as u32, 1391 aspect_mask: atch_ref.aspects.into(), 1392 } 1393 }) 1394 }, 1395 ) 1396 }) 1397 .collect() 1398 } else { 1399 SmallVec::new() 1400 }; 1401 1402 let mut input_attachment_aspect_create_info = 1403 if !input_attachment_aspect_references.is_empty() { 1404 Some(ash::vk::RenderPassInputAttachmentAspectCreateInfo { 1405 aspect_reference_count: input_attachment_aspect_references.len() as u32, 1406 p_aspect_references: input_attachment_aspect_references.as_ptr(), 1407 ..Default::default() 1408 }) 1409 } else { 1410 None 1411 }; 1412 1413 /* Multiview */ 1414 1415 let is_multiview = subpasses[0].view_mask != 0; 1416 1417 let (multiview_view_masks, multiview_view_offsets): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) = 1418 if is_multiview { 1419 ( 1420 subpasses.iter().map(|subpass| subpass.view_mask).collect(), 1421 dependencies 1422 .iter() 1423 .map(|dependency| dependency.view_offset) 1424 .collect(), 1425 ) 1426 } else { 1427 (SmallVec::new(), SmallVec::new()) 1428 }; 1429 1430 let mut multiview_create_info = if is_multiview { 1431 debug_assert!(multiview_view_masks.len() == subpasses.len()); 1432 debug_assert!(multiview_view_offsets.len() == dependencies.len()); 1433 1434 Some(ash::vk::RenderPassMultiviewCreateInfo { 1435 subpass_count: multiview_view_masks.len() as u32, 1436 p_view_masks: multiview_view_masks.as_ptr(), 1437 dependency_count: multiview_view_offsets.len() as u32, 1438 p_view_offsets: multiview_view_offsets.as_ptr(), 1439 correlation_mask_count: correlated_view_masks.len() as u32, 1440 p_correlation_masks: correlated_view_masks.as_ptr(), 1441 ..Default::default() 1442 }) 1443 } else { 1444 None 1445 }; 1446 1447 /* Create */ 1448 1449 let mut create_info = ash::vk::RenderPassCreateInfo { 1450 flags: ash::vk::RenderPassCreateFlags::empty(), 1451 attachment_count: attachments_vk.len() as u32, 1452 p_attachments: if attachments_vk.is_empty() { 1453 ptr::null() 1454 } else { 1455 attachments_vk.as_ptr() 1456 }, 1457 subpass_count: subpasses_vk.len() as u32, 1458 p_subpasses: if subpasses_vk.is_empty() { 1459 ptr::null() 1460 } else { 1461 subpasses_vk.as_ptr() 1462 }, 1463 dependency_count: dependencies_vk.len() as u32, 1464 p_dependencies: if dependencies_vk.is_empty() { 1465 ptr::null() 1466 } else { 1467 dependencies_vk.as_ptr() 1468 }, 1469 ..Default::default() 1470 }; 1471 1472 if let Some(input_attachment_aspect_create_info) = 1473 input_attachment_aspect_create_info.as_mut() 1474 { 1475 input_attachment_aspect_create_info.p_next = create_info.p_next; 1476 create_info.p_next = input_attachment_aspect_create_info as *const _ as *const _; 1477 } 1478 1479 if let Some(multiview_create_info) = multiview_create_info.as_mut() { 1480 multiview_create_info.p_next = create_info.p_next; 1481 create_info.p_next = multiview_create_info as *const _ as *const _; 1482 } 1483 1484 Ok({ 1485 let fns = device.fns(); 1486 let mut output = MaybeUninit::uninit(); 1487 (fns.v1_0.create_render_pass)( 1488 device.handle(), 1489 &create_info, 1490 ptr::null(), 1491 output.as_mut_ptr(), 1492 ) 1493 .result() 1494 .map_err(VulkanError::from)?; 1495 output.assume_init() 1496 }) 1497 } 1498 } 1499 1500 /// Error that can happen when creating a `RenderPass`. 1501 #[derive(Clone, Debug, PartialEq, Eq)] 1502 pub enum RenderPassCreationError { 1503 /// Not enough memory. 1504 OomError(OomError), 1505 1506 RequirementNotMet { 1507 required_for: &'static str, 1508 requires_one_of: RequiresOneOf, 1509 }, 1510 1511 /// An attachment is first used in the render pass with a read-only layout or as an input 1512 /// attachment, but its `load_op` or `stencil_load_op` is [`LoadOp::Clear`]. 1513 AttachmentFirstUseLoadOpInvalid { 1514 attachment: u32, 1515 first_use_subpass: u32, 1516 }, 1517 1518 /// An attachment has an `initial_layout` or `final_layout` value that is invalid for the 1519 /// provided `format`. 1520 AttachmentLayoutInvalid { attachment: u32 }, 1521 1522 /// Correlated view masks were included, but multiview is not enabled on the render pass. 1523 CorrelatedViewMasksMultiviewNotEnabled, 1524 1525 /// The provided correlated view masks contain a bit that is set in more than one element. 1526 CorrelatedViewMasksOverlapping, 1527 1528 /// A subpass dependency specified an access type that was not supported by the given stages. 1529 DependencyAccessNotSupportedByStages { dependency: u32 }, 1530 1531 /// A subpass dependency has both `src_subpass` and `dst_subpass` set to `None`. 1532 DependencyBothSubpassesExternal { dependency: u32 }, 1533 1534 /// A subpass dependency specifies a subpass self-dependency and includes framebuffer stages in 1535 /// both `src_stages` and `dst_stages`, but the `by_region` dependency was not enabled. 1536 DependencySelfDependencyFramebufferStagesWithoutByRegion { dependency: u32 }, 1537 1538 /// A subpass dependency specifies a subpass self-dependency and includes 1539 /// non-framebuffer stages, but the latest stage in `src_stages` is after the earliest stage 1540 /// in `dst_stages`. 1541 DependencySelfDependencySourceStageAfterDestinationStage { dependency: u32 }, 1542 1543 /// A subpass dependency specifies a subpass self-dependency and has the `view_local` dependency 1544 /// enabled, but the inner offset value was not 0. 1545 DependencySelfDependencyViewLocalNonzeroViewOffset { dependency: u32 }, 1546 1547 /// A subpass dependency specifies a subpass self-dependency without the `view_local` 1548 /// dependency, but the referenced subpass has more than one bit set in its `view_mask`. 1549 DependencySelfDependencyViewMaskMultiple { dependency: u32, subpass: u32 }, 1550 1551 /// A subpass dependency has a `src_subpass` that is later than the `dst_subpass`. 1552 DependencySourceSubpassAfterDestinationSubpass { dependency: u32 }, 1553 1554 /// A subpass dependency has a bit set in the `src_stages` or `dst_stages` that is 1555 /// not supported for graphics pipelines. 1556 DependencyStageNotSupported { dependency: u32 }, 1557 1558 /// A subpass index in a subpass dependency is not less than the number of subpasses in the 1559 /// render pass. 1560 DependencySubpassOutOfRange { dependency: u32, subpass: u32 }, 1561 1562 /// In a subpass dependency, `dependency_flags` contains [`VIEW_LOCAL`], but `src_subpass` or 1563 /// `dst_subpass` were set to `None`. 1564 /// 1565 /// [`VIEW_LOCAL`]: crate::sync::DependencyFlags::VIEW_LOCAL 1566 DependencyViewLocalExternalDependency { dependency: u32 }, 1567 1568 /// In a subpass dependency, `dependency_flags` contains [`VIEW_LOCAL`], but multiview is not 1569 /// enabled on the render pass. 1570 /// 1571 /// [`VIEW_LOCAL`]: crate::sync::DependencyFlags::VIEW_LOCAL 1572 DependencyViewLocalMultiviewNotEnabled { dependency: u32 }, 1573 1574 /// In a subpass dependency, `view_offset` is not zero, but `dependency_flags` does not contain 1575 /// [`VIEW_LOCAL`]. 1576 /// 1577 /// [`VIEW_LOCAL`]: crate::sync::DependencyFlags::VIEW_LOCAL 1578 DependencyViewOffzetNonzeroWithoutViewLocal { dependency: u32 }, 1579 1580 /// A reference to an attachment used other than as an input attachment in a subpass has 1581 /// one or more aspects selected. 1582 SubpassAttachmentAspectsNotEmpty { subpass: u32, attachment: u32 }, 1583 1584 /// An attachment used as an attachment in a subpass has a layout that is not supported for 1585 /// that usage. 1586 SubpassAttachmentLayoutInvalid { 1587 subpass: u32, 1588 attachment: u32, 1589 usage: &'static str, 1590 }, 1591 1592 /// The layouts of all uses of an attachment in a subpass do not match. 1593 SubpassAttachmentLayoutMismatch { subpass: u32, attachment: u32 }, 1594 1595 /// An attachment index in a subpass is not less than the number of attachments in the render 1596 /// pass. 1597 SubpassAttachmentOutOfRange { subpass: u32, attachment: u32 }, 1598 1599 /// An attachment is used as both a color attachment and a depth/stencil attachment in a 1600 /// subpass. 1601 SubpassAttachmentUsageColorDepthStencil { subpass: u32, attachment: u32 }, 1602 1603 /// An attachment used as an attachment in a subpass has a format that does not support that 1604 /// usage. 1605 SubpassAttachmentFormatUsageNotSupported { 1606 subpass: u32, 1607 attachment: u32, 1608 usage: &'static str, 1609 }, 1610 1611 /// An attachment used as a color attachment in a subpass with resolve attachments has a 1612 /// `samples` value of [`SampleCount::Sample1`]. 1613 SubpassColorAttachmentWithResolveNotMultisampled { subpass: u32, attachment: u32 }, 1614 1615 /// An attachment used as a color or depth/stencil attachment in a subpass has a `samples` value 1616 /// that is different from the first color attachment. 1617 SubpassColorDepthStencilAttachmentSamplesMismatch { 1618 subpass: u32, 1619 attachment: u32, 1620 samples: SampleCount, 1621 first_samples: SampleCount, 1622 }, 1623 1624 /// A reference to an attachment used as an input attachment in a subpass selects aspects that 1625 /// are not present in the format of the attachment. 1626 SubpassInputAttachmentAspectsNotCompatible { subpass: u32, attachment: u32 }, 1627 1628 /// The `max_color_attachments` limit has been exceeded for a subpass. 1629 SubpassMaxColorAttachmentsExceeded { 1630 subpass: u32, 1631 color_attachment_count: u32, 1632 max: u32, 1633 }, 1634 1635 /// The `max_multiview_view_count` limit has been exceeded for a subpass. 1636 SubpassMaxMultiviewViewCountExceeded { 1637 subpass: u32, 1638 view_count: u32, 1639 max: u32, 1640 }, 1641 1642 /// The multiview state (whether `view_mask` is nonzero) of a subpass is different from the 1643 /// first subpass. 1644 SubpassMultiviewMismatch { 1645 subpass: u32, 1646 multiview: bool, 1647 first_subpass_multiview: bool, 1648 }, 1649 1650 /// An attachment marked as a preserve attachment in a subpass is also used as an attachment 1651 /// in that subpass. 1652 SubpassPreserveAttachmentUsedElsewhere { subpass: u32, attachment: u32 }, 1653 1654 /// The `resolve_attachments` field of a subpass was not empty, but its length did not match 1655 /// the length of `color_attachments`. 1656 SubpassResolveAttachmentsColorAttachmentsLenMismatch { subpass: u32 }, 1657 1658 /// An attachment used as a resolve attachment in a subpass has a `format` value different from 1659 /// the corresponding color attachment. 1660 SubpassResolveAttachmentFormatMismatch { 1661 subpass: u32, 1662 resolve_attachment: u32, 1663 color_attachment: u32, 1664 }, 1665 1666 /// An attachment used as a resolve attachment in a subpass has a `samples` value other than 1667 /// [`SampleCount::Sample1`]. 1668 SubpassResolveAttachmentMultisampled { subpass: u32, attachment: u32 }, 1669 1670 /// A resolve attachment in a subpass is `Some`, but the corresponding color attachment is 1671 /// `None`. 1672 SubpassResolveAttachmentWithoutColorAttachment { subpass: u32 }, 1673 } 1674 1675 impl Error for RenderPassCreationError { source(&self) -> Option<&(dyn Error + 'static)>1676 fn source(&self) -> Option<&(dyn Error + 'static)> { 1677 match self { 1678 RenderPassCreationError::OomError(err) => Some(err), 1679 _ => None, 1680 } 1681 } 1682 } 1683 1684 impl Display for RenderPassCreationError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1685 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 1686 match self { 1687 Self::OomError(_) => write!(f, "not enough memory available"), 1688 Self::RequirementNotMet { 1689 required_for, 1690 requires_one_of, 1691 } => write!( 1692 f, 1693 "a requirement was not met for: {}; requires one of: {}", 1694 required_for, requires_one_of, 1695 ), 1696 Self::AttachmentFirstUseLoadOpInvalid { 1697 attachment, 1698 first_use_subpass, 1699 } => write!( 1700 f, 1701 "attachment {} is first used in the render pass in subpass {} with a read-only \ 1702 layout or as an input attachment, but its `load_op` or `stencil_load_op` is \ 1703 `LoadOp::Clear`", 1704 attachment, first_use_subpass, 1705 ), 1706 Self::AttachmentLayoutInvalid { attachment } => write!( 1707 f, 1708 "attachment {} has an `initial_layout` or `final_layout` value that is invalid for \ 1709 the provided `format`", 1710 attachment, 1711 ), 1712 Self::CorrelatedViewMasksMultiviewNotEnabled => write!( 1713 f, 1714 "correlated view masks were included, but multiview is not enabled on the render \ 1715 pass", 1716 ), 1717 Self::CorrelatedViewMasksOverlapping => write!( 1718 f, 1719 "the provided correlated view masks contain a bit that is set in more than one \ 1720 element", 1721 ), 1722 Self::DependencyAccessNotSupportedByStages { dependency } => write!( 1723 f, 1724 "subpass dependency {} specified an access type that was not supported by the \ 1725 given stages", 1726 dependency, 1727 ), 1728 Self::DependencySelfDependencyFramebufferStagesWithoutByRegion { dependency } => { 1729 write!( 1730 f, 1731 "subpass dependency {} specifies a subpass self-dependency and includes \ 1732 framebuffer stages in both `src_stages` and `dst_stages`, but the \ 1733 `by_region` dependency was not enabled", 1734 dependency, 1735 ) 1736 } 1737 Self::DependencySelfDependencySourceStageAfterDestinationStage { dependency } => { 1738 write!( 1739 f, 1740 "subpass dependency {} specifies a subpass self-dependency and includes \ 1741 non-framebuffer stages, but the latest stage in `src_stages` is after the \ 1742 earliest stage in `dst_stages`", 1743 dependency, 1744 ) 1745 } 1746 Self::DependencySelfDependencyViewLocalNonzeroViewOffset { dependency } => write!( 1747 f, 1748 "subpass dependency {} specifies a subpass self-dependency and has the \ 1749 `view_local` dependency enabled, but the inner offset value was not 0", 1750 dependency, 1751 ), 1752 Self::DependencySelfDependencyViewMaskMultiple { 1753 dependency, 1754 subpass, 1755 } => write!( 1756 f, 1757 "subpass dependency {} specifies a subpass self-dependency without the \ 1758 `view_local` dependency, but the referenced subpass {} has more than one bit set \ 1759 in its `view_mask`", 1760 dependency, subpass, 1761 ), 1762 Self::DependencySourceSubpassAfterDestinationSubpass { dependency } => write!( 1763 f, 1764 "subpass dependency {} has a `src_subpass` that is later than the \ 1765 `dst_subpass`", 1766 dependency, 1767 ), 1768 Self::DependencyStageNotSupported { dependency } => write!( 1769 f, 1770 "subpass dependency {} has a bit set in the `src_stages` or \ 1771 `dst_stages` that is not supported for graphics pipelines", 1772 dependency, 1773 ), 1774 Self::DependencyBothSubpassesExternal { dependency } => write!( 1775 f, 1776 "subpass dependency {} has both `src_subpass` and `dst_subpass` set to \ 1777 `None`", 1778 dependency, 1779 ), 1780 Self::DependencySubpassOutOfRange { 1781 dependency, 1782 subpass, 1783 } => write!( 1784 f, 1785 "the subpass index {} in subpass dependency {} is not less than the number of \ 1786 subpasses in the render pass", 1787 subpass, dependency, 1788 ), 1789 Self::DependencyViewLocalExternalDependency { dependency } => write!( 1790 f, 1791 "in subpass dependency {}, `dependency_flags` contains `VIEW_LOCAL`, but \ 1792 `src_subpass` or `dst_subpass` were set to `None`", 1793 dependency, 1794 ), 1795 Self::DependencyViewLocalMultiviewNotEnabled { dependency } => write!( 1796 f, 1797 "in subpass dependency {}, `dependency_flags` contains `VIEW_LOCAL`, but \ 1798 multiview is not enabled on the render pass", 1799 dependency, 1800 ), 1801 Self::DependencyViewOffzetNonzeroWithoutViewLocal { dependency } => write!( 1802 f, 1803 "in subpass dependency {}, `view_offset` is not zero, but `dependency_flags` does \ 1804 not contain `VIEW_LOCAL`", 1805 dependency, 1806 ), 1807 Self::SubpassAttachmentAspectsNotEmpty { 1808 subpass, 1809 attachment, 1810 } => write!( 1811 f, 1812 "a reference to attachment {} used other than as an input attachment in subpass {} \ 1813 has one or more aspects selected", 1814 attachment, subpass, 1815 ), 1816 Self::SubpassAttachmentLayoutMismatch { 1817 subpass, 1818 attachment, 1819 } => write!( 1820 f, 1821 "the layouts of all uses of attachment {} in subpass {} do not match.", 1822 attachment, subpass, 1823 ), 1824 Self::SubpassAttachmentLayoutInvalid { 1825 subpass, 1826 attachment, 1827 usage, 1828 } => write!( 1829 f, 1830 "attachment {} used as {} attachment in subpass {} has a layout that is not \ 1831 supported for that usage", 1832 attachment, usage, subpass, 1833 ), 1834 Self::SubpassAttachmentOutOfRange { 1835 subpass, 1836 attachment, 1837 } => write!( 1838 f, 1839 "the attachment index {} in subpass {} is not less than the number of attachments \ 1840 in the render pass", 1841 attachment, subpass, 1842 ), 1843 Self::SubpassAttachmentUsageColorDepthStencil { 1844 subpass, 1845 attachment, 1846 } => write!( 1847 f, 1848 "attachment {} is used as both a color attachment and a depth/stencil attachment \ 1849 in subpass {}", 1850 attachment, subpass, 1851 ), 1852 Self::SubpassAttachmentFormatUsageNotSupported { 1853 subpass, 1854 attachment, 1855 usage, 1856 } => write!( 1857 f, 1858 "attachment {} used as {} attachment in subpass {} has a format that does not \ 1859 support that usage", 1860 attachment, usage, subpass, 1861 ), 1862 Self::SubpassColorAttachmentWithResolveNotMultisampled { 1863 subpass, 1864 attachment, 1865 } => write!( 1866 f, 1867 "attachment {} used as a color attachment in subpass {} with resolve attachments \ 1868 has a `samples` value of `SampleCount::Sample1`", 1869 attachment, subpass, 1870 ), 1871 Self::SubpassColorDepthStencilAttachmentSamplesMismatch { 1872 subpass, 1873 attachment, 1874 samples, 1875 first_samples, 1876 } => write!( 1877 f, 1878 "attachment {} used as a color or depth/stencil attachment in subpass {} has a \ 1879 `samples` value {:?} that is different from the first color attachment ({:?})", 1880 attachment, subpass, samples, first_samples, 1881 ), 1882 Self::SubpassInputAttachmentAspectsNotCompatible { 1883 subpass, 1884 attachment, 1885 } => write!( 1886 f, 1887 "a reference to attachment {} used as an input attachment in subpass {} selects \ 1888 aspects that are not present in the format of the attachment", 1889 attachment, subpass, 1890 ), 1891 Self::SubpassMaxColorAttachmentsExceeded { .. } => { 1892 write!(f, "the `max_color_attachments` limit has been exceeded") 1893 } 1894 Self::SubpassMaxMultiviewViewCountExceeded { .. } => write!( 1895 f, 1896 "the `max_multiview_view_count` limit has been exceeded for a subpass", 1897 ), 1898 Self::SubpassMultiviewMismatch { 1899 subpass, 1900 multiview, 1901 first_subpass_multiview, 1902 } => write!( 1903 f, 1904 "the multiview state (whether `view_mask` is nonzero) of subpass {} is {}, which \ 1905 is different from the first subpass ({})", 1906 subpass, multiview, first_subpass_multiview, 1907 ), 1908 Self::SubpassPreserveAttachmentUsedElsewhere { 1909 subpass, 1910 attachment, 1911 } => write!( 1912 f, 1913 "attachment {} marked as a preserve attachment in subpass {} is also used as an \ 1914 attachment in that subpass", 1915 attachment, subpass, 1916 ), 1917 Self::SubpassResolveAttachmentsColorAttachmentsLenMismatch { subpass } => write!( 1918 f, 1919 "the `resolve_attachments` field of subpass {} was not empty, but its length did \ 1920 not match the length of `color_attachments`", 1921 subpass, 1922 ), 1923 Self::SubpassResolveAttachmentFormatMismatch { 1924 subpass, 1925 resolve_attachment, 1926 color_attachment, 1927 } => write!( 1928 f, 1929 "attachment {} used as a resolve attachment in subpass {} has a `format` value \ 1930 different from the corresponding color attachment {}", 1931 subpass, resolve_attachment, color_attachment, 1932 ), 1933 Self::SubpassResolveAttachmentMultisampled { 1934 subpass, 1935 attachment, 1936 } => write!( 1937 f, 1938 "attachment {} used as a resolve attachment in subpass {} has a `samples` value \ 1939 other than `SampleCount::Sample1`", 1940 attachment, subpass, 1941 ), 1942 Self::SubpassResolveAttachmentWithoutColorAttachment { subpass } => write!( 1943 f, 1944 "a resolve attachment in subpass {} is `Some`, but the corresponding color \ 1945 attachment is `None`", 1946 subpass, 1947 ), 1948 } 1949 } 1950 } 1951 1952 impl From<OomError> for RenderPassCreationError { from(err: OomError) -> RenderPassCreationError1953 fn from(err: OomError) -> RenderPassCreationError { 1954 RenderPassCreationError::OomError(err) 1955 } 1956 } 1957 1958 impl From<VulkanError> for RenderPassCreationError { from(err: VulkanError) -> RenderPassCreationError1959 fn from(err: VulkanError) -> RenderPassCreationError { 1960 match err { 1961 err @ VulkanError::OutOfHostMemory => { 1962 RenderPassCreationError::OomError(OomError::from(err)) 1963 } 1964 err @ VulkanError::OutOfDeviceMemory => { 1965 RenderPassCreationError::OomError(OomError::from(err)) 1966 } 1967 _ => panic!("unexpected error: {:?}", err), 1968 } 1969 } 1970 } 1971 1972 impl From<RequirementNotMet> for RenderPassCreationError { from(err: RequirementNotMet) -> Self1973 fn from(err: RequirementNotMet) -> Self { 1974 Self::RequirementNotMet { 1975 required_for: err.required_for, 1976 requires_one_of: err.requires_one_of, 1977 } 1978 } 1979 } 1980