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 //! The layout of descriptor sets and push constants used by a pipeline. 11 //! 12 //! # Overview 13 //! 14 //! The layout itself only *describes* the descriptors and push constants, and does not contain 15 //! their content itself. Instead, you can think of it as a `struct` definition that states which 16 //! members there are, what types they have, and in what order. 17 //! One could imagine a Rust definition somewhat like this: 18 //! 19 //! ```text 20 //! #[repr(C)] 21 //! struct MyPipelineLayout { 22 //! push_constants: Pc, 23 //! descriptor_set0: Ds0, 24 //! descriptor_set1: Ds1, 25 //! descriptor_set2: Ds2, 26 //! descriptor_set3: Ds3, 27 //! } 28 //! ``` 29 //! 30 //! Of course, a pipeline layout is created at runtime, unlike a Rust type. 31 //! 32 //! # Layout compatibility 33 //! 34 //! When binding descriptor sets or setting push constants, you must provide a pipeline layout. 35 //! This layout is used to decide where in memory Vulkan should write the new data. The 36 //! descriptor sets and push constants can later be read by dispatch or draw calls, but only if 37 //! the bound pipeline being used for the command has a layout that is *compatible* with the layout 38 //! that was used to bind the resources. 39 //! 40 //! *Compatible* means that the pipeline layout must be the same object, or a different layout in 41 //! which the push constant ranges and descriptor set layouts were be identically defined. 42 //! However, Vulkan allows for partial compatibility as well. In the `struct` analogy used above, 43 //! one could imagine that using a different definition would leave some members with the same 44 //! offset and size within the struct as in the old definition, while others are no longer 45 //! positioned correctly. For example, if a new, incompatible type were used for `Ds1`, then the 46 //! `descriptor_set1`, `descriptor_set2` and `descriptor_set3` members would no longer be correct, 47 //! but `descriptor_set0` and `push_constants` would remain accessible in the new layout. 48 //! Because of this behaviour, the following rules apply to compatibility between the layouts used 49 //! in subsequent descriptor set binding calls: 50 //! 51 //! - An incompatible definition of `Pc` invalidates all bound descriptor sets. 52 //! - An incompatible definition of `DsN` invalidates all bound descriptor sets *N* and higher. 53 //! - If *N* is the highest set being assigned in a bind command, and it and all lower sets 54 //! have compatible definitions, including the push constants, then descriptor sets above *N* 55 //! remain valid. 56 //! 57 //! [`SyncCommandBufferBuilder`](crate::command_buffer::synced::SyncCommandBufferBuilder) keeps 58 //! track of this state and will automatically remove descriptor sets that have been invalidated 59 //! by incompatible layouts in subsequent binding commands. 60 //! 61 //! # Creating pipeline layouts 62 //! 63 //! A pipeline layout is a Vulkan object type, represented in Vulkano with the `PipelineLayout` 64 //! type. Each pipeline that you create holds a pipeline layout object. 65 66 use crate::{ 67 descriptor_set::layout::{DescriptorRequirementsNotMet, DescriptorSetLayout, DescriptorType}, 68 device::{Device, DeviceOwned}, 69 macros::impl_id_counter, 70 shader::{DescriptorBindingRequirements, ShaderStages}, 71 OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject, 72 }; 73 use smallvec::SmallVec; 74 use std::{ 75 error::Error, 76 fmt::{Display, Error as FmtError, Formatter}, 77 mem::MaybeUninit, 78 num::NonZeroU64, 79 ptr, 80 sync::Arc, 81 }; 82 83 /// Describes the layout of descriptor sets and push constants that are made available to shaders. 84 #[derive(Debug)] 85 pub struct PipelineLayout { 86 handle: ash::vk::PipelineLayout, 87 device: Arc<Device>, 88 id: NonZeroU64, 89 90 set_layouts: Vec<Arc<DescriptorSetLayout>>, 91 push_constant_ranges: Vec<PushConstantRange>, 92 93 push_constant_ranges_disjoint: Vec<PushConstantRange>, 94 } 95 96 impl PipelineLayout { 97 /// Creates a new `PipelineLayout`. 98 /// 99 /// # Panics 100 /// 101 /// - Panics if an element of `create_info.push_constant_ranges` has an empty `stages` value. 102 /// - Panics if an element of `create_info.push_constant_ranges` has an `offset` or `size` 103 /// that's not divisible by 4. 104 /// - Panics if an element of `create_info.push_constant_ranges` has an `size` of zero. new( device: Arc<Device>, mut create_info: PipelineLayoutCreateInfo, ) -> Result<Arc<PipelineLayout>, PipelineLayoutCreationError>105 pub fn new( 106 device: Arc<Device>, 107 mut create_info: PipelineLayoutCreateInfo, 108 ) -> Result<Arc<PipelineLayout>, PipelineLayoutCreationError> { 109 Self::validate(&device, &mut create_info)?; 110 let handle = unsafe { Self::create(&device, &create_info)? }; 111 112 let PipelineLayoutCreateInfo { 113 set_layouts, 114 mut push_constant_ranges, 115 _ne: _, 116 } = create_info; 117 118 // Sort the ranges for the purpose of comparing for equality. 119 // The stage mask is guaranteed to be unique, so it's a suitable sorting key. 120 push_constant_ranges.sort_unstable_by_key(|range| { 121 ( 122 range.offset, 123 range.size, 124 ash::vk::ShaderStageFlags::from(range.stages), 125 ) 126 }); 127 128 let push_constant_ranges_disjoint = 129 Self::create_push_constant_ranges_disjoint(&push_constant_ranges); 130 131 Ok(Arc::new(PipelineLayout { 132 handle, 133 device, 134 id: Self::next_id(), 135 set_layouts, 136 push_constant_ranges, 137 push_constant_ranges_disjoint, 138 })) 139 } 140 create_push_constant_ranges_disjoint( push_constant_ranges: &Vec<PushConstantRange>, ) -> Vec<PushConstantRange>141 fn create_push_constant_ranges_disjoint( 142 push_constant_ranges: &Vec<PushConstantRange>, 143 ) -> Vec<PushConstantRange> { 144 let mut push_constant_ranges_disjoint: Vec<PushConstantRange> = 145 Vec::with_capacity(push_constant_ranges.len()); 146 147 if !push_constant_ranges.is_empty() { 148 let mut min_offset = push_constant_ranges[0].offset; 149 loop { 150 let mut max_offset = u32::MAX; 151 let mut stages = ShaderStages::empty(); 152 153 for range in push_constant_ranges.iter() { 154 // new start (begin next time from it) 155 if range.offset > min_offset { 156 max_offset = max_offset.min(range.offset); 157 break; 158 } else if range.offset + range.size > min_offset { 159 // inside the range, include the stage 160 // use the minimum of the end of all ranges that are overlapping 161 max_offset = max_offset.min(range.offset + range.size); 162 stages |= range.stages; 163 } 164 } 165 // finished all stages 166 if stages.is_empty() { 167 break; 168 } 169 170 push_constant_ranges_disjoint.push(PushConstantRange { 171 stages, 172 offset: min_offset, 173 size: max_offset - min_offset, 174 }); 175 // prepare for next range 176 min_offset = max_offset; 177 } 178 } 179 push_constant_ranges_disjoint 180 } 181 validate( device: &Device, create_info: &mut PipelineLayoutCreateInfo, ) -> Result<(), PipelineLayoutCreationError>182 fn validate( 183 device: &Device, 184 create_info: &mut PipelineLayoutCreateInfo, 185 ) -> Result<(), PipelineLayoutCreationError> { 186 let &mut PipelineLayoutCreateInfo { 187 ref set_layouts, 188 ref push_constant_ranges, 189 _ne: _, 190 } = create_info; 191 192 let properties = device.physical_device().properties(); 193 194 /* Check descriptor set layouts */ 195 196 // VUID-VkPipelineLayoutCreateInfo-setLayoutCount-00286 197 if set_layouts.len() > properties.max_bound_descriptor_sets as usize { 198 return Err( 199 PipelineLayoutCreationError::MaxBoundDescriptorSetsExceeded { 200 provided: set_layouts.len() as u32, 201 max_supported: properties.max_bound_descriptor_sets, 202 }, 203 ); 204 } 205 206 { 207 let mut num_resources = Counter::default(); 208 let mut num_samplers = Counter::default(); 209 let mut num_uniform_buffers = Counter::default(); 210 let mut num_uniform_buffers_dynamic = 0; 211 let mut num_storage_buffers = Counter::default(); 212 let mut num_storage_buffers_dynamic = 0; 213 let mut num_sampled_images = Counter::default(); 214 let mut num_storage_images = Counter::default(); 215 let mut num_input_attachments = Counter::default(); 216 let mut push_descriptor_set = None; 217 218 for (set_num, set_layout) in set_layouts.iter().enumerate() { 219 let set_num = set_num as u32; 220 221 if set_layout.push_descriptor() { 222 // VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00293 223 if push_descriptor_set.is_some() { 224 return Err(PipelineLayoutCreationError::SetLayoutsPushDescriptorMultiple); 225 } else { 226 push_descriptor_set = Some(set_num); 227 } 228 } 229 230 for layout_binding in set_layout.bindings().values() { 231 num_resources.increment(layout_binding.descriptor_count, layout_binding.stages); 232 233 match layout_binding.descriptor_type { 234 DescriptorType::Sampler => { 235 num_samplers 236 .increment(layout_binding.descriptor_count, layout_binding.stages); 237 } 238 DescriptorType::CombinedImageSampler => { 239 num_samplers 240 .increment(layout_binding.descriptor_count, layout_binding.stages); 241 num_sampled_images 242 .increment(layout_binding.descriptor_count, layout_binding.stages); 243 } 244 DescriptorType::SampledImage | DescriptorType::UniformTexelBuffer => { 245 num_sampled_images 246 .increment(layout_binding.descriptor_count, layout_binding.stages); 247 } 248 DescriptorType::StorageImage | DescriptorType::StorageTexelBuffer => { 249 num_storage_images 250 .increment(layout_binding.descriptor_count, layout_binding.stages); 251 } 252 DescriptorType::UniformBuffer => { 253 num_uniform_buffers 254 .increment(layout_binding.descriptor_count, layout_binding.stages); 255 } 256 DescriptorType::UniformBufferDynamic => { 257 num_uniform_buffers 258 .increment(layout_binding.descriptor_count, layout_binding.stages); 259 num_uniform_buffers_dynamic += 1; 260 } 261 DescriptorType::StorageBuffer => { 262 num_storage_buffers 263 .increment(layout_binding.descriptor_count, layout_binding.stages); 264 } 265 DescriptorType::StorageBufferDynamic => { 266 num_storage_buffers 267 .increment(layout_binding.descriptor_count, layout_binding.stages); 268 num_storage_buffers_dynamic += 1; 269 } 270 DescriptorType::InputAttachment => { 271 num_input_attachments 272 .increment(layout_binding.descriptor_count, layout_binding.stages); 273 } 274 } 275 } 276 } 277 278 if num_resources.max_per_stage() > properties.max_per_stage_resources { 279 return Err(PipelineLayoutCreationError::MaxPerStageResourcesExceeded { 280 provided: num_resources.max_per_stage(), 281 max_supported: properties.max_per_stage_resources, 282 }); 283 } 284 285 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03016 286 if num_samplers.max_per_stage() > properties.max_per_stage_descriptor_samplers { 287 return Err( 288 PipelineLayoutCreationError::MaxPerStageDescriptorSamplersExceeded { 289 provided: num_samplers.max_per_stage(), 290 max_supported: properties.max_per_stage_descriptor_samplers, 291 }, 292 ); 293 } 294 295 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03017 296 if num_uniform_buffers.max_per_stage() 297 > properties.max_per_stage_descriptor_uniform_buffers 298 { 299 return Err( 300 PipelineLayoutCreationError::MaxPerStageDescriptorUniformBuffersExceeded { 301 provided: num_uniform_buffers.max_per_stage(), 302 max_supported: properties.max_per_stage_descriptor_uniform_buffers, 303 }, 304 ); 305 } 306 307 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03018 308 if num_storage_buffers.max_per_stage() 309 > properties.max_per_stage_descriptor_storage_buffers 310 { 311 return Err( 312 PipelineLayoutCreationError::MaxPerStageDescriptorStorageBuffersExceeded { 313 provided: num_storage_buffers.max_per_stage(), 314 max_supported: properties.max_per_stage_descriptor_storage_buffers, 315 }, 316 ); 317 } 318 319 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03019 320 if num_sampled_images.max_per_stage() 321 > properties.max_per_stage_descriptor_sampled_images 322 { 323 return Err( 324 PipelineLayoutCreationError::MaxPerStageDescriptorSampledImagesExceeded { 325 provided: num_sampled_images.max_per_stage(), 326 max_supported: properties.max_per_stage_descriptor_sampled_images, 327 }, 328 ); 329 } 330 331 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03020 332 if num_storage_images.max_per_stage() 333 > properties.max_per_stage_descriptor_storage_images 334 { 335 return Err( 336 PipelineLayoutCreationError::MaxPerStageDescriptorStorageImagesExceeded { 337 provided: num_storage_images.max_per_stage(), 338 max_supported: properties.max_per_stage_descriptor_storage_images, 339 }, 340 ); 341 } 342 343 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03021 344 if num_input_attachments.max_per_stage() 345 > properties.max_per_stage_descriptor_input_attachments 346 { 347 return Err( 348 PipelineLayoutCreationError::MaxPerStageDescriptorInputAttachmentsExceeded { 349 provided: num_input_attachments.max_per_stage(), 350 max_supported: properties.max_per_stage_descriptor_input_attachments, 351 }, 352 ); 353 } 354 355 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03028 356 if num_samplers.total > properties.max_descriptor_set_samplers { 357 return Err( 358 PipelineLayoutCreationError::MaxDescriptorSetSamplersExceeded { 359 provided: num_samplers.total, 360 max_supported: properties.max_descriptor_set_samplers, 361 }, 362 ); 363 } 364 365 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03029 366 if num_uniform_buffers.total > properties.max_descriptor_set_uniform_buffers { 367 return Err( 368 PipelineLayoutCreationError::MaxDescriptorSetUniformBuffersExceeded { 369 provided: num_uniform_buffers.total, 370 max_supported: properties.max_descriptor_set_uniform_buffers, 371 }, 372 ); 373 } 374 375 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03030 376 if num_uniform_buffers_dynamic > properties.max_descriptor_set_uniform_buffers_dynamic { 377 return Err( 378 PipelineLayoutCreationError::MaxDescriptorSetUniformBuffersDynamicExceeded { 379 provided: num_uniform_buffers_dynamic, 380 max_supported: properties.max_descriptor_set_uniform_buffers_dynamic, 381 }, 382 ); 383 } 384 385 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03031 386 if num_storage_buffers.total > properties.max_descriptor_set_storage_buffers { 387 return Err( 388 PipelineLayoutCreationError::MaxDescriptorSetStorageBuffersExceeded { 389 provided: num_storage_buffers.total, 390 max_supported: properties.max_descriptor_set_storage_buffers, 391 }, 392 ); 393 } 394 395 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03032 396 if num_storage_buffers_dynamic > properties.max_descriptor_set_storage_buffers_dynamic { 397 return Err( 398 PipelineLayoutCreationError::MaxDescriptorSetStorageBuffersDynamicExceeded { 399 provided: num_storage_buffers_dynamic, 400 max_supported: properties.max_descriptor_set_storage_buffers_dynamic, 401 }, 402 ); 403 } 404 405 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03033 406 if num_sampled_images.total > properties.max_descriptor_set_sampled_images { 407 return Err( 408 PipelineLayoutCreationError::MaxDescriptorSetSampledImagesExceeded { 409 provided: num_sampled_images.total, 410 max_supported: properties.max_descriptor_set_sampled_images, 411 }, 412 ); 413 } 414 415 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03034 416 if num_storage_images.total > properties.max_descriptor_set_storage_images { 417 return Err( 418 PipelineLayoutCreationError::MaxDescriptorSetStorageImagesExceeded { 419 provided: num_storage_images.total, 420 max_supported: properties.max_descriptor_set_storage_images, 421 }, 422 ); 423 } 424 425 // VUID-VkPipelineLayoutCreateInfo-descriptorType-03035 426 if num_input_attachments.total > properties.max_descriptor_set_input_attachments { 427 return Err( 428 PipelineLayoutCreationError::MaxDescriptorSetInputAttachmentsExceeded { 429 provided: num_input_attachments.total, 430 max_supported: properties.max_descriptor_set_input_attachments, 431 }, 432 ); 433 } 434 } 435 436 /* Check push constant ranges */ 437 438 push_constant_ranges 439 .iter() 440 .try_fold(ShaderStages::empty(), |total, range| { 441 let &PushConstantRange { 442 stages, 443 offset, 444 size, 445 } = range; 446 447 // VUID-VkPushConstantRange-stageFlags-parameter 448 stages.validate_device(device)?; 449 450 // VUID-VkPushConstantRange-stageFlags-requiredbitmask 451 assert!(!stages.is_empty()); 452 453 // VUID-VkPushConstantRange-offset-00295 454 assert!(offset % 4 == 0); 455 456 // VUID-VkPushConstantRange-size-00296 457 assert!(size != 0); 458 459 // VUID-VkPushConstantRange-size-00297 460 assert!(size % 4 == 0); 461 462 // VUID-VkPushConstantRange-offset-00294 463 // VUID-VkPushConstantRange-size-00298 464 if offset + size > properties.max_push_constants_size { 465 return Err(PipelineLayoutCreationError::MaxPushConstantsSizeExceeded { 466 provided: offset + size, 467 max_supported: properties.max_push_constants_size, 468 }); 469 } 470 471 // VUID-VkPipelineLayoutCreateInfo-pPushConstantRanges-00292 472 if !(total & stages).is_empty() { 473 return Err(PipelineLayoutCreationError::PushConstantRangesStageMultiple); 474 } 475 476 Ok(total | stages) 477 })?; 478 479 Ok(()) 480 } 481 create( device: &Device, create_info: &PipelineLayoutCreateInfo, ) -> Result<ash::vk::PipelineLayout, PipelineLayoutCreationError>482 unsafe fn create( 483 device: &Device, 484 create_info: &PipelineLayoutCreateInfo, 485 ) -> Result<ash::vk::PipelineLayout, PipelineLayoutCreationError> { 486 let PipelineLayoutCreateInfo { 487 set_layouts, 488 push_constant_ranges, 489 _ne: _, 490 } = create_info; 491 492 let set_layouts: SmallVec<[_; 4]> = set_layouts.iter().map(|l| l.handle()).collect(); 493 494 let push_constant_ranges: SmallVec<[_; 4]> = push_constant_ranges 495 .iter() 496 .map(|range| ash::vk::PushConstantRange { 497 stage_flags: range.stages.into(), 498 offset: range.offset, 499 size: range.size, 500 }) 501 .collect(); 502 503 let create_info = ash::vk::PipelineLayoutCreateInfo { 504 flags: ash::vk::PipelineLayoutCreateFlags::empty(), 505 set_layout_count: set_layouts.len() as u32, 506 p_set_layouts: set_layouts.as_ptr(), 507 push_constant_range_count: push_constant_ranges.len() as u32, 508 p_push_constant_ranges: push_constant_ranges.as_ptr(), 509 ..Default::default() 510 }; 511 512 let handle = { 513 let fns = device.fns(); 514 let mut output = MaybeUninit::uninit(); 515 (fns.v1_0.create_pipeline_layout)( 516 device.handle(), 517 &create_info, 518 ptr::null(), 519 output.as_mut_ptr(), 520 ) 521 .result() 522 .map_err(VulkanError::from)?; 523 output.assume_init() 524 }; 525 526 Ok(handle) 527 } 528 529 /// Creates a new `PipelineLayout` from a raw object handle. 530 /// 531 /// # Safety 532 /// 533 /// - `handle` must be a valid Vulkan object handle created from `device`. 534 /// - `create_info` must match the info used to create the object. 535 #[inline] from_handle( device: Arc<Device>, handle: ash::vk::PipelineLayout, create_info: PipelineLayoutCreateInfo, ) -> Arc<PipelineLayout>536 pub unsafe fn from_handle( 537 device: Arc<Device>, 538 handle: ash::vk::PipelineLayout, 539 create_info: PipelineLayoutCreateInfo, 540 ) -> Arc<PipelineLayout> { 541 let PipelineLayoutCreateInfo { 542 set_layouts, 543 push_constant_ranges, 544 _ne: _, 545 } = create_info; 546 547 let push_constant_ranges_disjoint = 548 Self::create_push_constant_ranges_disjoint(&push_constant_ranges); 549 550 Arc::new(PipelineLayout { 551 handle, 552 device, 553 id: Self::next_id(), 554 set_layouts, 555 push_constant_ranges, 556 push_constant_ranges_disjoint, 557 }) 558 } 559 560 /// Returns the descriptor set layouts this pipeline layout was created from. 561 #[inline] set_layouts(&self) -> &[Arc<DescriptorSetLayout>]562 pub fn set_layouts(&self) -> &[Arc<DescriptorSetLayout>] { 563 &self.set_layouts 564 } 565 566 /// Returns a slice containing the push constant ranges this pipeline layout was created from. 567 /// 568 /// The ranges are guaranteed to be sorted deterministically by offset, size, then stages. 569 /// This means that two slices containing the same elements will always have the same order. 570 #[inline] push_constant_ranges(&self) -> &[PushConstantRange]571 pub fn push_constant_ranges(&self) -> &[PushConstantRange] { 572 &self.push_constant_ranges 573 } 574 575 /// Returns a slice containing the push constant ranges in with all disjoint stages. 576 /// 577 /// For example, if we have these `push_constant_ranges`: 578 /// - `offset=0, size=4, stages=vertex` 579 /// - `offset=0, size=12, stages=fragment` 580 /// 581 /// The returned value will be: 582 /// - `offset=0, size=4, stages=vertex|fragment` 583 /// - `offset=4, size=8, stages=fragment` 584 /// 585 /// The ranges are guaranteed to be sorted deterministically by offset, and 586 /// guaranteed to be disjoint, meaning that there is no overlap between the ranges. 587 #[inline] push_constant_ranges_disjoint(&self) -> &[PushConstantRange]588 pub(crate) fn push_constant_ranges_disjoint(&self) -> &[PushConstantRange] { 589 &self.push_constant_ranges_disjoint 590 } 591 592 /// Returns whether `self` is compatible with `other` for the given number of sets. 593 #[inline] is_compatible_with(&self, other: &PipelineLayout, num_sets: u32) -> bool594 pub fn is_compatible_with(&self, other: &PipelineLayout, num_sets: u32) -> bool { 595 let num_sets = num_sets as usize; 596 assert!(num_sets >= self.set_layouts.len()); 597 598 if self == other { 599 return true; 600 } 601 602 if self.push_constant_ranges != other.push_constant_ranges { 603 return false; 604 } 605 606 let other_sets = match other.set_layouts.get(0..num_sets) { 607 Some(x) => x, 608 None => return false, 609 }; 610 611 self.set_layouts 612 .iter() 613 .zip(other_sets) 614 .all(|(self_set_layout, other_set_layout)| { 615 self_set_layout.is_compatible_with(other_set_layout) 616 }) 617 } 618 619 /// Makes sure that `self` is a superset of the provided descriptor set layouts and push 620 /// constant ranges. Returns an `Err` if this is not the case. ensure_compatible_with_shader<'a>( &self, descriptor_requirements: impl IntoIterator< Item = ((u32, u32), &'a DescriptorBindingRequirements), >, push_constant_range: Option<&PushConstantRange>, ) -> Result<(), PipelineLayoutSupersetError>621 pub fn ensure_compatible_with_shader<'a>( 622 &self, 623 descriptor_requirements: impl IntoIterator< 624 Item = ((u32, u32), &'a DescriptorBindingRequirements), 625 >, 626 push_constant_range: Option<&PushConstantRange>, 627 ) -> Result<(), PipelineLayoutSupersetError> { 628 for ((set_num, binding_num), reqs) in descriptor_requirements.into_iter() { 629 let layout_binding = self 630 .set_layouts 631 .get(set_num as usize) 632 .and_then(|set_layout| set_layout.bindings().get(&binding_num)); 633 634 let layout_binding = match layout_binding { 635 Some(x) => x, 636 None => { 637 return Err(PipelineLayoutSupersetError::DescriptorMissing { 638 set_num, 639 binding_num, 640 }) 641 } 642 }; 643 644 if let Err(error) = layout_binding.ensure_compatible_with_shader(reqs) { 645 return Err(PipelineLayoutSupersetError::DescriptorRequirementsNotMet { 646 set_num, 647 binding_num, 648 error, 649 }); 650 } 651 } 652 653 // FIXME: check push constants 654 if let Some(range) = push_constant_range { 655 for own_range in self.push_constant_ranges.iter() { 656 if range.stages.intersects(own_range.stages) && // check if it shares any stages 657 (range.offset < own_range.offset || // our range must start before and end after the given range 658 own_range.offset + own_range.size < range.offset + range.size) 659 { 660 return Err(PipelineLayoutSupersetError::PushConstantRange { 661 first_range: *own_range, 662 second_range: *range, 663 }); 664 } 665 } 666 } 667 668 Ok(()) 669 } 670 } 671 672 impl Drop for PipelineLayout { 673 #[inline] drop(&mut self)674 fn drop(&mut self) { 675 unsafe { 676 let fns = self.device.fns(); 677 (fns.v1_0.destroy_pipeline_layout)(self.device.handle(), self.handle, ptr::null()); 678 } 679 } 680 } 681 682 unsafe impl VulkanObject for PipelineLayout { 683 type Handle = ash::vk::PipelineLayout; 684 685 #[inline] handle(&self) -> Self::Handle686 fn handle(&self) -> Self::Handle { 687 self.handle 688 } 689 } 690 691 unsafe impl DeviceOwned for PipelineLayout { 692 #[inline] device(&self) -> &Arc<Device>693 fn device(&self) -> &Arc<Device> { 694 &self.device 695 } 696 } 697 698 impl_id_counter!(PipelineLayout); 699 700 /// Error that can happen when creating a pipeline layout. 701 #[derive(Clone, Debug, PartialEq, Eq)] 702 pub enum PipelineLayoutCreationError { 703 /// Not enough memory. 704 OomError(OomError), 705 706 RequirementNotMet { 707 required_for: &'static str, 708 requires_one_of: RequiresOneOf, 709 }, 710 711 /// The number of elements in `set_layouts` is greater than the 712 /// [`max_bound_descriptor_sets`](crate::device::Properties::max_bound_descriptor_sets) limit. 713 MaxBoundDescriptorSetsExceeded { provided: u32, max_supported: u32 }, 714 715 /// The `set_layouts` contain more [`DescriptorType::Sampler`], 716 /// [`DescriptorType::CombinedImageSampler`] and [`DescriptorType::UniformTexelBuffer`] 717 /// descriptors than the 718 /// [`max_descriptor_set_samplers`](crate::device::Properties::max_descriptor_set_samplers) 719 /// limit. 720 MaxDescriptorSetSamplersExceeded { provided: u32, max_supported: u32 }, 721 722 /// The `set_layouts` contain more [`DescriptorType::UniformBuffer`] descriptors than the 723 /// [`max_descriptor_set_uniform_buffers`](crate::device::Properties::max_descriptor_set_uniform_buffers) 724 /// limit. 725 MaxDescriptorSetUniformBuffersExceeded { provided: u32, max_supported: u32 }, 726 727 /// The `set_layouts` contain more [`DescriptorType::UniformBufferDynamic`] descriptors than the 728 /// [`max_descriptor_set_uniform_buffers_dynamic`](crate::device::Properties::max_descriptor_set_uniform_buffers_dynamic) 729 /// limit. 730 MaxDescriptorSetUniformBuffersDynamicExceeded { provided: u32, max_supported: u32 }, 731 732 /// The `set_layouts` contain more [`DescriptorType::StorageBuffer`] descriptors than the 733 /// [`max_descriptor_set_storage_buffers`](crate::device::Properties::max_descriptor_set_storage_buffers) 734 /// limit. 735 MaxDescriptorSetStorageBuffersExceeded { provided: u32, max_supported: u32 }, 736 737 /// The `set_layouts` contain more [`DescriptorType::StorageBufferDynamic`] descriptors than the 738 /// [`max_descriptor_set_storage_buffers_dynamic`](crate::device::Properties::max_descriptor_set_storage_buffers_dynamic) 739 /// limit. 740 MaxDescriptorSetStorageBuffersDynamicExceeded { provided: u32, max_supported: u32 }, 741 742 /// The `set_layouts` contain more [`DescriptorType::SampledImage`] and 743 /// [`DescriptorType::CombinedImageSampler`] descriptors than the 744 /// [`max_descriptor_set_sampled_images`](crate::device::Properties::max_descriptor_set_sampled_images) 745 /// limit. 746 MaxDescriptorSetSampledImagesExceeded { provided: u32, max_supported: u32 }, 747 748 /// The `set_layouts` contain more [`DescriptorType::StorageImage`] and 749 /// [`DescriptorType::StorageTexelBuffer`] descriptors than the 750 /// [`max_descriptor_set_storage_images`](crate::device::Properties::max_descriptor_set_storage_images) 751 /// limit. 752 MaxDescriptorSetStorageImagesExceeded { provided: u32, max_supported: u32 }, 753 754 /// The `set_layouts` contain more [`DescriptorType::InputAttachment`] descriptors than the 755 /// [`max_descriptor_set_input_attachments`](crate::device::Properties::max_descriptor_set_input_attachments) 756 /// limit. 757 MaxDescriptorSetInputAttachmentsExceeded { provided: u32, max_supported: u32 }, 758 759 /// The `set_layouts` contain more bound resources in a single stage than the 760 /// [`max_per_stage_resources`](crate::device::Properties::max_per_stage_resources) 761 /// limit. 762 MaxPerStageResourcesExceeded { provided: u32, max_supported: u32 }, 763 764 /// The `set_layouts` contain more [`DescriptorType::Sampler`] and 765 /// [`DescriptorType::CombinedImageSampler`] descriptors in a single stage than the 766 /// [`max_per_stage_descriptor_samplers`](crate::device::Properties::max_per_stage_descriptor_samplers) 767 /// limit. 768 MaxPerStageDescriptorSamplersExceeded { provided: u32, max_supported: u32 }, 769 770 /// The `set_layouts` contain more [`DescriptorType::UniformBuffer`] and 771 /// [`DescriptorType::UniformBufferDynamic`] descriptors in a single stage than the 772 /// [`max_per_stage_descriptor_uniform_buffers`](crate::device::Properties::max_per_stage_descriptor_uniform_buffers) 773 /// limit. 774 MaxPerStageDescriptorUniformBuffersExceeded { provided: u32, max_supported: u32 }, 775 776 /// The `set_layouts` contain more [`DescriptorType::StorageBuffer`] and 777 /// [`DescriptorType::StorageBufferDynamic`] descriptors in a single stage than the 778 /// [`max_per_stage_descriptor_storage_buffers`](crate::device::Properties::max_per_stage_descriptor_storage_buffers) 779 /// limit. 780 MaxPerStageDescriptorStorageBuffersExceeded { provided: u32, max_supported: u32 }, 781 782 /// The `set_layouts` contain more [`DescriptorType::SampledImage`], 783 /// [`DescriptorType::CombinedImageSampler`] and [`DescriptorType::UniformTexelBuffer`] 784 /// descriptors in a single stage than the 785 /// [`max_per_stage_descriptor_sampled_images`](crate::device::Properties::max_per_stage_descriptor_sampled_images) 786 /// limit. 787 MaxPerStageDescriptorSampledImagesExceeded { provided: u32, max_supported: u32 }, 788 789 /// The `set_layouts` contain more [`DescriptorType::StorageImage`] and 790 /// [`DescriptorType::StorageTexelBuffer`] descriptors in a single stage than the 791 /// [`max_per_stage_descriptor_storage_images`](crate::device::Properties::max_per_stage_descriptor_storage_images) 792 /// limit. 793 MaxPerStageDescriptorStorageImagesExceeded { provided: u32, max_supported: u32 }, 794 795 /// The `set_layouts` contain more [`DescriptorType::InputAttachment`] descriptors in a single 796 /// stage than the 797 /// [`max_per_stage_descriptor_input_attachments`](crate::device::Properties::max_per_stage_descriptor_input_attachments) 798 /// limit. 799 MaxPerStageDescriptorInputAttachmentsExceeded { provided: u32, max_supported: u32 }, 800 801 /// An element in `push_constant_ranges` has an `offset + size` greater than the 802 /// [`max_push_constants_size`](crate::device::Properties::max_push_constants_size) limit. 803 MaxPushConstantsSizeExceeded { provided: u32, max_supported: u32 }, 804 805 /// A shader stage appears in multiple elements of `push_constant_ranges`. 806 PushConstantRangesStageMultiple, 807 808 /// Multiple elements of `set_layouts` have `push_descriptor` enabled. 809 SetLayoutsPushDescriptorMultiple, 810 } 811 812 impl Error for PipelineLayoutCreationError { source(&self) -> Option<&(dyn Error + 'static)>813 fn source(&self) -> Option<&(dyn Error + 'static)> { 814 match self { 815 Self::OomError(err) => Some(err), 816 _ => None, 817 } 818 } 819 } 820 821 impl Display for PipelineLayoutCreationError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>822 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 823 match self { 824 Self::OomError(_) => write!(f, "not enough memory available"), 825 Self::RequirementNotMet { 826 required_for, 827 requires_one_of, 828 } => write!( 829 f, 830 "a requirement was not met for: {}; requires one of: {}", 831 required_for, requires_one_of, 832 ), 833 Self::MaxBoundDescriptorSetsExceeded { 834 provided, 835 max_supported, 836 } => write!( 837 f, 838 "the number of elements in `set_layouts` ({}) is greater than the \ 839 `max_bound_descriptor_sets` limit ({})", 840 provided, max_supported, 841 ), 842 Self::MaxDescriptorSetSamplersExceeded { 843 provided, 844 max_supported, 845 } => write!( 846 f, 847 "the `set_layouts` contain more `DescriptorType::Sampler` and \ 848 `DescriptorType::CombinedImageSampler` descriptors ({}) than the \ 849 `max_descriptor_set_samplers` limit ({})", 850 provided, max_supported, 851 ), 852 Self::MaxDescriptorSetUniformBuffersExceeded { 853 provided, 854 max_supported, 855 } => write!( 856 f, 857 "the `set_layouts` contain more `DescriptorType::UniformBuffer` descriptors ({}) \ 858 than the `max_descriptor_set_uniform_buffers` limit ({})", 859 provided, max_supported, 860 ), 861 Self::MaxDescriptorSetUniformBuffersDynamicExceeded { 862 provided, 863 max_supported, 864 } => write!( 865 f, 866 "the `set_layouts` contain more `DescriptorType::UniformBufferDynamic` descriptors \ 867 ({}) than the `max_descriptor_set_uniform_buffers_dynamic` limit ({})", 868 provided, max_supported, 869 ), 870 Self::MaxDescriptorSetStorageBuffersExceeded { 871 provided, 872 max_supported, 873 } => write!( 874 f, 875 "the `set_layouts` contain more `DescriptorType::StorageBuffer` descriptors ({}) \ 876 than the `max_descriptor_set_storage_buffers` limit ({})", 877 provided, max_supported, 878 ), 879 Self::MaxDescriptorSetStorageBuffersDynamicExceeded { 880 provided, 881 max_supported, 882 } => write!( 883 f, 884 "the `set_layouts` contain more `DescriptorType::StorageBufferDynamic` descriptors \ 885 ({}) than the `max_descriptor_set_storage_buffers_dynamic` limit ({})", 886 provided, max_supported, 887 ), 888 Self::MaxDescriptorSetSampledImagesExceeded { 889 provided, 890 max_supported, 891 } => write!( 892 f, 893 "the `set_layouts` contain more `DescriptorType::SampledImage`, \ 894 `DescriptorType::CombinedImageSampler` and `DescriptorType::UniformTexelBuffer` \ 895 descriptors ({}) than the `max_descriptor_set_sampled_images` limit ({})", 896 provided, max_supported, 897 ), 898 Self::MaxDescriptorSetStorageImagesExceeded { 899 provided, 900 max_supported, 901 } => write!( 902 f, 903 "the `set_layouts` contain more `DescriptorType::StorageImage` and \ 904 `DescriptorType::StorageTexelBuffer` descriptors ({}) than the \ 905 `max_descriptor_set_storage_images` limit ({})", 906 provided, max_supported, 907 ), 908 Self::MaxDescriptorSetInputAttachmentsExceeded { 909 provided, 910 max_supported, 911 } => write!( 912 f, 913 "the `set_layouts` contain more `DescriptorType::InputAttachment` descriptors ({}) \ 914 than the `max_descriptor_set_input_attachments` limit ({})", 915 provided, max_supported, 916 ), 917 Self::MaxPerStageResourcesExceeded { 918 provided, 919 max_supported, 920 } => write!( 921 f, 922 "the `set_layouts` contain more bound resources ({}) in a single stage than the \ 923 `max_per_stage_resources` limit ({})", 924 provided, max_supported, 925 ), 926 Self::MaxPerStageDescriptorSamplersExceeded { 927 provided, 928 max_supported, 929 } => write!( 930 f, 931 "the `set_layouts` contain more `DescriptorType::Sampler` and \ 932 `DescriptorType::CombinedImageSampler` descriptors ({}) in a single stage than the \ 933 `max_per_stage_descriptor_set_samplers` limit ({})", 934 provided, max_supported, 935 ), 936 Self::MaxPerStageDescriptorUniformBuffersExceeded { 937 provided, 938 max_supported, 939 } => write!( 940 f, 941 "the `set_layouts` contain more `DescriptorType::UniformBuffer` and \ 942 `DescriptorType::UniformBufferDynamic` descriptors ({}) in a single stage than the \ 943 `max_per_stage_descriptor_set_uniform_buffers` limit ({})", 944 provided, max_supported, 945 ), 946 Self::MaxPerStageDescriptorStorageBuffersExceeded { 947 provided, 948 max_supported, 949 } => write!( 950 f, 951 "the `set_layouts` contain more `DescriptorType::StorageBuffer` and \ 952 `DescriptorType::StorageBufferDynamic` descriptors ({}) in a single stage than the \ 953 `max_per_stage_descriptor_set_storage_buffers` limit ({})", 954 provided, max_supported, 955 ), 956 Self::MaxPerStageDescriptorSampledImagesExceeded { 957 provided, 958 max_supported, 959 } => write!( 960 f, 961 "the `set_layouts` contain more `DescriptorType::SampledImage`, \ 962 `DescriptorType::CombinedImageSampler` and `DescriptorType::UniformTexelBuffer` \ 963 descriptors ({}) in a single stage than the \ 964 `max_per_stage_descriptor_set_sampled_images` limit ({})", 965 provided, max_supported, 966 ), 967 Self::MaxPerStageDescriptorStorageImagesExceeded { 968 provided, 969 max_supported, 970 } => write!( 971 f, 972 "the `set_layouts` contain more `DescriptorType::StorageImage` and \ 973 `DescriptorType::StorageTexelBuffer` descriptors ({}) in a single stage than the \ 974 `max_per_stage_descriptor_set_storage_images` limit ({})", 975 provided, max_supported, 976 ), 977 Self::MaxPerStageDescriptorInputAttachmentsExceeded { 978 provided, 979 max_supported, 980 } => write!( 981 f, 982 "the `set_layouts` contain more `DescriptorType::InputAttachment` descriptors ({}) \ 983 in a single stage than the `max_per_stage_descriptor_set_input_attachments` limit \ 984 ({})", 985 provided, max_supported, 986 ), 987 Self::MaxPushConstantsSizeExceeded { 988 provided, 989 max_supported, 990 } => write!( 991 f, 992 "an element in `push_constant_ranges` has an `offset + size` ({}) greater than the \ 993 `max_push_constants_size` limit ({})", 994 provided, max_supported, 995 ), 996 Self::PushConstantRangesStageMultiple => write!( 997 f, 998 "a shader stage appears in multiple elements of `push_constant_ranges`", 999 ), 1000 Self::SetLayoutsPushDescriptorMultiple => write!( 1001 f, 1002 "multiple elements of `set_layouts` have `push_descriptor` enabled", 1003 ), 1004 } 1005 } 1006 } 1007 1008 impl From<OomError> for PipelineLayoutCreationError { from(err: OomError) -> PipelineLayoutCreationError1009 fn from(err: OomError) -> PipelineLayoutCreationError { 1010 PipelineLayoutCreationError::OomError(err) 1011 } 1012 } 1013 1014 impl From<VulkanError> for PipelineLayoutCreationError { from(err: VulkanError) -> PipelineLayoutCreationError1015 fn from(err: VulkanError) -> PipelineLayoutCreationError { 1016 match err { 1017 err @ VulkanError::OutOfHostMemory => { 1018 PipelineLayoutCreationError::OomError(OomError::from(err)) 1019 } 1020 err @ VulkanError::OutOfDeviceMemory => { 1021 PipelineLayoutCreationError::OomError(OomError::from(err)) 1022 } 1023 _ => panic!("unexpected error: {:?}", err), 1024 } 1025 } 1026 } 1027 1028 impl From<RequirementNotMet> for PipelineLayoutCreationError { from(err: RequirementNotMet) -> Self1029 fn from(err: RequirementNotMet) -> Self { 1030 Self::RequirementNotMet { 1031 required_for: err.required_for, 1032 requires_one_of: err.requires_one_of, 1033 } 1034 } 1035 } 1036 1037 /// Error when checking whether a pipeline layout is a superset of another one. 1038 #[derive(Clone, Debug, PartialEq, Eq)] 1039 pub enum PipelineLayoutSupersetError { 1040 DescriptorMissing { 1041 set_num: u32, 1042 binding_num: u32, 1043 }, 1044 DescriptorRequirementsNotMet { 1045 set_num: u32, 1046 binding_num: u32, 1047 error: DescriptorRequirementsNotMet, 1048 }, 1049 PushConstantRange { 1050 first_range: PushConstantRange, 1051 second_range: PushConstantRange, 1052 }, 1053 } 1054 1055 impl Error for PipelineLayoutSupersetError { source(&self) -> Option<&(dyn Error + 'static)>1056 fn source(&self) -> Option<&(dyn Error + 'static)> { 1057 match self { 1058 PipelineLayoutSupersetError::DescriptorRequirementsNotMet { error, .. } => Some(error), 1059 _ => None, 1060 } 1061 } 1062 } 1063 1064 impl Display for PipelineLayoutSupersetError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1065 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 1066 match self { 1067 PipelineLayoutSupersetError::DescriptorRequirementsNotMet { 1068 set_num, 1069 binding_num, 1070 .. 1071 } => write!( 1072 f, 1073 "the descriptor at set {} binding {} does not meet the requirements", 1074 set_num, binding_num, 1075 ), 1076 PipelineLayoutSupersetError::DescriptorMissing { 1077 set_num, 1078 binding_num, 1079 } => write!( 1080 f, 1081 "a descriptor at set {} binding {} is required by the shaders, but is missing from \ 1082 the pipeline layout", 1083 set_num, binding_num, 1084 ), 1085 PipelineLayoutSupersetError::PushConstantRange { 1086 first_range, 1087 second_range, 1088 } => { 1089 writeln!(f, "our range did not completely encompass the other range")?; 1090 writeln!(f, " our stages: {:?}", first_range.stages)?; 1091 writeln!( 1092 f, 1093 " our range: {} - {}", 1094 first_range.offset, 1095 first_range.offset + first_range.size, 1096 )?; 1097 writeln!(f, " other stages: {:?}", second_range.stages)?; 1098 write!( 1099 f, 1100 " other range: {} - {}", 1101 second_range.offset, 1102 second_range.offset + second_range.size, 1103 ) 1104 } 1105 } 1106 } 1107 } 1108 1109 /// Parameters to create a new `PipelineLayout`. 1110 #[derive(Clone, Debug)] 1111 pub struct PipelineLayoutCreateInfo { 1112 /// The descriptor set layouts that should be part of the pipeline layout. 1113 /// 1114 /// They are provided in order of set number. 1115 /// 1116 /// The default value is empty. 1117 pub set_layouts: Vec<Arc<DescriptorSetLayout>>, 1118 1119 /// The ranges of push constants that the pipeline will access. 1120 /// 1121 /// A shader stage can only appear in one element of the list, but it is possible to combine 1122 /// ranges for multiple shader stages if they are the same. 1123 /// 1124 /// The default value is empty. 1125 pub push_constant_ranges: Vec<PushConstantRange>, 1126 1127 pub _ne: crate::NonExhaustive, 1128 } 1129 1130 impl Default for PipelineLayoutCreateInfo { 1131 #[inline] default() -> Self1132 fn default() -> Self { 1133 Self { 1134 set_layouts: Vec::new(), 1135 push_constant_ranges: Vec::new(), 1136 _ne: crate::NonExhaustive(()), 1137 } 1138 } 1139 } 1140 1141 /// Description of a range of the push constants of a pipeline layout. 1142 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 1143 pub struct PushConstantRange { 1144 /// The stages which can access this range. A stage can access at most one push constant range. 1145 /// 1146 /// The default value is [`ShaderStages::empty()`], which must be overridden. 1147 pub stages: ShaderStages, 1148 1149 /// Offset in bytes from the start of the push constants to this range. 1150 /// 1151 /// The value must be a multiple of 4. 1152 /// 1153 /// The default value is `0`. 1154 pub offset: u32, 1155 1156 /// Size in bytes of the range. 1157 /// 1158 /// The value must be a multiple of 4, and not 0. 1159 /// 1160 /// The default value is `0`, which must be overridden. 1161 pub size: u32, 1162 } 1163 1164 impl Default for PushConstantRange { 1165 #[inline] default() -> Self1166 fn default() -> Self { 1167 Self { 1168 stages: ShaderStages::empty(), 1169 offset: 0, 1170 size: 0, 1171 } 1172 } 1173 } 1174 1175 // Helper struct for the main function. 1176 #[derive(Default)] 1177 struct Counter { 1178 total: u32, 1179 compute: u32, 1180 vertex: u32, 1181 geometry: u32, 1182 tess_ctl: u32, 1183 tess_eval: u32, 1184 frag: u32, 1185 } 1186 1187 impl Counter { increment(&mut self, num: u32, stages: ShaderStages)1188 fn increment(&mut self, num: u32, stages: ShaderStages) { 1189 self.total += num; 1190 if stages.intersects(ShaderStages::COMPUTE) { 1191 self.compute += num; 1192 } 1193 if stages.intersects(ShaderStages::VERTEX) { 1194 self.vertex += num; 1195 } 1196 if stages.intersects(ShaderStages::TESSELLATION_CONTROL) { 1197 self.tess_ctl += num; 1198 } 1199 if stages.intersects(ShaderStages::TESSELLATION_EVALUATION) { 1200 self.tess_eval += num; 1201 } 1202 if stages.intersects(ShaderStages::GEOMETRY) { 1203 self.geometry += num; 1204 } 1205 if stages.intersects(ShaderStages::FRAGMENT) { 1206 self.frag += num; 1207 } 1208 } 1209 max_per_stage(&self) -> u321210 fn max_per_stage(&self) -> u32 { 1211 [ 1212 self.compute, 1213 self.vertex, 1214 self.tess_ctl, 1215 self.tess_eval, 1216 self.geometry, 1217 self.frag, 1218 ] 1219 .into_iter() 1220 .max() 1221 .unwrap_or(0) 1222 } 1223 } 1224 1225 #[cfg(test)] 1226 mod tests { 1227 1228 use super::PipelineLayout; 1229 use crate::{ 1230 pipeline::layout::{PipelineLayoutCreateInfo, PushConstantRange}, 1231 shader::ShaderStages, 1232 }; 1233 1234 #[test] push_constant_ranges_disjoint()1235 fn push_constant_ranges_disjoint() { 1236 let test_cases = [ 1237 // input: 1238 // - `0..12`, stage=fragment 1239 // - `0..40`, stage=vertex 1240 // 1241 // output: 1242 // - `0..12`, stage=fragment|vertex 1243 // - `12..40`, stage=vertex 1244 ( 1245 &[ 1246 PushConstantRange { 1247 stages: ShaderStages::FRAGMENT, 1248 offset: 0, 1249 size: 12, 1250 }, 1251 PushConstantRange { 1252 stages: ShaderStages::VERTEX, 1253 offset: 0, 1254 size: 40, 1255 }, 1256 ][..], 1257 &[ 1258 PushConstantRange { 1259 stages: ShaderStages::VERTEX | ShaderStages::FRAGMENT, 1260 offset: 0, 1261 size: 12, 1262 }, 1263 PushConstantRange { 1264 stages: ShaderStages::VERTEX, 1265 offset: 12, 1266 size: 28, 1267 }, 1268 ][..], 1269 ), 1270 // input: 1271 // - `0..12`, stage=fragment 1272 // - `4..40`, stage=vertex 1273 // 1274 // output: 1275 // - `0..4`, stage=fragment 1276 // - `4..12`, stage=fragment|vertex 1277 // - `12..40`, stage=vertex 1278 ( 1279 &[ 1280 PushConstantRange { 1281 stages: ShaderStages::FRAGMENT, 1282 offset: 0, 1283 size: 12, 1284 }, 1285 PushConstantRange { 1286 stages: ShaderStages::VERTEX, 1287 offset: 4, 1288 size: 36, 1289 }, 1290 ][..], 1291 &[ 1292 PushConstantRange { 1293 stages: ShaderStages::FRAGMENT, 1294 offset: 0, 1295 size: 4, 1296 }, 1297 PushConstantRange { 1298 stages: ShaderStages::FRAGMENT | ShaderStages::VERTEX, 1299 offset: 4, 1300 size: 8, 1301 }, 1302 PushConstantRange { 1303 stages: ShaderStages::VERTEX, 1304 offset: 12, 1305 size: 28, 1306 }, 1307 ][..], 1308 ), 1309 // input: 1310 // - `0..12`, stage=fragment 1311 // - `8..20`, stage=compute 1312 // - `4..16`, stage=vertex 1313 // - `8..32`, stage=tess_ctl 1314 // 1315 // output: 1316 // - `0..4`, stage=fragment 1317 // - `4..8`, stage=fragment|vertex 1318 // - `8..16`, stage=fragment|vertex|compute|tess_ctl 1319 // - `16..20`, stage=compute|tess_ctl 1320 // - `20..32` stage=tess_ctl 1321 ( 1322 &[ 1323 PushConstantRange { 1324 stages: ShaderStages::FRAGMENT, 1325 offset: 0, 1326 size: 12, 1327 }, 1328 PushConstantRange { 1329 stages: ShaderStages::COMPUTE, 1330 offset: 8, 1331 size: 12, 1332 }, 1333 PushConstantRange { 1334 stages: ShaderStages::VERTEX, 1335 offset: 4, 1336 size: 12, 1337 }, 1338 PushConstantRange { 1339 stages: ShaderStages::TESSELLATION_CONTROL, 1340 offset: 8, 1341 size: 24, 1342 }, 1343 ][..], 1344 &[ 1345 PushConstantRange { 1346 stages: ShaderStages::FRAGMENT, 1347 offset: 0, 1348 size: 4, 1349 }, 1350 PushConstantRange { 1351 stages: ShaderStages::FRAGMENT | ShaderStages::VERTEX, 1352 offset: 4, 1353 size: 4, 1354 }, 1355 PushConstantRange { 1356 stages: ShaderStages::VERTEX 1357 | ShaderStages::FRAGMENT 1358 | ShaderStages::COMPUTE 1359 | ShaderStages::TESSELLATION_CONTROL, 1360 offset: 8, 1361 size: 4, 1362 }, 1363 PushConstantRange { 1364 stages: ShaderStages::VERTEX 1365 | ShaderStages::COMPUTE 1366 | ShaderStages::TESSELLATION_CONTROL, 1367 offset: 12, 1368 size: 4, 1369 }, 1370 PushConstantRange { 1371 stages: ShaderStages::COMPUTE | ShaderStages::TESSELLATION_CONTROL, 1372 offset: 16, 1373 size: 4, 1374 }, 1375 PushConstantRange { 1376 stages: ShaderStages::TESSELLATION_CONTROL, 1377 offset: 20, 1378 size: 12, 1379 }, 1380 ][..], 1381 ), 1382 ]; 1383 1384 let (device, _) = gfx_dev_and_queue!(); 1385 1386 for (input, expected) in test_cases { 1387 let layout = PipelineLayout::new( 1388 device.clone(), 1389 PipelineLayoutCreateInfo { 1390 push_constant_ranges: input.into(), 1391 ..Default::default() 1392 }, 1393 ) 1394 .unwrap(); 1395 1396 assert_eq!(layout.push_constant_ranges_disjoint.as_slice(), expected); 1397 } 1398 } 1399 } 1400 1401 /* TODO: restore 1402 #[cfg(test)] 1403 mod tests { 1404 use std::iter; 1405 use std::sync::Arc; 1406 use descriptor::descriptor::ShaderStages; 1407 use descriptor::descriptor_set::DescriptorSetLayout; 1408 use descriptor::pipeline_layout::sys::PipelineLayout; 1409 use descriptor::pipeline_layout::sys::PipelineLayoutCreationError; 1410 1411 #[test] 1412 fn empty() { 1413 let (device, _) = gfx_dev_and_queue!(); 1414 let _layout = PipelineLayout::new(&device, iter::empty(), iter::empty()).unwrap(); 1415 } 1416 1417 #[test] 1418 fn wrong_device_panic() { 1419 let (device1, _) = gfx_dev_and_queue!(); 1420 let (device2, _) = gfx_dev_and_queue!(); 1421 1422 let set = match DescriptorSetLayout::raw(device1, iter::empty()) { 1423 Ok(s) => Arc::new(s), 1424 Err(_) => return 1425 }; 1426 1427 assert_should_panic!({ 1428 let _ = PipelineLayout::new(&device2, Some(&set), iter::empty()); 1429 }); 1430 } 1431 1432 #[test] 1433 fn invalid_push_constant_stages() { 1434 let (device, _) = gfx_dev_and_queue!(); 1435 1436 let push_constant = (0, 8, ShaderStages::empty()); 1437 1438 match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) { 1439 Err(PipelineLayoutCreationError::InvalidPushConstant) => (), 1440 _ => panic!() 1441 } 1442 } 1443 1444 #[test] 1445 fn invalid_push_constant_size1() { 1446 let (device, _) = gfx_dev_and_queue!(); 1447 1448 let push_constant = (0, 0, ShaderStages::all_graphics()); 1449 1450 match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) { 1451 Err(PipelineLayoutCreationError::InvalidPushConstant) => (), 1452 _ => panic!() 1453 } 1454 } 1455 1456 #[test] 1457 fn invalid_push_constant_size2() { 1458 let (device, _) = gfx_dev_and_queue!(); 1459 1460 let push_constant = (0, 11, ShaderStages::all_graphics()); 1461 1462 match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) { 1463 Err(PipelineLayoutCreationError::InvalidPushConstant) => (), 1464 _ => panic!() 1465 } 1466 } 1467 } 1468 */ 1469