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 crate::{ 11 buffer::{BufferContents, BufferUsage, Subbuffer}, 12 command_buffer::{ 13 allocator::CommandBufferAllocator, 14 auto::RenderPassStateType, 15 synced::{Command, SetOrPush, SyncCommandBufferBuilder}, 16 sys::UnsafeCommandBufferBuilder, 17 AutoCommandBufferBuilder, 18 }, 19 descriptor_set::{ 20 check_descriptor_write, layout::DescriptorType, sys::UnsafeDescriptorSet, 21 DescriptorBindingResources, DescriptorSetResources, DescriptorSetUpdateError, 22 DescriptorSetWithOffsets, DescriptorSetsCollection, DescriptorWriteInfo, 23 WriteDescriptorSet, 24 }, 25 device::{DeviceOwned, QueueFlags}, 26 memory::{is_aligned, DeviceAlignment}, 27 pipeline::{ 28 graphics::{ 29 input_assembly::{Index, IndexType}, 30 render_pass::PipelineRenderPassType, 31 vertex_input::VertexBuffersCollection, 32 }, 33 ComputePipeline, GraphicsPipeline, PipelineBindPoint, PipelineLayout, 34 }, 35 shader::ShaderStages, 36 DeviceSize, RequirementNotMet, RequiresOneOf, VulkanObject, 37 }; 38 use parking_lot::Mutex; 39 use smallvec::SmallVec; 40 use std::{ 41 cmp::min, 42 error, 43 fmt::{Display, Error as FmtError, Formatter}, 44 mem::{size_of, size_of_val}, 45 ptr, slice, 46 sync::Arc, 47 }; 48 49 /// # Commands to bind or push state for pipeline execution commands. 50 /// 51 /// These commands require a queue with a pipeline type that uses the given state. 52 impl<L, A> AutoCommandBufferBuilder<L, A> 53 where 54 A: CommandBufferAllocator, 55 { 56 /// Binds descriptor sets for future dispatch or draw calls. 57 /// 58 /// # Panics 59 /// 60 /// - Panics if the queue family of the command buffer does not support `pipeline_bind_point`. 61 /// - Panics if the highest descriptor set slot being bound is not less than the number of sets 62 /// in `pipeline_layout`. 63 /// - Panics if `self` and any element of `descriptor_sets` do not belong to the same device. bind_descriptor_sets<S>( &mut self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: Arc<PipelineLayout>, first_set: u32, descriptor_sets: S, ) -> &mut Self where S: DescriptorSetsCollection,64 pub fn bind_descriptor_sets<S>( 65 &mut self, 66 pipeline_bind_point: PipelineBindPoint, 67 pipeline_layout: Arc<PipelineLayout>, 68 first_set: u32, 69 descriptor_sets: S, 70 ) -> &mut Self 71 where 72 S: DescriptorSetsCollection, 73 { 74 let descriptor_sets = descriptor_sets.into_vec(); 75 self.validate_bind_descriptor_sets( 76 pipeline_bind_point, 77 &pipeline_layout, 78 first_set, 79 &descriptor_sets, 80 ) 81 .unwrap(); 82 83 unsafe { 84 let mut sets_binder = self.inner.bind_descriptor_sets(); 85 for set in descriptor_sets.into_iter() { 86 sets_binder.add(set); 87 } 88 sets_binder.submit(pipeline_bind_point, pipeline_layout, first_set); 89 } 90 91 self 92 } 93 validate_bind_descriptor_sets( &self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: &PipelineLayout, first_set: u32, descriptor_sets: &[DescriptorSetWithOffsets], ) -> Result<(), BindPushError>94 fn validate_bind_descriptor_sets( 95 &self, 96 pipeline_bind_point: PipelineBindPoint, 97 pipeline_layout: &PipelineLayout, 98 first_set: u32, 99 descriptor_sets: &[DescriptorSetWithOffsets], 100 ) -> Result<(), BindPushError> { 101 // VUID-vkCmdBindDescriptorSets-pipelineBindPoint-parameter 102 pipeline_bind_point.validate_device(self.device())?; 103 104 let queue_family_properties = self.queue_family_properties(); 105 106 // VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool 107 // VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361 108 match pipeline_bind_point { 109 PipelineBindPoint::Compute => { 110 if !queue_family_properties 111 .queue_flags 112 .intersects(QueueFlags::COMPUTE) 113 { 114 return Err(BindPushError::NotSupportedByQueueFamily); 115 } 116 } 117 PipelineBindPoint::Graphics => { 118 if !queue_family_properties 119 .queue_flags 120 .intersects(QueueFlags::GRAPHICS) 121 { 122 return Err(BindPushError::NotSupportedByQueueFamily); 123 } 124 } 125 } 126 127 // VUID-vkCmdBindDescriptorSets-firstSet-00360 128 if first_set + descriptor_sets.len() as u32 > pipeline_layout.set_layouts().len() as u32 { 129 return Err(BindPushError::DescriptorSetOutOfRange { 130 set_num: first_set + descriptor_sets.len() as u32, 131 pipeline_layout_set_count: pipeline_layout.set_layouts().len() as u32, 132 }); 133 } 134 135 let properties = self.device().physical_device().properties(); 136 let uniform_alignment = properties.min_uniform_buffer_offset_alignment; 137 let storage_alignment = properties.min_storage_buffer_offset_alignment; 138 139 for (i, set) in descriptor_sets.iter().enumerate() { 140 let set_num = first_set + i as u32; 141 let (set, dynamic_offsets) = set.as_ref(); 142 143 // VUID-vkCmdBindDescriptorSets-commonparent 144 assert_eq!(self.device(), set.device()); 145 146 let set_layout = set.layout(); 147 let pipeline_set_layout = &pipeline_layout.set_layouts()[set_num as usize]; 148 149 // VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358 150 if !pipeline_set_layout.is_compatible_with(set_layout) { 151 return Err(BindPushError::DescriptorSetNotCompatible { set_num }); 152 } 153 154 let mut dynamic_offsets_remaining = dynamic_offsets; 155 let mut required_dynamic_offset_count = 0; 156 157 for (&binding_num, binding) in set_layout.bindings() { 158 let required_alignment = match binding.descriptor_type { 159 DescriptorType::UniformBufferDynamic => uniform_alignment, 160 DescriptorType::StorageBufferDynamic => storage_alignment, 161 _ => continue, 162 }; 163 164 let count = if binding.variable_descriptor_count { 165 set.variable_descriptor_count() 166 } else { 167 binding.descriptor_count 168 } as usize; 169 170 required_dynamic_offset_count += count; 171 172 if !dynamic_offsets_remaining.is_empty() { 173 let split_index = min(count, dynamic_offsets_remaining.len()); 174 let dynamic_offsets = &dynamic_offsets_remaining[..split_index]; 175 dynamic_offsets_remaining = &dynamic_offsets_remaining[split_index..]; 176 177 let elements = match set.resources().binding(binding_num) { 178 Some(DescriptorBindingResources::Buffer(elements)) => elements.as_slice(), 179 _ => unreachable!(), 180 }; 181 182 for (index, (&offset, element)) in 183 dynamic_offsets.iter().zip(elements).enumerate() 184 { 185 // VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971 186 // VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01972 187 if !is_aligned(offset as DeviceSize, required_alignment) { 188 return Err(BindPushError::DynamicOffsetNotAligned { 189 set_num, 190 binding_num, 191 index: index as u32, 192 offset, 193 required_alignment, 194 }); 195 } 196 197 if let Some((buffer, range)) = element { 198 // VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979 199 if offset as DeviceSize + range.end > buffer.size() { 200 return Err(BindPushError::DynamicOffsetOutOfBufferBounds { 201 set_num, 202 binding_num, 203 index: index as u32, 204 offset, 205 range_end: range.end, 206 buffer_size: buffer.size(), 207 }); 208 } 209 } 210 } 211 } 212 } 213 214 // VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359 215 if dynamic_offsets.len() != required_dynamic_offset_count { 216 return Err(BindPushError::DynamicOffsetCountMismatch { 217 set_num, 218 provided_count: dynamic_offsets.len(), 219 required_count: required_dynamic_offset_count, 220 }); 221 } 222 } 223 224 Ok(()) 225 } 226 227 /// Binds an index buffer for future indexed draw calls. 228 /// 229 /// # Panics 230 /// 231 /// - Panics if the queue family of the command buffer does not support graphics operations. 232 /// - Panics if `self` and `index_buffer` do not belong to the same device. 233 /// - Panics if `index_buffer` does not have the [`BufferUsage::INDEX_BUFFER`] usage enabled. 234 /// - If the index buffer contains `u8` indices, panics if the [`index_type_uint8`] feature is 235 /// not enabled on the device. 236 /// 237 /// [`BufferUsage::INDEX_BUFFER`]: crate::buffer::BufferUsage::INDEX_BUFFER 238 /// [`index_type_uint8`]: crate::device::Features::index_type_uint8 bind_index_buffer<I: Index>(&mut self, index_buffer: Subbuffer<[I]>) -> &mut Self239 pub fn bind_index_buffer<I: Index>(&mut self, index_buffer: Subbuffer<[I]>) -> &mut Self { 240 self.validate_bind_index_buffer(index_buffer.as_bytes(), I::ty()) 241 .unwrap(); 242 243 unsafe { 244 self.inner 245 .bind_index_buffer(index_buffer.into_bytes(), I::ty()); 246 } 247 248 self 249 } 250 validate_bind_index_buffer( &self, index_buffer: &Subbuffer<[u8]>, index_type: IndexType, ) -> Result<(), BindPushError>251 fn validate_bind_index_buffer( 252 &self, 253 index_buffer: &Subbuffer<[u8]>, 254 index_type: IndexType, 255 ) -> Result<(), BindPushError> { 256 let queue_family_properties = self.queue_family_properties(); 257 258 // VUID-vkCmdBindIndexBuffer-commandBuffer-cmdpool 259 if !queue_family_properties 260 .queue_flags 261 .intersects(QueueFlags::GRAPHICS) 262 { 263 return Err(BindPushError::NotSupportedByQueueFamily); 264 } 265 266 // VUID-vkCmdBindIndexBuffer-commonparent 267 assert_eq!(self.device(), index_buffer.device()); 268 269 // VUID-vkCmdBindIndexBuffer-buffer-00433 270 if !index_buffer 271 .buffer() 272 .usage() 273 .intersects(BufferUsage::INDEX_BUFFER) 274 { 275 return Err(BindPushError::IndexBufferMissingUsage); 276 } 277 278 // VUID-vkCmdBindIndexBuffer-indexType-02765 279 if index_type == IndexType::U8 && !self.device().enabled_features().index_type_uint8 { 280 return Err(BindPushError::RequirementNotMet { 281 required_for: "`index_type` is `IndexType::U8`", 282 requires_one_of: RequiresOneOf { 283 features: &["index_type_uint8"], 284 ..Default::default() 285 }, 286 }); 287 } 288 289 // TODO: 290 // VUID-vkCmdBindIndexBuffer-offset-00432 291 292 Ok(()) 293 } 294 295 /// Binds a compute pipeline for future dispatch calls. 296 /// 297 /// # Panics 298 /// 299 /// - Panics if the queue family of the command buffer does not support compute operations. 300 /// - Panics if `self` and `pipeline` do not belong to the same device. bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>) -> &mut Self301 pub fn bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>) -> &mut Self { 302 self.validate_bind_pipeline_compute(&pipeline).unwrap(); 303 304 unsafe { 305 self.inner.bind_pipeline_compute(pipeline); 306 } 307 308 self 309 } 310 validate_bind_pipeline_compute( &self, pipeline: &ComputePipeline, ) -> Result<(), BindPushError>311 fn validate_bind_pipeline_compute( 312 &self, 313 pipeline: &ComputePipeline, 314 ) -> Result<(), BindPushError> { 315 let queue_family_properties = self.queue_family_properties(); 316 317 // VUID-vkCmdBindPipeline-pipelineBindPoint-00777 318 if !queue_family_properties 319 .queue_flags 320 .intersects(QueueFlags::COMPUTE) 321 { 322 return Err(BindPushError::NotSupportedByQueueFamily); 323 } 324 325 // VUID-vkCmdBindPipeline-commonparent 326 assert_eq!(self.device(), pipeline.device()); 327 328 Ok(()) 329 } 330 331 /// Binds a graphics pipeline for future draw calls. 332 /// 333 /// # Panics 334 /// 335 /// - Panics if the queue family of the command buffer does not support graphics operations. 336 /// - Panics if `self` and `pipeline` do not belong to the same device. bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>) -> &mut Self337 pub fn bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>) -> &mut Self { 338 self.validate_bind_pipeline_graphics(&pipeline).unwrap(); 339 340 unsafe { 341 self.inner.bind_pipeline_graphics(pipeline); 342 } 343 344 self 345 } 346 validate_bind_pipeline_graphics( &self, pipeline: &GraphicsPipeline, ) -> Result<(), BindPushError>347 fn validate_bind_pipeline_graphics( 348 &self, 349 pipeline: &GraphicsPipeline, 350 ) -> Result<(), BindPushError> { 351 let queue_family_properties = self.queue_family_properties(); 352 353 // VUID-vkCmdBindPipeline-pipelineBindPoint-00778 354 if !queue_family_properties 355 .queue_flags 356 .intersects(QueueFlags::GRAPHICS) 357 { 358 return Err(BindPushError::NotSupportedByQueueFamily); 359 } 360 361 // VUID-vkCmdBindPipeline-commonparent 362 assert_eq!(self.device(), pipeline.device()); 363 364 if let Some(last_pipeline) = self 365 .render_pass_state 366 .as_ref() 367 .and_then(|render_pass_state| match &render_pass_state.render_pass { 368 RenderPassStateType::BeginRendering(state) if state.pipeline_used => { 369 self.state().pipeline_graphics() 370 } 371 _ => None, 372 }) 373 { 374 if let ( 375 PipelineRenderPassType::BeginRendering(pipeline_rendering_info), 376 PipelineRenderPassType::BeginRendering(last_pipeline_rendering_info), 377 ) = (pipeline.render_pass(), last_pipeline.render_pass()) 378 { 379 // VUID-vkCmdBindPipeline-pipeline-06195 380 // VUID-vkCmdBindPipeline-pipeline-06196 381 if pipeline_rendering_info.color_attachment_formats 382 != last_pipeline_rendering_info.color_attachment_formats 383 { 384 return Err(BindPushError::PreviousPipelineColorAttachmentFormatMismatch); 385 } 386 387 // VUID-vkCmdBindPipeline-pipeline-06197 388 if pipeline_rendering_info.depth_attachment_format 389 != last_pipeline_rendering_info.depth_attachment_format 390 { 391 return Err(BindPushError::PreviousPipelineDepthAttachmentFormatMismatch); 392 } 393 394 // VUID-vkCmdBindPipeline-pipeline-06194 395 if pipeline_rendering_info.stencil_attachment_format 396 != last_pipeline_rendering_info.stencil_attachment_format 397 { 398 return Err(BindPushError::PreviousPipelineStencilAttachmentFormatMismatch); 399 } 400 } 401 } 402 403 // VUID-vkCmdBindPipeline-pipeline-00781 404 // TODO: 405 406 Ok(()) 407 } 408 409 /// Binds vertex buffers for future draw calls. 410 /// 411 /// # Panics 412 /// 413 /// - Panics if the queue family of the command buffer does not support graphics operations. 414 /// - Panics if the highest vertex buffer binding being bound is greater than the 415 /// [`max_vertex_input_bindings`] device property. 416 /// - Panics if `self` and any element of `vertex_buffers` do not belong to the same device. 417 /// - Panics if any element of `vertex_buffers` does not have the 418 /// [`BufferUsage::VERTEX_BUFFER`] usage enabled. 419 /// 420 /// [`max_vertex_input_bindings`]: crate::device::Properties::max_vertex_input_bindings 421 /// [`BufferUsage::VERTEX_BUFFER`]: crate::buffer::BufferUsage::VERTEX_BUFFER bind_vertex_buffers( &mut self, first_binding: u32, vertex_buffers: impl VertexBuffersCollection, ) -> &mut Self422 pub fn bind_vertex_buffers( 423 &mut self, 424 first_binding: u32, 425 vertex_buffers: impl VertexBuffersCollection, 426 ) -> &mut Self { 427 let vertex_buffers = vertex_buffers.into_vec(); 428 self.validate_bind_vertex_buffers(first_binding, &vertex_buffers) 429 .unwrap(); 430 431 unsafe { 432 let mut binder = self.inner.bind_vertex_buffers(); 433 for vb in vertex_buffers.into_iter() { 434 binder.add(vb); 435 } 436 binder.submit(first_binding); 437 } 438 439 self 440 } 441 validate_bind_vertex_buffers( &self, first_binding: u32, vertex_buffers: &[Subbuffer<[u8]>], ) -> Result<(), BindPushError>442 fn validate_bind_vertex_buffers( 443 &self, 444 first_binding: u32, 445 vertex_buffers: &[Subbuffer<[u8]>], 446 ) -> Result<(), BindPushError> { 447 let queue_family_properties = self.queue_family_properties(); 448 449 // VUID-vkCmdBindVertexBuffers-commandBuffer-cmdpool 450 if !queue_family_properties 451 .queue_flags 452 .intersects(QueueFlags::GRAPHICS) 453 { 454 return Err(BindPushError::NotSupportedByQueueFamily); 455 } 456 457 // VUID-vkCmdBindVertexBuffers-firstBinding-00624 458 // VUID-vkCmdBindVertexBuffers-firstBinding-00625 459 if first_binding + vertex_buffers.len() as u32 460 > self 461 .device() 462 .physical_device() 463 .properties() 464 .max_vertex_input_bindings 465 { 466 return Err(BindPushError::MaxVertexInputBindingsExceeded { 467 _binding_count: first_binding + vertex_buffers.len() as u32, 468 _max: self 469 .device() 470 .physical_device() 471 .properties() 472 .max_vertex_input_bindings, 473 }); 474 } 475 476 for buffer in vertex_buffers { 477 // VUID-vkCmdBindVertexBuffers-commonparent 478 assert_eq!(self.device(), buffer.device()); 479 480 // VUID-vkCmdBindVertexBuffers-pBuffers-00627 481 if !buffer 482 .buffer() 483 .usage() 484 .intersects(BufferUsage::VERTEX_BUFFER) 485 { 486 return Err(BindPushError::VertexBufferMissingUsage); 487 } 488 } 489 490 Ok(()) 491 } 492 493 /// Sets push constants for future dispatch or draw calls. 494 /// 495 /// # Panics 496 /// 497 /// - Panics if `offset` is not a multiple of 4. 498 /// - Panics if the size of `push_constants` is not a multiple of 4. 499 /// - Panics if any of the bytes in `push_constants` do not fall within any of the pipeline 500 /// layout's push constant ranges. push_constants<Pc>( &mut self, pipeline_layout: Arc<PipelineLayout>, offset: u32, push_constants: Pc, ) -> &mut Self where Pc: BufferContents,501 pub fn push_constants<Pc>( 502 &mut self, 503 pipeline_layout: Arc<PipelineLayout>, 504 offset: u32, 505 push_constants: Pc, 506 ) -> &mut Self 507 where 508 Pc: BufferContents, 509 { 510 let size = size_of::<Pc>() as u32; 511 512 if size == 0 { 513 return self; 514 } 515 516 // SAFETY: `&push_constants` is a valid pointer, and the size of the struct is `size`, 517 // thus, getting a slice of the whole struct is safe if its not modified. 518 let push_constants = unsafe { 519 slice::from_raw_parts(&push_constants as *const Pc as *const u8, size as usize) 520 }; 521 522 self.validate_push_constants(&pipeline_layout, offset, push_constants) 523 .unwrap(); 524 525 let mut current_offset = offset; 526 let mut remaining_size = size; 527 for range in pipeline_layout 528 .push_constant_ranges_disjoint() 529 .iter() 530 .skip_while(|range| range.offset + range.size <= offset) 531 { 532 // there is a gap between ranges, but the passed push_constants contains 533 // some bytes in this gap, exit the loop and report error 534 if range.offset > current_offset { 535 break; 536 } 537 538 // push the minimum of the whole remaining data, and the part until the end of this range 539 let push_size = remaining_size.min(range.offset + range.size - current_offset); 540 let data_offset = (current_offset - offset) as usize; 541 unsafe { 542 self.inner.push_constants::<[u8]>( 543 pipeline_layout.clone(), 544 range.stages, 545 current_offset, 546 push_size, 547 &push_constants[data_offset..(data_offset + push_size as usize)], 548 ); 549 } 550 current_offset += push_size; 551 remaining_size -= push_size; 552 553 if remaining_size == 0 { 554 break; 555 } 556 } 557 558 debug_assert!(remaining_size == 0); 559 560 self 561 } 562 validate_push_constants( &self, pipeline_layout: &PipelineLayout, offset: u32, push_constants: &[u8], ) -> Result<(), BindPushError>563 fn validate_push_constants( 564 &self, 565 pipeline_layout: &PipelineLayout, 566 offset: u32, 567 push_constants: &[u8], 568 ) -> Result<(), BindPushError> { 569 if offset % 4 != 0 { 570 return Err(BindPushError::PushConstantsOffsetNotAligned); 571 } 572 573 if push_constants.len() % 4 != 0 { 574 return Err(BindPushError::PushConstantsSizeNotAligned); 575 } 576 577 let mut current_offset = offset; 578 let mut remaining_size = push_constants.len() as u32; 579 for range in pipeline_layout 580 .push_constant_ranges_disjoint() 581 .iter() 582 .skip_while(|range| range.offset + range.size <= offset) 583 { 584 // there is a gap between ranges, but the passed push_constants contains 585 // some bytes in this gap, exit the loop and report error 586 if range.offset > current_offset { 587 break; 588 } 589 590 // push the minimum of the whole remaining data, and the part until the end of this range 591 let push_size = remaining_size.min(range.offset + range.size - current_offset); 592 current_offset += push_size; 593 remaining_size -= push_size; 594 595 if remaining_size == 0 { 596 break; 597 } 598 } 599 600 if remaining_size != 0 { 601 return Err(BindPushError::PushConstantsDataOutOfRange { 602 offset: current_offset, 603 }); 604 } 605 606 Ok(()) 607 } 608 609 /// Pushes descriptor data directly into the command buffer for future dispatch or draw calls. 610 /// 611 /// # Panics 612 /// 613 /// - Panics if the queue family of the command buffer does not support `pipeline_bind_point`. 614 /// - Panics if the 615 /// [`khr_push_descriptor`](crate::device::DeviceExtensions::khr_push_descriptor) 616 /// extension is not enabled on the device. 617 /// - Panics if `set_num` is not less than the number of sets in `pipeline_layout`. 618 /// - Panics if an element of `descriptor_writes` is not compatible with `pipeline_layout`. push_descriptor_set( &mut self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: Arc<PipelineLayout>, set_num: u32, descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>, ) -> &mut Self619 pub fn push_descriptor_set( 620 &mut self, 621 pipeline_bind_point: PipelineBindPoint, 622 pipeline_layout: Arc<PipelineLayout>, 623 set_num: u32, 624 descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>, 625 ) -> &mut Self { 626 let descriptor_writes: SmallVec<[_; 8]> = descriptor_writes.into_iter().collect(); 627 self.validate_push_descriptor_set( 628 pipeline_bind_point, 629 &pipeline_layout, 630 set_num, 631 &descriptor_writes, 632 ) 633 .unwrap(); 634 635 unsafe { 636 self.inner.push_descriptor_set( 637 pipeline_bind_point, 638 pipeline_layout, 639 set_num, 640 descriptor_writes, 641 ); 642 } 643 644 self 645 } 646 validate_push_descriptor_set( &self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: &PipelineLayout, set_num: u32, descriptor_writes: &[WriteDescriptorSet], ) -> Result<(), BindPushError>647 fn validate_push_descriptor_set( 648 &self, 649 pipeline_bind_point: PipelineBindPoint, 650 pipeline_layout: &PipelineLayout, 651 set_num: u32, 652 descriptor_writes: &[WriteDescriptorSet], 653 ) -> Result<(), BindPushError> { 654 if !self.device().enabled_extensions().khr_push_descriptor { 655 return Err(BindPushError::RequirementNotMet { 656 required_for: "`AutoCommandBufferBuilder::push_descriptor_set`", 657 requires_one_of: RequiresOneOf { 658 device_extensions: &["khr_push_descriptor"], 659 ..Default::default() 660 }, 661 }); 662 } 663 664 // VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-parameter 665 pipeline_bind_point.validate_device(self.device())?; 666 667 let queue_family_properties = self.queue_family_properties(); 668 669 // VUID-vkCmdPushDescriptorSetKHR-commandBuffer-cmdpool 670 // VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363 671 match pipeline_bind_point { 672 PipelineBindPoint::Compute => { 673 if !queue_family_properties 674 .queue_flags 675 .intersects(QueueFlags::COMPUTE) 676 { 677 return Err(BindPushError::NotSupportedByQueueFamily); 678 } 679 } 680 PipelineBindPoint::Graphics => { 681 if !queue_family_properties 682 .queue_flags 683 .intersects(QueueFlags::GRAPHICS) 684 { 685 return Err(BindPushError::NotSupportedByQueueFamily); 686 } 687 } 688 } 689 690 // VUID-vkCmdPushDescriptorSetKHR-commonparent 691 assert_eq!(self.device(), pipeline_layout.device()); 692 693 // VUID-vkCmdPushDescriptorSetKHR-set-00364 694 if set_num as usize > pipeline_layout.set_layouts().len() { 695 return Err(BindPushError::DescriptorSetOutOfRange { 696 set_num, 697 pipeline_layout_set_count: pipeline_layout.set_layouts().len() as u32, 698 }); 699 } 700 701 let descriptor_set_layout = &pipeline_layout.set_layouts()[set_num as usize]; 702 703 // VUID-vkCmdPushDescriptorSetKHR-set-00365 704 if !descriptor_set_layout.push_descriptor() { 705 return Err(BindPushError::DescriptorSetNotPush { set_num }); 706 } 707 708 for write in descriptor_writes { 709 check_descriptor_write(write, descriptor_set_layout, 0)?; 710 } 711 712 Ok(()) 713 } 714 } 715 716 impl SyncCommandBufferBuilder { 717 /// Starts the process of binding descriptor sets. Returns an intermediate struct which can be 718 /// used to add the sets. 719 #[inline] bind_descriptor_sets(&mut self) -> SyncCommandBufferBuilderBindDescriptorSets<'_>720 pub fn bind_descriptor_sets(&mut self) -> SyncCommandBufferBuilderBindDescriptorSets<'_> { 721 SyncCommandBufferBuilderBindDescriptorSets { 722 builder: self, 723 descriptor_sets: SmallVec::new(), 724 } 725 } 726 727 /// Calls `vkCmdBindIndexBuffer` on the builder. 728 #[inline] bind_index_buffer(&mut self, buffer: Subbuffer<[u8]>, index_type: IndexType)729 pub unsafe fn bind_index_buffer(&mut self, buffer: Subbuffer<[u8]>, index_type: IndexType) { 730 struct Cmd { 731 buffer: Subbuffer<[u8]>, 732 index_type: IndexType, 733 } 734 735 impl Command for Cmd { 736 fn name(&self) -> &'static str { 737 "bind_index_buffer" 738 } 739 740 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 741 out.bind_index_buffer(&self.buffer, self.index_type); 742 } 743 } 744 745 self.current_state.index_buffer = Some((buffer.clone(), index_type)); 746 self.commands.push(Box::new(Cmd { buffer, index_type })); 747 } 748 749 /// Calls `vkCmdBindPipeline` on the builder with a compute pipeline. 750 #[inline] bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>)751 pub unsafe fn bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>) { 752 struct Cmd { 753 pipeline: Arc<ComputePipeline>, 754 } 755 756 impl Command for Cmd { 757 fn name(&self) -> &'static str { 758 "bind_pipeline_compute" 759 } 760 761 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 762 out.bind_pipeline_compute(&self.pipeline); 763 } 764 } 765 766 self.current_state.pipeline_compute = Some(pipeline.clone()); 767 self.commands.push(Box::new(Cmd { pipeline })); 768 } 769 770 /// Calls `vkCmdBindPipeline` on the builder with a graphics pipeline. 771 #[inline] bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>)772 pub unsafe fn bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>) { 773 struct Cmd { 774 pipeline: Arc<GraphicsPipeline>, 775 } 776 777 impl Command for Cmd { 778 fn name(&self) -> &'static str { 779 "bind_pipeline_graphics" 780 } 781 782 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 783 out.bind_pipeline_graphics(&self.pipeline); 784 } 785 } 786 787 // Reset any states that are fixed in the new pipeline. The pipeline bind command will 788 // overwrite these states. 789 self.current_state.reset_dynamic_states( 790 pipeline 791 .dynamic_states() 792 .filter(|(_, d)| !d) // not dynamic 793 .map(|(s, _)| s), 794 ); 795 self.current_state.pipeline_graphics = Some(pipeline.clone()); 796 self.commands.push(Box::new(Cmd { pipeline })); 797 } 798 799 /// Starts the process of binding vertex buffers. Returns an intermediate struct which can be 800 /// used to add the buffers. 801 #[inline] bind_vertex_buffers(&mut self) -> SyncCommandBufferBuilderBindVertexBuffer<'_>802 pub fn bind_vertex_buffers(&mut self) -> SyncCommandBufferBuilderBindVertexBuffer<'_> { 803 SyncCommandBufferBuilderBindVertexBuffer { 804 builder: self, 805 inner: UnsafeCommandBufferBuilderBindVertexBuffer::new(), 806 buffers: SmallVec::new(), 807 } 808 } 809 810 /// Calls `vkCmdPushConstants` on the builder. push_constants<D>( &mut self, pipeline_layout: Arc<PipelineLayout>, stages: ShaderStages, offset: u32, size: u32, data: &D, ) where D: ?Sized + Send + Sync + 'static,811 pub unsafe fn push_constants<D>( 812 &mut self, 813 pipeline_layout: Arc<PipelineLayout>, 814 stages: ShaderStages, 815 offset: u32, 816 size: u32, 817 data: &D, 818 ) where 819 D: ?Sized + Send + Sync + 'static, 820 { 821 struct Cmd { 822 pipeline_layout: Arc<PipelineLayout>, 823 stages: ShaderStages, 824 offset: u32, 825 size: u32, 826 data: Box<[u8]>, 827 } 828 829 impl Command for Cmd { 830 fn name(&self) -> &'static str { 831 "push_constants" 832 } 833 834 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 835 out.push_constants::<[u8]>( 836 &self.pipeline_layout, 837 self.stages, 838 self.offset, 839 self.size, 840 &self.data, 841 ); 842 } 843 } 844 845 debug_assert!(size_of_val(data) >= size as usize); 846 847 let mut out = Vec::with_capacity(size as usize); 848 ptr::copy::<u8>( 849 data as *const D as *const u8, 850 out.as_mut_ptr(), 851 size as usize, 852 ); 853 out.set_len(size as usize); 854 855 self.commands.push(Box::new(Cmd { 856 pipeline_layout: pipeline_layout.clone(), 857 stages, 858 offset, 859 size, 860 data: out.into(), 861 })); 862 863 // TODO: Push constant invalidations. 864 // The Vulkan spec currently is unclear about this, so Vulkano currently just marks 865 // push constants as set, and never unsets them. See: 866 // https://github.com/KhronosGroup/Vulkan-Docs/issues/1485 867 // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2711 868 self.current_state 869 .push_constants 870 .insert(offset..offset + size); 871 self.current_state.push_constants_pipeline_layout = Some(pipeline_layout); 872 } 873 874 /// Calls `vkCmdPushDescriptorSetKHR` on the builder. push_descriptor_set( &mut self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: Arc<PipelineLayout>, set_num: u32, descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>, )875 pub unsafe fn push_descriptor_set( 876 &mut self, 877 pipeline_bind_point: PipelineBindPoint, 878 pipeline_layout: Arc<PipelineLayout>, 879 set_num: u32, 880 descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>, 881 ) { 882 struct Cmd { 883 pipeline_bind_point: PipelineBindPoint, 884 pipeline_layout: Arc<PipelineLayout>, 885 set_num: u32, 886 descriptor_writes: SmallVec<[WriteDescriptorSet; 8]>, 887 } 888 889 impl Command for Cmd { 890 fn name(&self) -> &'static str { 891 "push_descriptor_set" 892 } 893 894 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 895 out.push_descriptor_set( 896 self.pipeline_bind_point, 897 &self.pipeline_layout, 898 self.set_num, 899 &self.descriptor_writes, 900 ); 901 } 902 } 903 904 let descriptor_writes: SmallVec<[WriteDescriptorSet; 8]> = 905 descriptor_writes.into_iter().collect(); 906 907 let state = self.current_state.invalidate_descriptor_sets( 908 pipeline_bind_point, 909 pipeline_layout.clone(), 910 set_num, 911 1, 912 ); 913 let layout = state.pipeline_layout.set_layouts()[set_num as usize].as_ref(); 914 debug_assert!(layout.push_descriptor()); 915 916 let set_resources = match state 917 .descriptor_sets 918 .entry(set_num) 919 .or_insert_with(|| SetOrPush::Push(DescriptorSetResources::new(layout, 0))) 920 { 921 SetOrPush::Push(set_resources) => set_resources, 922 _ => unreachable!(), 923 }; 924 925 for write in &descriptor_writes { 926 set_resources.update(write); 927 } 928 929 self.commands.push(Box::new(Cmd { 930 pipeline_bind_point, 931 pipeline_layout, 932 set_num, 933 descriptor_writes, 934 })); 935 } 936 } 937 938 pub struct SyncCommandBufferBuilderBindDescriptorSets<'b> { 939 builder: &'b mut SyncCommandBufferBuilder, 940 descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>, 941 } 942 943 impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> { 944 /// Adds a descriptor set to the list. add(&mut self, descriptor_set: impl Into<DescriptorSetWithOffsets>)945 pub fn add(&mut self, descriptor_set: impl Into<DescriptorSetWithOffsets>) { 946 self.descriptor_sets.push(descriptor_set.into()); 947 } 948 949 #[inline] submit( self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: Arc<PipelineLayout>, first_set: u32, )950 pub unsafe fn submit( 951 self, 952 pipeline_bind_point: PipelineBindPoint, 953 pipeline_layout: Arc<PipelineLayout>, 954 first_set: u32, 955 ) { 956 if self.descriptor_sets.is_empty() { 957 return; 958 } 959 960 struct Cmd { 961 descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>, 962 pipeline_bind_point: PipelineBindPoint, 963 pipeline_layout: Arc<PipelineLayout>, 964 first_set: u32, 965 } 966 967 impl Command for Cmd { 968 fn name(&self) -> &'static str { 969 "bind_descriptor_sets" 970 } 971 972 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 973 let descriptor_sets = self.descriptor_sets.iter().map(|x| x.as_ref().0.inner()); 974 let dynamic_offsets = self 975 .descriptor_sets 976 .iter() 977 .flat_map(|x| x.as_ref().1.iter().copied()); 978 979 out.bind_descriptor_sets( 980 self.pipeline_bind_point, 981 &self.pipeline_layout, 982 self.first_set, 983 descriptor_sets, 984 dynamic_offsets, 985 ); 986 } 987 } 988 989 let state = self.builder.current_state.invalidate_descriptor_sets( 990 pipeline_bind_point, 991 pipeline_layout.clone(), 992 first_set, 993 self.descriptor_sets.len() as u32, 994 ); 995 996 for (set_num, set) in self.descriptor_sets.iter().enumerate() { 997 state 998 .descriptor_sets 999 .insert(first_set + set_num as u32, SetOrPush::Set(set.clone())); 1000 } 1001 1002 self.builder.commands.push(Box::new(Cmd { 1003 descriptor_sets: self.descriptor_sets, 1004 pipeline_bind_point, 1005 pipeline_layout, 1006 first_set, 1007 })); 1008 } 1009 } 1010 1011 /// Prototype for a `vkCmdBindVertexBuffers`. 1012 pub struct SyncCommandBufferBuilderBindVertexBuffer<'a> { 1013 builder: &'a mut SyncCommandBufferBuilder, 1014 inner: UnsafeCommandBufferBuilderBindVertexBuffer, 1015 buffers: SmallVec<[Subbuffer<[u8]>; 4]>, 1016 } 1017 1018 impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> { 1019 /// Adds a buffer to the list. 1020 #[inline] add(&mut self, buffer: Subbuffer<[u8]>)1021 pub fn add(&mut self, buffer: Subbuffer<[u8]>) { 1022 self.inner.add(&buffer); 1023 self.buffers.push(buffer); 1024 } 1025 1026 #[inline] submit(self, first_set: u32)1027 pub unsafe fn submit(self, first_set: u32) { 1028 struct Cmd { 1029 first_set: u32, 1030 inner: Mutex<Option<UnsafeCommandBufferBuilderBindVertexBuffer>>, 1031 _buffers: SmallVec<[Subbuffer<[u8]>; 4]>, 1032 } 1033 1034 impl Command for Cmd { 1035 fn name(&self) -> &'static str { 1036 "bind_vertex_buffers" 1037 } 1038 1039 unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { 1040 out.bind_vertex_buffers(self.first_set, self.inner.lock().take().unwrap()); 1041 } 1042 } 1043 1044 for (i, buffer) in self.buffers.iter().enumerate() { 1045 self.builder 1046 .current_state 1047 .vertex_buffers 1048 .insert(first_set + i as u32, buffer.clone()); 1049 } 1050 1051 self.builder.commands.push(Box::new(Cmd { 1052 first_set, 1053 inner: Mutex::new(Some(self.inner)), 1054 _buffers: self.buffers, 1055 })); 1056 } 1057 } 1058 1059 impl UnsafeCommandBufferBuilder { 1060 /// Calls `vkCmdBindDescriptorSets` on the builder. 1061 /// 1062 /// Does nothing if the list of descriptor sets is empty, as it would be a no-op and isn't a 1063 /// valid usage of the command anyway. 1064 #[inline] bind_descriptor_sets<'s>( &mut self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: &PipelineLayout, first_set: u32, sets: impl IntoIterator<Item = &'s UnsafeDescriptorSet>, dynamic_offsets: impl IntoIterator<Item = u32>, )1065 pub unsafe fn bind_descriptor_sets<'s>( 1066 &mut self, 1067 pipeline_bind_point: PipelineBindPoint, 1068 pipeline_layout: &PipelineLayout, 1069 first_set: u32, 1070 sets: impl IntoIterator<Item = &'s UnsafeDescriptorSet>, 1071 dynamic_offsets: impl IntoIterator<Item = u32>, 1072 ) { 1073 let fns = self.device.fns(); 1074 1075 let sets: SmallVec<[_; 12]> = sets.into_iter().map(|s| s.handle()).collect(); 1076 if sets.is_empty() { 1077 return; 1078 } 1079 let dynamic_offsets: SmallVec<[u32; 32]> = dynamic_offsets.into_iter().collect(); 1080 1081 let num_bindings = sets.len() as u32; 1082 debug_assert!(first_set + num_bindings <= pipeline_layout.set_layouts().len() as u32); 1083 1084 (fns.v1_0.cmd_bind_descriptor_sets)( 1085 self.handle, 1086 pipeline_bind_point.into(), 1087 pipeline_layout.handle(), 1088 first_set, 1089 num_bindings, 1090 sets.as_ptr(), 1091 dynamic_offsets.len() as u32, 1092 dynamic_offsets.as_ptr(), 1093 ); 1094 } 1095 1096 /// Calls `vkCmdBindIndexBuffer` on the builder. 1097 #[inline] bind_index_buffer(&mut self, buffer: &Subbuffer<[u8]>, index_type: IndexType)1098 pub unsafe fn bind_index_buffer(&mut self, buffer: &Subbuffer<[u8]>, index_type: IndexType) { 1099 let fns = self.device.fns(); 1100 1101 debug_assert!(buffer.offset() < buffer.buffer().size()); 1102 debug_assert!(buffer 1103 .buffer() 1104 .usage() 1105 .intersects(BufferUsage::INDEX_BUFFER)); 1106 1107 (fns.v1_0.cmd_bind_index_buffer)( 1108 self.handle, 1109 buffer.buffer().handle(), 1110 buffer.offset(), 1111 index_type.into(), 1112 ); 1113 } 1114 1115 /// Calls `vkCmdBindPipeline` on the builder with a compute pipeline. 1116 #[inline] bind_pipeline_compute(&mut self, pipeline: &ComputePipeline)1117 pub unsafe fn bind_pipeline_compute(&mut self, pipeline: &ComputePipeline) { 1118 let fns = self.device.fns(); 1119 (fns.v1_0.cmd_bind_pipeline)( 1120 self.handle, 1121 ash::vk::PipelineBindPoint::COMPUTE, 1122 pipeline.handle(), 1123 ); 1124 } 1125 1126 /// Calls `vkCmdBindPipeline` on the builder with a graphics pipeline. 1127 #[inline] bind_pipeline_graphics(&mut self, pipeline: &GraphicsPipeline)1128 pub unsafe fn bind_pipeline_graphics(&mut self, pipeline: &GraphicsPipeline) { 1129 let fns = self.device.fns(); 1130 (fns.v1_0.cmd_bind_pipeline)( 1131 self.handle, 1132 ash::vk::PipelineBindPoint::GRAPHICS, 1133 pipeline.handle(), 1134 ); 1135 } 1136 1137 /// Calls `vkCmdBindVertexBuffers` on the builder. 1138 /// 1139 /// Does nothing if the list of buffers is empty, as it would be a no-op and isn't a valid 1140 /// usage of the command anyway. 1141 // TODO: vkCmdBindVertexBuffers2EXT 1142 #[inline] bind_vertex_buffers( &mut self, first_binding: u32, params: UnsafeCommandBufferBuilderBindVertexBuffer, )1143 pub unsafe fn bind_vertex_buffers( 1144 &mut self, 1145 first_binding: u32, 1146 params: UnsafeCommandBufferBuilderBindVertexBuffer, 1147 ) { 1148 debug_assert_eq!(params.raw_buffers.len(), params.offsets.len()); 1149 1150 if params.raw_buffers.is_empty() { 1151 return; 1152 } 1153 1154 let fns = self.device.fns(); 1155 1156 let num_bindings = params.raw_buffers.len() as u32; 1157 1158 debug_assert!({ 1159 let max_bindings = self 1160 .device 1161 .physical_device() 1162 .properties() 1163 .max_vertex_input_bindings; 1164 first_binding + num_bindings <= max_bindings 1165 }); 1166 1167 (fns.v1_0.cmd_bind_vertex_buffers)( 1168 self.handle, 1169 first_binding, 1170 num_bindings, 1171 params.raw_buffers.as_ptr(), 1172 params.offsets.as_ptr(), 1173 ); 1174 } 1175 1176 /// Calls `vkCmdPushConstants` on the builder. push_constants<D>( &mut self, pipeline_layout: &PipelineLayout, stages: ShaderStages, offset: u32, size: u32, data: &D, ) where D: BufferContents + ?Sized,1177 pub unsafe fn push_constants<D>( 1178 &mut self, 1179 pipeline_layout: &PipelineLayout, 1180 stages: ShaderStages, 1181 offset: u32, 1182 size: u32, 1183 data: &D, 1184 ) where 1185 D: BufferContents + ?Sized, 1186 { 1187 let fns = self.device.fns(); 1188 1189 debug_assert!(!stages.is_empty()); 1190 debug_assert!(size > 0); 1191 debug_assert_eq!(size % 4, 0); 1192 debug_assert_eq!(offset % 4, 0); 1193 debug_assert!(size_of_val(data) >= size as usize); 1194 1195 (fns.v1_0.cmd_push_constants)( 1196 self.handle, 1197 pipeline_layout.handle(), 1198 stages.into(), 1199 offset, 1200 size, 1201 data as *const _ as *const _, 1202 ); 1203 } 1204 1205 /// Calls `vkCmdPushDescriptorSetKHR` on the builder. 1206 /// 1207 /// If the list is empty then the command is automatically ignored. push_descriptor_set<'a>( &mut self, pipeline_bind_point: PipelineBindPoint, pipeline_layout: &PipelineLayout, set_num: u32, descriptor_writes: impl IntoIterator<Item = &'a WriteDescriptorSet>, )1208 pub unsafe fn push_descriptor_set<'a>( 1209 &mut self, 1210 pipeline_bind_point: PipelineBindPoint, 1211 pipeline_layout: &PipelineLayout, 1212 set_num: u32, 1213 descriptor_writes: impl IntoIterator<Item = &'a WriteDescriptorSet>, 1214 ) { 1215 debug_assert!(self.device.enabled_extensions().khr_push_descriptor); 1216 1217 let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = descriptor_writes 1218 .into_iter() 1219 .map(|write| { 1220 let binding = 1221 &pipeline_layout.set_layouts()[set_num as usize].bindings()[&write.binding()]; 1222 1223 ( 1224 write.to_vulkan_info(binding.descriptor_type), 1225 write.to_vulkan(ash::vk::DescriptorSet::null(), binding.descriptor_type), 1226 ) 1227 }) 1228 .unzip(); 1229 1230 if writes.is_empty() { 1231 return; 1232 } 1233 1234 // Set the info pointers separately. 1235 for (info, write) in infos.iter().zip(writes.iter_mut()) { 1236 match info { 1237 DescriptorWriteInfo::Image(info) => { 1238 write.descriptor_count = info.len() as u32; 1239 write.p_image_info = info.as_ptr(); 1240 } 1241 DescriptorWriteInfo::Buffer(info) => { 1242 write.descriptor_count = info.len() as u32; 1243 write.p_buffer_info = info.as_ptr(); 1244 } 1245 DescriptorWriteInfo::BufferView(info) => { 1246 write.descriptor_count = info.len() as u32; 1247 write.p_texel_buffer_view = info.as_ptr(); 1248 } 1249 } 1250 1251 debug_assert!(write.descriptor_count != 0); 1252 } 1253 1254 let fns = self.device.fns(); 1255 1256 (fns.khr_push_descriptor.cmd_push_descriptor_set_khr)( 1257 self.handle, 1258 pipeline_bind_point.into(), 1259 pipeline_layout.handle(), 1260 set_num, 1261 writes.len() as u32, 1262 writes.as_ptr(), 1263 ); 1264 } 1265 } 1266 1267 /// Prototype for a `vkCmdBindVertexBuffers`. 1268 #[derive(Debug)] 1269 pub struct UnsafeCommandBufferBuilderBindVertexBuffer { 1270 // Raw handles of the buffers to bind. 1271 pub raw_buffers: SmallVec<[ash::vk::Buffer; 4]>, 1272 // Raw offsets of the buffers to bind. 1273 pub offsets: SmallVec<[DeviceSize; 4]>, 1274 } 1275 1276 impl UnsafeCommandBufferBuilderBindVertexBuffer { 1277 /// Builds a new empty list. 1278 #[inline] new() -> UnsafeCommandBufferBuilderBindVertexBuffer1279 pub fn new() -> UnsafeCommandBufferBuilderBindVertexBuffer { 1280 UnsafeCommandBufferBuilderBindVertexBuffer { 1281 raw_buffers: SmallVec::new(), 1282 offsets: SmallVec::new(), 1283 } 1284 } 1285 1286 /// Adds a buffer to the list. 1287 #[inline] add(&mut self, subbuffer: &Subbuffer<[u8]>)1288 pub fn add(&mut self, subbuffer: &Subbuffer<[u8]>) { 1289 debug_assert!(subbuffer 1290 .buffer() 1291 .usage() 1292 .intersects(BufferUsage::VERTEX_BUFFER)); 1293 self.raw_buffers.push(subbuffer.buffer().handle()); 1294 self.offsets.push(subbuffer.offset()); 1295 } 1296 } 1297 1298 #[derive(Clone, Debug)] 1299 pub(in super::super) enum BindPushError { 1300 DescriptorSetUpdateError(DescriptorSetUpdateError), 1301 1302 RequirementNotMet { 1303 required_for: &'static str, 1304 requires_one_of: RequiresOneOf, 1305 }, 1306 1307 /// The element of `descriptor_sets` being bound to a slot is not compatible with the 1308 /// corresponding slot in `pipeline_layout`. 1309 DescriptorSetNotCompatible { 1310 set_num: u32, 1311 }, 1312 1313 /// The descriptor set number being pushed is not defined for push descriptor sets in the 1314 /// pipeline layout. 1315 DescriptorSetNotPush { 1316 set_num: u32, 1317 }, 1318 1319 /// The highest descriptor set slot being bound is greater than the number of sets in 1320 /// `pipeline_layout`. 1321 DescriptorSetOutOfRange { 1322 set_num: u32, 1323 pipeline_layout_set_count: u32, 1324 }, 1325 1326 /// In an element of `descriptor_sets`, the number of provided dynamic offsets does not match 1327 /// the number required by the descriptor set. 1328 DynamicOffsetCountMismatch { 1329 set_num: u32, 1330 provided_count: usize, 1331 required_count: usize, 1332 }, 1333 1334 /// In an element of `descriptor_sets`, a provided dynamic offset 1335 /// is not a multiple of the value of the [`min_uniform_buffer_offset_alignment`] or 1336 /// [`min_storage_buffer_offset_alignment`] property. 1337 /// 1338 /// min_uniform_buffer_offset_alignment: crate::device::Properties::min_uniform_buffer_offset_alignment 1339 /// min_storage_buffer_offset_alignment: crate::device::Properties::min_storage_buffer_offset_alignment 1340 DynamicOffsetNotAligned { 1341 set_num: u32, 1342 binding_num: u32, 1343 index: u32, 1344 offset: u32, 1345 required_alignment: DeviceAlignment, 1346 }, 1347 1348 /// In an element of `descriptor_sets`, a provided dynamic offset, when added to the end of the 1349 /// buffer range bound to the descriptor set, is greater than the size of the buffer. 1350 DynamicOffsetOutOfBufferBounds { 1351 set_num: u32, 1352 binding_num: u32, 1353 index: u32, 1354 offset: u32, 1355 range_end: DeviceSize, 1356 buffer_size: DeviceSize, 1357 }, 1358 1359 /// An index buffer is missing the `index_buffer` usage. 1360 IndexBufferMissingUsage, 1361 1362 /// The `max_vertex_input_bindings` limit has been exceeded. 1363 MaxVertexInputBindingsExceeded { 1364 _binding_count: u32, 1365 _max: u32, 1366 }, 1367 1368 /// The queue family doesn't allow this operation. 1369 NotSupportedByQueueFamily, 1370 1371 /// The newly set pipeline has color attachment formats that do not match the 1372 /// previously used pipeline. 1373 PreviousPipelineColorAttachmentFormatMismatch, 1374 1375 /// The newly set pipeline has a depth attachment format that does not match the 1376 /// previously used pipeline. 1377 PreviousPipelineDepthAttachmentFormatMismatch, 1378 1379 /// The newly set pipeline has a stencil attachment format that does not match the 1380 /// previously used pipeline. 1381 PreviousPipelineStencilAttachmentFormatMismatch, 1382 1383 /// The push constants data to be written at an offset is not included in any push constant 1384 /// range of the pipeline layout. 1385 PushConstantsDataOutOfRange { 1386 offset: u32, 1387 }, 1388 1389 /// The push constants offset is not a multiple of 4. 1390 PushConstantsOffsetNotAligned, 1391 1392 /// The push constants size is not a multiple of 4. 1393 PushConstantsSizeNotAligned, 1394 1395 /// A vertex buffer is missing the `vertex_buffer` usage. 1396 VertexBufferMissingUsage, 1397 } 1398 1399 impl error::Error for BindPushError { source(&self) -> Option<&(dyn error::Error + 'static)>1400 fn source(&self) -> Option<&(dyn error::Error + 'static)> { 1401 match self { 1402 BindPushError::DescriptorSetUpdateError(err) => Some(err), 1403 _ => None, 1404 } 1405 } 1406 } 1407 1408 impl Display for BindPushError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1409 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 1410 match self { 1411 Self::RequirementNotMet { 1412 required_for, 1413 requires_one_of, 1414 } => write!( 1415 f, 1416 "a requirement was not met for: {}; requires one of: {}", 1417 required_for, requires_one_of, 1418 ), 1419 Self::DescriptorSetUpdateError(_) => write!(f, "a DescriptorSetUpdateError"), 1420 Self::DescriptorSetNotCompatible { set_num } => write!( 1421 f, 1422 "the element of `descriptor_sets` being bound to slot {} is not compatible with \ 1423 the corresponding slot in `pipeline_layout`", 1424 set_num, 1425 ), 1426 Self::DescriptorSetNotPush { set_num } => write!( 1427 f, 1428 "the descriptor set number being pushed ({}) is not defined for push descriptor \ 1429 sets in the pipeline layout", 1430 set_num, 1431 ), 1432 Self::DescriptorSetOutOfRange { 1433 set_num, 1434 pipeline_layout_set_count, 1435 } => write!( 1436 f, 1437 "the highest descriptor set slot being bound ({}) is greater than the number of \ 1438 sets in `pipeline_layout` ({})", 1439 set_num, pipeline_layout_set_count, 1440 ), 1441 Self::DynamicOffsetCountMismatch { 1442 set_num, 1443 provided_count, 1444 required_count, 1445 } => write!( 1446 f, 1447 "in the element of `descriptor_sets` being bound to slot {}, the number of \ 1448 provided dynamic offsets ({}) does not match the number required by the \ 1449 descriptor set ({})", 1450 set_num, provided_count, required_count, 1451 ), 1452 Self::DynamicOffsetNotAligned { 1453 set_num, 1454 binding_num, 1455 index, 1456 offset, 1457 required_alignment, 1458 } => write!( 1459 f, 1460 "in the element of `descriptor_sets` being bound to slot {}, the dynamic offset \ 1461 provided for binding {} index {} ({}) is not a multiple of the value of the \ 1462 `min_uniform_buffer_offset_alignment` or `min_storage_buffer_offset_alignment` \ 1463 property ({:?})", 1464 set_num, binding_num, index, offset, required_alignment, 1465 ), 1466 Self::DynamicOffsetOutOfBufferBounds { 1467 set_num, 1468 binding_num, 1469 index, 1470 offset, 1471 range_end, 1472 buffer_size, 1473 } => write!( 1474 f, 1475 "in the element of `descriptor_sets` being bound to slot {}, the dynamic offset \ 1476 provided for binding {} index {} ({}), when added to the end of the buffer range \ 1477 bound to the descriptor set ({}), is greater than the size of the buffer ({})", 1478 set_num, binding_num, index, offset, range_end, buffer_size, 1479 ), 1480 Self::IndexBufferMissingUsage => { 1481 write!(f, "an index buffer is missing the `index_buffer` usage") 1482 } 1483 Self::MaxVertexInputBindingsExceeded { .. } => { 1484 write!(f, "the `max_vertex_input_bindings` limit has been exceeded") 1485 } 1486 Self::NotSupportedByQueueFamily => { 1487 write!(f, "the queue family doesn't allow this operation") 1488 } 1489 Self::PreviousPipelineColorAttachmentFormatMismatch => write!( 1490 f, 1491 "the newly set pipeline has color attachment formats that do not match the \ 1492 previously used pipeline", 1493 ), 1494 Self::PreviousPipelineDepthAttachmentFormatMismatch => write!( 1495 f, 1496 "the newly set pipeline has a depth attachment format that does not match the \ 1497 previously used pipeline", 1498 ), 1499 Self::PreviousPipelineStencilAttachmentFormatMismatch => write!( 1500 f, 1501 "the newly set pipeline has a stencil attachment format that does not match the \ 1502 previously used pipeline", 1503 ), 1504 Self::PushConstantsDataOutOfRange { offset } => write!( 1505 f, 1506 "the push constants data to be written at offset {} is not included in any push \ 1507 constant range of the pipeline layout", 1508 offset, 1509 ), 1510 Self::PushConstantsOffsetNotAligned => { 1511 write!(f, "the push constants offset is not a multiple of 4") 1512 } 1513 Self::PushConstantsSizeNotAligned => { 1514 write!(f, "the push constants size is not a multiple of 4") 1515 } 1516 Self::VertexBufferMissingUsage => { 1517 write!(f, "a vertex buffer is missing the `vertex_buffer` usage") 1518 } 1519 } 1520 } 1521 } 1522 1523 impl From<DescriptorSetUpdateError> for BindPushError { from(err: DescriptorSetUpdateError) -> Self1524 fn from(err: DescriptorSetUpdateError) -> Self { 1525 Self::DescriptorSetUpdateError(err) 1526 } 1527 } 1528 1529 impl From<RequirementNotMet> for BindPushError { from(err: RequirementNotMet) -> Self1530 fn from(err: RequirementNotMet) -> Self { 1531 Self::RequirementNotMet { 1532 required_for: err.required_for, 1533 requires_one_of: err.requires_one_of, 1534 } 1535 } 1536 } 1537