1use crate::{
2 buffer::{BufferContents, BufferUsage, IndexBuffer, Subbuffer},
3 command_buffer::{auto::SetOrPush, sys::RecordingCommandBuffer, AutoCommandBufferBuilder},
4 descriptor_set::{
5 layout::{DescriptorBindingFlags, DescriptorSetLayoutCreateFlags, DescriptorType},
6 sys::RawDescriptorSet,
7 DescriptorBindingResources, DescriptorBufferInfo, DescriptorSetResources,
8 DescriptorSetWithOffsets, DescriptorSetsCollection, WriteDescriptorSet,
9 },
10 device::{DeviceOwned, QueueFlags},
11 memory::is_aligned,
12 pipeline::{
13 graphics::vertex_input::VertexBuffersCollection, ray_tracing::RayTracingPipeline,
14 ComputePipeline, GraphicsPipeline, PipelineBindPoint, PipelineLayout,
15 },
16 DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError, Version, VulkanObject,
17};
18use smallvec::SmallVec;
19use std::{cmp::min, ffi::c_void, mem::size_of, ptr, sync::Arc};
20
21impl<L> AutoCommandBufferBuilder<L> {
25 pub fn bind_descriptor_sets(
27 &mut self,
28 pipeline_bind_point: PipelineBindPoint,
29 pipeline_layout: Arc<PipelineLayout>,
30 first_set: u32,
31 descriptor_sets: impl DescriptorSetsCollection,
32 ) -> Result<&mut Self, Box<ValidationError>> {
33 let descriptor_sets = descriptor_sets.into_vec();
34 self.validate_bind_descriptor_sets(
35 pipeline_bind_point,
36 &pipeline_layout,
37 first_set,
38 &descriptor_sets,
39 )?;
40
41 Ok(unsafe {
42 self.bind_descriptor_sets_unchecked(
43 pipeline_bind_point,
44 pipeline_layout,
45 first_set,
46 descriptor_sets,
47 )
48 })
49 }
50
51 fn validate_bind_descriptor_sets(
54 &self,
55 pipeline_bind_point: PipelineBindPoint,
56 pipeline_layout: &PipelineLayout,
57 first_set: u32,
58 descriptor_sets: &[DescriptorSetWithOffsets],
59 ) -> Result<(), Box<ValidationError>> {
60 self.inner.validate_bind_descriptor_sets_inner(
61 pipeline_bind_point,
62 pipeline_layout,
63 first_set,
64 descriptor_sets.len(),
65 )?;
66
67 let properties = self.device().physical_device().properties();
68
69 for (descriptor_sets_index, set) in descriptor_sets.iter().enumerate() {
70 let set_num = first_set + descriptor_sets_index as u32;
71 let (set, dynamic_offsets) = set.as_ref();
72
73 assert_eq!(self.device(), set.device());
75
76 let set_layout = set.layout();
77 let pipeline_set_layout = &pipeline_layout.set_layouts()[set_num as usize];
78
79 if !pipeline_set_layout.is_compatible_with(set_layout) {
80 return Err(Box::new(ValidationError {
81 problem: format!(
82 "`descriptor_sets[{0}]` (for set number {1}) is not compatible with \
83 `pipeline_layout.set_layouts()[{1}]`",
84 descriptor_sets_index, set_num
85 )
86 .into(),
87 vuids: &["VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358"],
88 ..Default::default()
89 }));
90 }
91
92 let mut dynamic_offsets_remaining = dynamic_offsets;
93 let mut required_dynamic_offset_count = 0;
94
95 for (&binding_num, binding) in set_layout.bindings() {
96 let required_alignment = match binding.descriptor_type {
97 DescriptorType::UniformBufferDynamic => {
98 properties.min_uniform_buffer_offset_alignment
99 }
100 DescriptorType::StorageBufferDynamic => {
101 properties.min_storage_buffer_offset_alignment
102 }
103 _ => continue,
104 };
105
106 let count = if binding
107 .binding_flags
108 .intersects(DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT)
109 {
110 set.variable_descriptor_count()
111 } else {
112 binding.descriptor_count
113 } as usize;
114
115 required_dynamic_offset_count += count;
116
117 if !dynamic_offsets_remaining.is_empty() {
118 let split_index = min(count, dynamic_offsets_remaining.len());
119 let dynamic_offsets = &dynamic_offsets_remaining[..split_index];
120 dynamic_offsets_remaining = &dynamic_offsets_remaining[split_index..];
121
122 let resources = set.resources();
123 let elements = match resources.binding(binding_num) {
124 Some(DescriptorBindingResources::Buffer(elements)) => elements.as_slice(),
125 _ => unreachable!(),
126 };
127
128 for (index, (&offset, element)) in
129 dynamic_offsets.iter().zip(elements).enumerate()
130 {
131 if !is_aligned(offset as DeviceSize, required_alignment) {
132 match binding.descriptor_type {
133 DescriptorType::UniformBufferDynamic => {
134 return Err(Box::new(ValidationError {
135 problem: format!(
136 "the descriptor type of `descriptor_sets[{}]` \
137 (for set number {}) is \
138 `DescriptorType::UniformBufferDynamic`, but the \
139 dynamic offset provided for binding {} index {} is \
140 not aligned to the \
141 `min_uniform_buffer_offset_alignment` device property",
142 descriptor_sets_index, set_num, binding_num, index,
143 )
144 .into(),
145 vuids: &[
146 "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971",
147 ],
148 ..Default::default()
149 }));
150 }
151 DescriptorType::StorageBufferDynamic => {
152 return Err(Box::new(ValidationError {
153 problem: format!(
154 "the descriptor type of `descriptor_sets[{}]` \
155 (for set number {}) is \
156 `DescriptorType::StorageBufferDynamic`, but the \
157 dynamic offset provided for binding {} index {} is \
158 not aligned to the \
159 `min_storage_buffer_offset_alignment` device property",
160 descriptor_sets_index, set_num, binding_num, index,
161 )
162 .into(),
163 vuids: &[
164 "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01972",
165 ],
166 ..Default::default()
167 }));
168 }
169 _ => unreachable!(),
170 }
171 }
172
173 if let Some(buffer_info) = element {
174 let DescriptorBufferInfo { buffer, range } = buffer_info;
175
176 if offset as DeviceSize + range.end > buffer.size() {
177 return Err(Box::new(ValidationError {
178 problem: format!(
179 "the dynamic offset of `descriptor_sets[{}]` \
180 (for set number {}) for binding {} index {}, when \
181 added to `range.end` of the descriptor write, is \
182 greater than the size of the bound buffer",
183 descriptor_sets_index, set_num, binding_num, index,
184 )
185 .into(),
186 vuids: &["VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979"],
187 ..Default::default()
188 }));
189 }
190 }
191 }
192 }
193 }
194
195 if dynamic_offsets.len() != required_dynamic_offset_count {
196 return Err(Box::new(ValidationError {
197 problem: format!(
198 "the number of dynamic offsets provided for `descriptor_sets[{}]` \
199 (for set number {}) does not equal the number required ({})",
200 descriptor_sets_index, set_num, required_dynamic_offset_count,
201 )
202 .into(),
203 vuids: &["VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359"],
204 ..Default::default()
205 }));
206 }
207 }
208
209 Ok(())
210 }
211
212 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
213 pub unsafe fn bind_descriptor_sets_unchecked(
214 &mut self,
215 pipeline_bind_point: PipelineBindPoint,
216 pipeline_layout: Arc<PipelineLayout>,
217 first_set: u32,
218 descriptor_sets: impl DescriptorSetsCollection,
219 ) -> &mut Self {
220 let descriptor_sets = descriptor_sets.into_vec();
221 if descriptor_sets.is_empty() {
222 return self;
223 }
224
225 let state = self.builder_state.invalidate_descriptor_sets(
226 pipeline_bind_point,
227 pipeline_layout.clone(),
228 first_set,
229 descriptor_sets.len() as u32,
230 );
231
232 for (set_num, set) in descriptor_sets.iter().enumerate() {
233 state
234 .descriptor_sets
235 .insert(first_set + set_num as u32, SetOrPush::Set(set.clone()));
236 }
237
238 self.add_command(
239 "bind_descriptor_sets",
240 Default::default(),
241 move |out: &mut RecordingCommandBuffer| {
242 let dynamic_offsets: SmallVec<[_; 32]> = descriptor_sets
243 .iter()
244 .flat_map(|x| x.as_ref().1.iter().copied())
245 .collect();
246 let descriptor_sets: SmallVec<[_; 12]> = descriptor_sets
247 .iter()
248 .map(|x| x.as_ref().0.as_raw())
249 .collect();
250
251 unsafe {
252 out.bind_descriptor_sets_unchecked(
253 pipeline_bind_point,
254 &pipeline_layout,
255 first_set,
256 &descriptor_sets,
257 &dynamic_offsets,
258 )
259 };
260 },
261 );
262
263 self
264 }
265
266 pub fn bind_index_buffer(
268 &mut self,
269 index_buffer: impl Into<IndexBuffer>,
270 ) -> Result<&mut Self, Box<ValidationError>> {
271 let index_buffer = index_buffer.into();
272 self.validate_bind_index_buffer(&index_buffer)?;
273
274 Ok(unsafe { self.bind_index_buffer_unchecked(index_buffer) })
275 }
276
277 fn validate_bind_index_buffer(
278 &self,
279 index_buffer: &IndexBuffer,
280 ) -> Result<(), Box<ValidationError>> {
281 self.inner.validate_bind_index_buffer(index_buffer)?;
282
283 Ok(())
284 }
285
286 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
287 pub unsafe fn bind_index_buffer_unchecked(
288 &mut self,
289 index_buffer: impl Into<IndexBuffer>,
290 ) -> &mut Self {
291 let index_buffer = index_buffer.into();
292 self.builder_state.index_buffer = Some(index_buffer.clone());
293 self.add_command(
294 "bind_index_buffer",
295 Default::default(),
296 move |out: &mut RecordingCommandBuffer| {
297 unsafe { out.bind_index_buffer_unchecked(&index_buffer) };
298 },
299 );
300
301 self
302 }
303
304 pub fn bind_pipeline_compute(
306 &mut self,
307 pipeline: Arc<ComputePipeline>,
308 ) -> Result<&mut Self, Box<ValidationError>> {
309 self.validate_bind_pipeline_compute(&pipeline)?;
310
311 Ok(unsafe { self.bind_pipeline_compute_unchecked(pipeline) })
312 }
313
314 fn validate_bind_pipeline_compute(
315 &self,
316 pipeline: &ComputePipeline,
317 ) -> Result<(), Box<ValidationError>> {
318 self.inner.validate_bind_pipeline_compute(pipeline)?;
319
320 Ok(())
321 }
322
323 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
324 pub unsafe fn bind_pipeline_compute_unchecked(
325 &mut self,
326 pipeline: Arc<ComputePipeline>,
327 ) -> &mut Self {
328 self.builder_state.pipeline_compute = Some(pipeline.clone());
329 self.add_command(
330 "bind_pipeline_compute",
331 Default::default(),
332 move |out: &mut RecordingCommandBuffer| {
333 unsafe { out.bind_pipeline_compute_unchecked(&pipeline) };
334 },
335 );
336
337 self
338 }
339
340 pub fn bind_pipeline_graphics(
342 &mut self,
343 pipeline: Arc<GraphicsPipeline>,
344 ) -> Result<&mut Self, Box<ValidationError>> {
345 self.validate_bind_pipeline_graphics(&pipeline)?;
346
347 Ok(unsafe { self.bind_pipeline_graphics_unchecked(pipeline) })
348 }
349
350 fn validate_bind_pipeline_graphics(
351 &self,
352 pipeline: &GraphicsPipeline,
353 ) -> Result<(), Box<ValidationError>> {
354 self.inner.validate_bind_pipeline_graphics(pipeline)?;
355
356 Ok(())
360 }
361
362 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
363 pub unsafe fn bind_pipeline_graphics_unchecked(
364 &mut self,
365 pipeline: Arc<GraphicsPipeline>,
366 ) -> &mut Self {
367 self.builder_state
370 .reset_dynamic_states(pipeline.fixed_state().iter().copied());
371 self.builder_state.pipeline_graphics = Some(pipeline.clone());
372 self.add_command(
373 "bind_pipeline_graphics",
374 Default::default(),
375 move |out: &mut RecordingCommandBuffer| {
376 unsafe { out.bind_pipeline_graphics_unchecked(&pipeline) };
377 },
378 );
379
380 self
381 }
382
383 pub fn bind_pipeline_ray_tracing(
385 &mut self,
386 pipeline: Arc<RayTracingPipeline>,
387 ) -> Result<&mut Self, Box<ValidationError>> {
388 self.inner.validate_bind_pipeline_ray_tracing(&pipeline)?;
389 Ok(unsafe { self.bind_pipeline_ray_tracing_unchecked(pipeline) })
390 }
391
392 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
393 pub unsafe fn bind_pipeline_ray_tracing_unchecked(
394 &mut self,
395 pipeline: Arc<RayTracingPipeline>,
396 ) -> &mut Self {
397 self.builder_state.pipeline_ray_tracing = Some(pipeline.clone());
398 self.add_command(
399 "bind_pipeline_ray_tracing",
400 Default::default(),
401 move |out: &mut RecordingCommandBuffer| {
402 unsafe { out.bind_pipeline_ray_tracing_unchecked(&pipeline) };
403 },
404 );
405
406 self
407 }
408
409 pub fn bind_vertex_buffers(
411 &mut self,
412 first_binding: u32,
413 vertex_buffers: impl VertexBuffersCollection,
414 ) -> Result<&mut Self, Box<ValidationError>> {
415 let vertex_buffers = vertex_buffers.into_vec();
416 self.validate_bind_vertex_buffers(first_binding, &vertex_buffers)?;
417
418 Ok(unsafe { self.bind_vertex_buffers_unchecked(first_binding, vertex_buffers) })
419 }
420
421 fn validate_bind_vertex_buffers(
422 &self,
423 first_binding: u32,
424 vertex_buffers: &[Subbuffer<[u8]>],
425 ) -> Result<(), Box<ValidationError>> {
426 self.inner
427 .validate_bind_vertex_buffers(first_binding, vertex_buffers)?;
428
429 Ok(())
430 }
431
432 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
433 pub unsafe fn bind_vertex_buffers_unchecked(
434 &mut self,
435 first_binding: u32,
436 vertex_buffers: impl VertexBuffersCollection,
437 ) -> &mut Self {
438 let vertex_buffers = vertex_buffers.into_vec();
439
440 for (i, buffer) in vertex_buffers.iter().enumerate() {
441 self.builder_state
442 .vertex_buffers
443 .insert(first_binding + i as u32, buffer.clone());
444 }
445
446 self.add_command(
447 "bind_vertex_buffers",
448 Default::default(),
449 move |out: &mut RecordingCommandBuffer| {
450 unsafe { out.bind_vertex_buffers_unchecked(first_binding, &vertex_buffers) };
451 },
452 );
453
454 self
455 }
456
457 pub fn push_constants<Pc>(
459 &mut self,
460 pipeline_layout: Arc<PipelineLayout>,
461 offset: u32,
462 push_constants: Pc,
463 ) -> Result<&mut Self, Box<ValidationError>>
464 where
465 Pc: BufferContents,
466 {
467 let size = size_of::<Pc>() as u32;
468
469 if size == 0 {
470 return Ok(self);
471 }
472
473 self.validate_push_constants(&pipeline_layout, offset, &push_constants)?;
474
475 Ok(unsafe { self.push_constants_unchecked(pipeline_layout, offset, push_constants) })
476 }
477
478 fn validate_push_constants<Pc: BufferContents>(
479 &self,
480 pipeline_layout: &PipelineLayout,
481 offset: u32,
482 push_constants: &Pc,
483 ) -> Result<(), Box<ValidationError>> {
484 self.inner
485 .validate_push_constants(pipeline_layout, offset, push_constants)?;
486
487 Ok(())
488 }
489
490 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
491 pub unsafe fn push_constants_unchecked<Pc>(
492 &mut self,
493 pipeline_layout: Arc<PipelineLayout>,
494 offset: u32,
495 push_constants: Pc,
496 ) -> &mut Self
497 where
498 Pc: BufferContents,
499 {
500 self.builder_state
506 .push_constants
507 .insert(offset..offset + size_of::<Pc>() as u32);
508 self.builder_state.push_constants_pipeline_layout = Some(pipeline_layout.clone());
509
510 self.add_command(
511 "push_constants",
512 Default::default(),
513 move |out: &mut RecordingCommandBuffer| {
514 unsafe { out.push_constants_unchecked(&pipeline_layout, offset, &push_constants) };
515 },
516 );
517
518 self
519 }
520
521 pub fn push_descriptor_set(
523 &mut self,
524 pipeline_bind_point: PipelineBindPoint,
525 pipeline_layout: Arc<PipelineLayout>,
526 set_num: u32,
527 descriptor_writes: SmallVec<[WriteDescriptorSet; 8]>,
528 ) -> Result<&mut Self, Box<ValidationError>> {
529 self.validate_push_descriptor_set(
530 pipeline_bind_point,
531 &pipeline_layout,
532 set_num,
533 &descriptor_writes,
534 )?;
535
536 Ok(unsafe {
537 self.push_descriptor_set_unchecked(
538 pipeline_bind_point,
539 pipeline_layout,
540 set_num,
541 descriptor_writes,
542 )
543 })
544 }
545
546 fn validate_push_descriptor_set(
547 &self,
548 pipeline_bind_point: PipelineBindPoint,
549 pipeline_layout: &PipelineLayout,
550 set_num: u32,
551 descriptor_writes: &[WriteDescriptorSet],
552 ) -> Result<(), Box<ValidationError>> {
553 self.inner.validate_push_descriptor_set(
554 pipeline_bind_point,
555 pipeline_layout,
556 set_num,
557 descriptor_writes,
558 )?;
559
560 Ok(())
561 }
562
563 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
564 pub unsafe fn push_descriptor_set_unchecked(
565 &mut self,
566 pipeline_bind_point: PipelineBindPoint,
567 pipeline_layout: Arc<PipelineLayout>,
568 set_num: u32,
569 descriptor_writes: SmallVec<[WriteDescriptorSet; 8]>,
570 ) -> &mut Self {
571 let state = self.builder_state.invalidate_descriptor_sets(
572 pipeline_bind_point,
573 pipeline_layout.clone(),
574 set_num,
575 1,
576 );
577 let layout = state.pipeline_layout.set_layouts()[set_num as usize].as_ref();
578 debug_assert!(layout
579 .flags()
580 .intersects(DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR));
581
582 let set_resources = match state
583 .descriptor_sets
584 .entry(set_num)
585 .or_insert_with(|| SetOrPush::Push(DescriptorSetResources::new(layout, 0)))
586 {
587 SetOrPush::Push(set_resources) => set_resources,
588 _ => unreachable!(),
589 };
590
591 for write in &descriptor_writes {
592 set_resources.write(write, layout);
593 }
594
595 self.add_command(
596 "push_descriptor_set",
597 Default::default(),
598 move |out: &mut RecordingCommandBuffer| {
599 unsafe {
600 out.push_descriptor_set_unchecked(
601 pipeline_bind_point,
602 &pipeline_layout,
603 set_num,
604 &descriptor_writes,
605 )
606 };
607 },
608 );
609
610 self
611 }
612}
613
614impl RecordingCommandBuffer {
615 #[inline]
616 pub unsafe fn bind_descriptor_sets(
617 &mut self,
618 pipeline_bind_point: PipelineBindPoint,
619 pipeline_layout: &PipelineLayout,
620 first_set: u32,
621 descriptor_sets: &[&RawDescriptorSet],
622 dynamic_offsets: &[u32],
623 ) -> Result<&mut Self, Box<ValidationError>> {
624 self.validate_bind_descriptor_sets(
625 pipeline_bind_point,
626 pipeline_layout,
627 first_set,
628 descriptor_sets,
629 dynamic_offsets,
630 )?;
631
632 Ok(unsafe {
633 self.bind_descriptor_sets_unchecked(
634 pipeline_bind_point,
635 pipeline_layout,
636 first_set,
637 descriptor_sets,
638 dynamic_offsets,
639 )
640 })
641 }
642
643 fn validate_bind_descriptor_sets(
644 &self,
645 pipeline_bind_point: PipelineBindPoint,
646 pipeline_layout: &PipelineLayout,
647 first_set: u32,
648 descriptor_sets: &[&RawDescriptorSet],
649 dynamic_offsets: &[u32],
650 ) -> Result<(), Box<ValidationError>> {
651 self.validate_bind_descriptor_sets_inner(
652 pipeline_bind_point,
653 pipeline_layout,
654 first_set,
655 descriptor_sets.len(),
656 )?;
657
658 let properties = self.device().physical_device().properties();
659 let mut dynamic_offsets_remaining = dynamic_offsets;
660 let mut required_dynamic_offset_count = 0;
661
662 for (descriptor_sets_index, set) in descriptor_sets.iter().enumerate() {
663 let set_num = first_set + descriptor_sets_index as u32;
664
665 assert_eq!(self.device(), set.device());
667
668 let set_layout = set.layout();
669 let pipeline_set_layout = &pipeline_layout.set_layouts()[set_num as usize];
670
671 if !pipeline_set_layout.is_compatible_with(set_layout) {
672 return Err(Box::new(ValidationError {
673 problem: format!(
674 "`descriptor_sets[{0}]` (for set number {1}) is not compatible with \
675 `pipeline_layout.set_layouts()[{1}]`",
676 descriptor_sets_index, set_num
677 )
678 .into(),
679 vuids: &["VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358"],
680 ..Default::default()
681 }));
682 }
683
684 for (&binding_num, binding) in set_layout.bindings() {
685 let required_alignment = match binding.descriptor_type {
686 DescriptorType::UniformBufferDynamic => {
687 properties.min_uniform_buffer_offset_alignment
688 }
689 DescriptorType::StorageBufferDynamic => {
690 properties.min_storage_buffer_offset_alignment
691 }
692 _ => continue,
693 };
694
695 let count = if binding
696 .binding_flags
697 .intersects(DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT)
698 {
699 set.variable_descriptor_count()
700 } else {
701 binding.descriptor_count
702 } as usize;
703
704 required_dynamic_offset_count += count;
705
706 if !dynamic_offsets_remaining.is_empty() {
707 let split_index = min(count, dynamic_offsets_remaining.len());
708 let dynamic_offsets = &dynamic_offsets_remaining[..split_index];
709 dynamic_offsets_remaining = &dynamic_offsets_remaining[split_index..];
710
711 for (index, &offset) in dynamic_offsets.iter().enumerate() {
712 if !is_aligned(offset as DeviceSize, required_alignment) {
713 match binding.descriptor_type {
714 DescriptorType::UniformBufferDynamic => {
715 return Err(Box::new(ValidationError {
716 problem: format!(
717 "the descriptor type of `descriptor_sets[{}]` \
718 (for set number {}) is \
719 `DescriptorType::UniformBufferDynamic`, but the \
720 dynamic offset provided for binding {} index {} is \
721 not aligned to the \
722 `min_uniform_buffer_offset_alignment` device property",
723 descriptor_sets_index, set_num, binding_num, index,
724 )
725 .into(),
726 vuids: &[
727 "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971",
728 ],
729 ..Default::default()
730 }));
731 }
732 DescriptorType::StorageBufferDynamic => {
733 return Err(Box::new(ValidationError {
734 problem: format!(
735 "the descriptor type of `descriptor_sets[{}]` \
736 (for set number {}) is \
737 `DescriptorType::StorageBufferDynamic`, but the \
738 dynamic offset provided for binding {} index {} is \
739 not aligned to the \
740 `min_storage_buffer_offset_alignment` device property",
741 descriptor_sets_index, set_num, binding_num, index,
742 )
743 .into(),
744 vuids: &[
745 "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01972",
746 ],
747 ..Default::default()
748 }));
749 }
750 _ => unreachable!(),
751 }
752 }
753 }
754 }
755 }
756 }
757
758 if dynamic_offsets.len() != required_dynamic_offset_count {
759 return Err(Box::new(ValidationError {
760 problem: format!(
761 "the number of dynamic offsets provided does not equal the number required \
762 ({})",
763 required_dynamic_offset_count,
764 )
765 .into(),
766 vuids: &["VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359"],
767 ..Default::default()
768 }));
769 }
770
771 Ok(())
772 }
773
774 fn validate_bind_descriptor_sets_inner(
775 &self,
776 pipeline_bind_point: PipelineBindPoint,
777 pipeline_layout: &PipelineLayout,
778 first_set: u32,
779 descriptor_sets: usize,
780 ) -> Result<(), Box<ValidationError>> {
781 pipeline_bind_point
782 .validate_device(self.device())
783 .map_err(|err| {
784 err.add_context("pipeline_bind_point")
785 .set_vuids(&["VUID-vkCmdBindDescriptorSets-pipelineBindPoint-parameter"])
786 })?;
787
788 let queue_family_properties = self.queue_family_properties();
789
790 match pipeline_bind_point {
791 PipelineBindPoint::Compute => {
792 if !queue_family_properties
793 .queue_flags
794 .intersects(QueueFlags::COMPUTE)
795 {
796 return Err(Box::new(ValidationError {
797 context: "pipeline_bind_point".into(),
798 problem: "is `PipelineBindPoint::Compute`, but \
799 the queue family of the command buffer does not support \
800 compute operations"
801 .into(),
802 vuids: &[
803 "VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361",
804 "VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool",
805 ],
806 ..Default::default()
807 }));
808 }
809 }
810 PipelineBindPoint::Graphics => {
811 if !queue_family_properties
812 .queue_flags
813 .intersects(QueueFlags::GRAPHICS)
814 {
815 return Err(Box::new(ValidationError {
816 context: "pipeline_bind_point".into(),
817 problem: "is `PipelineBindPoint::Graphics`, but \
818 the queue family of the command buffer does not support \
819 graphics operations"
820 .into(),
821 vuids: &[
822 "VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361",
823 "VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool",
824 ],
825 ..Default::default()
826 }));
827 }
828 }
829 PipelineBindPoint::RayTracing => {
830 if !queue_family_properties
831 .queue_flags
832 .intersects(QueueFlags::COMPUTE)
833 {
834 return Err(Box::new(ValidationError {
835 context: "pipeline_bind_point".into(),
836 problem: "is `PipelineBindPoint::RayTracing`, but \
837 the queue family of the command buffer does not support \
838 compute operations"
839 .into(),
840 vuids: &[
841 "VUID-vkCmdBindDescriptorSets-pipelineBindPoint-02391",
842 "VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool",
843 ],
844 ..Default::default()
845 }));
846 }
847 }
848 }
849
850 if first_set + descriptor_sets as u32 > pipeline_layout.set_layouts().len() as u32 {
851 return Err(Box::new(ValidationError {
852 problem: "`first_set + descriptor_sets.len()` is greater than \
853 `pipeline_layout.set_layouts().len()`"
854 .into(),
855 vuids: &["VUID-vkCmdBindDescriptorSets-firstSet-00360"],
856 ..Default::default()
857 }));
858 }
859
860 Ok(())
861 }
862
863 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
864 pub unsafe fn bind_descriptor_sets_unchecked(
865 &mut self,
866 pipeline_bind_point: PipelineBindPoint,
867 pipeline_layout: &PipelineLayout,
868 first_set: u32,
869 descriptor_sets: &[&RawDescriptorSet],
870 dynamic_offsets: &[u32],
871 ) -> &mut Self {
872 if descriptor_sets.is_empty() {
873 return self;
874 }
875
876 let descriptor_sets_vk: SmallVec<[_; 12]> =
877 descriptor_sets.iter().map(|x| x.handle()).collect();
878
879 let fns = self.device().fns();
880 unsafe {
881 (fns.v1_0.cmd_bind_descriptor_sets)(
882 self.handle(),
883 pipeline_bind_point.into(),
884 pipeline_layout.handle(),
885 first_set,
886 descriptor_sets_vk.len() as u32,
887 descriptor_sets_vk.as_ptr(),
888 dynamic_offsets.len() as u32,
889 dynamic_offsets.as_ptr(),
890 )
891 };
892
893 self
894 }
895
896 #[inline]
897 pub unsafe fn bind_index_buffer(
898 &mut self,
899 index_buffer: &IndexBuffer,
900 ) -> Result<&mut Self, Box<ValidationError>> {
901 self.validate_bind_index_buffer(index_buffer)?;
902
903 Ok(unsafe { self.bind_index_buffer_unchecked(index_buffer) })
904 }
905
906 fn validate_bind_index_buffer(
907 &self,
908 index_buffer: &IndexBuffer,
909 ) -> Result<(), Box<ValidationError>> {
910 if !self
911 .queue_family_properties()
912 .queue_flags
913 .intersects(QueueFlags::GRAPHICS)
914 {
915 return Err(Box::new(ValidationError {
916 problem: "the queue family of the command buffer does not support \
917 graphics operations"
918 .into(),
919 vuids: &["VUID-vkCmdBindIndexBuffer-commandBuffer-cmdpool"],
920 ..Default::default()
921 }));
922 }
923
924 let index_buffer_bytes = index_buffer.as_bytes();
925
926 assert_eq!(self.device(), index_buffer_bytes.device());
928
929 if !index_buffer_bytes
930 .buffer()
931 .usage()
932 .intersects(BufferUsage::INDEX_BUFFER)
933 {
934 return Err(Box::new(ValidationError {
935 context: "index_buffer.usage()".into(),
936 problem: "does not contain `BufferUsage::INDEX_BUFFER`".into(),
937 vuids: &["VUID-vkCmdBindIndexBuffer-buffer-00433"],
938 ..Default::default()
939 }));
940 }
941
942 if matches!(index_buffer, IndexBuffer::U8(_))
943 && !self.device().enabled_features().index_type_uint8
944 {
945 return Err(Box::new(ValidationError {
946 context: "index_buffer".into(),
947 problem: "is `IndexBuffer::U8`".into(),
948 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
949 "index_type_uint8",
950 )])]),
951 vuids: &["VUID-vkCmdBindIndexBuffer-indexType-02765"],
952 }));
953 }
954
955 Ok(())
959 }
960
961 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
962 pub unsafe fn bind_index_buffer_unchecked(&mut self, index_buffer: &IndexBuffer) -> &mut Self {
963 let index_buffer_bytes = index_buffer.as_bytes();
964
965 let fns = self.device().fns();
966 unsafe {
967 (fns.v1_0.cmd_bind_index_buffer)(
968 self.handle(),
969 index_buffer_bytes.buffer().handle(),
970 index_buffer_bytes.offset(),
971 index_buffer.index_type().into(),
972 )
973 };
974
975 self
976 }
977
978 #[inline]
979 pub unsafe fn bind_pipeline_compute(
980 &mut self,
981 pipeline: &ComputePipeline,
982 ) -> Result<&mut Self, Box<ValidationError>> {
983 self.validate_bind_pipeline_compute(pipeline)?;
984
985 Ok(unsafe { self.bind_pipeline_compute_unchecked(pipeline) })
986 }
987
988 fn validate_bind_pipeline_compute(
989 &self,
990 pipeline: &ComputePipeline,
991 ) -> Result<(), Box<ValidationError>> {
992 if !self
993 .queue_family_properties()
994 .queue_flags
995 .intersects(QueueFlags::COMPUTE)
996 {
997 return Err(Box::new(ValidationError {
998 problem: "the queue family of the command buffer does not support \
999 compute operations"
1000 .into(),
1001 vuids: &["VUID-vkCmdBindPipeline-pipelineBindPoint-00777"],
1002 ..Default::default()
1003 }));
1004 }
1005
1006 assert_eq!(self.device(), pipeline.device());
1008
1009 Ok(())
1010 }
1011
1012 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1013 pub unsafe fn bind_pipeline_compute_unchecked(
1014 &mut self,
1015 pipeline: &ComputePipeline,
1016 ) -> &mut Self {
1017 let fns = self.device().fns();
1018 unsafe {
1019 (fns.v1_0.cmd_bind_pipeline)(
1020 self.handle(),
1021 ash::vk::PipelineBindPoint::COMPUTE,
1022 pipeline.handle(),
1023 )
1024 };
1025
1026 self
1027 }
1028
1029 #[inline]
1030 pub unsafe fn bind_pipeline_graphics(
1031 &mut self,
1032 pipeline: &GraphicsPipeline,
1033 ) -> Result<&mut Self, Box<ValidationError>> {
1034 self.validate_bind_pipeline_graphics(pipeline)?;
1035
1036 Ok(unsafe { self.bind_pipeline_graphics_unchecked(pipeline) })
1037 }
1038
1039 fn validate_bind_pipeline_graphics(
1040 &self,
1041 pipeline: &GraphicsPipeline,
1042 ) -> Result<(), Box<ValidationError>> {
1043 if !self
1044 .queue_family_properties()
1045 .queue_flags
1046 .intersects(QueueFlags::GRAPHICS)
1047 {
1048 return Err(Box::new(ValidationError {
1049 problem: "the queue family of the command buffer does not support \
1050 graphics operations"
1051 .into(),
1052 vuids: &["VUID-vkCmdBindPipeline-pipelineBindPoint-00778"],
1053 ..Default::default()
1054 }));
1055 }
1056
1057 assert_eq!(self.device(), pipeline.device());
1059
1060 Ok(())
1061 }
1062
1063 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1064 pub unsafe fn bind_pipeline_graphics_unchecked(
1065 &mut self,
1066 pipeline: &GraphicsPipeline,
1067 ) -> &mut Self {
1068 let fns = self.device().fns();
1069 unsafe {
1070 (fns.v1_0.cmd_bind_pipeline)(
1071 self.handle(),
1072 ash::vk::PipelineBindPoint::GRAPHICS,
1073 pipeline.handle(),
1074 )
1075 };
1076
1077 self
1078 }
1079
1080 pub unsafe fn bind_pipeline_ray_tracing(
1081 &mut self,
1082 pipeline: &RayTracingPipeline,
1083 ) -> Result<&mut Self, Box<ValidationError>> {
1084 self.validate_bind_pipeline_ray_tracing(pipeline)?;
1085 Ok(unsafe { self.bind_pipeline_ray_tracing_unchecked(pipeline) })
1086 }
1087
1088 fn validate_bind_pipeline_ray_tracing(
1089 &self,
1090 pipeline: &RayTracingPipeline,
1091 ) -> Result<(), Box<ValidationError>> {
1092 if !self
1093 .queue_family_properties()
1094 .queue_flags
1095 .intersects(QueueFlags::COMPUTE)
1096 {
1097 return Err(Box::new(ValidationError {
1098 problem: "the queue family of the command buffer does not support \
1099 compute operations"
1100 .into(),
1101 vuids: &["VUID-vkCmdBindPipeline-pipelineBindPoint-02391"],
1102 ..Default::default()
1103 }));
1104 }
1105
1106 assert_eq!(self.device(), pipeline.device());
1108
1109 Ok(())
1112 }
1113
1114 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1115 pub unsafe fn bind_pipeline_ray_tracing_unchecked(
1116 &mut self,
1117 pipeline: &RayTracingPipeline,
1118 ) -> &mut Self {
1119 let fns = self.device().fns();
1120 unsafe {
1121 (fns.v1_0.cmd_bind_pipeline)(
1122 self.handle(),
1123 ash::vk::PipelineBindPoint::RAY_TRACING_KHR,
1124 pipeline.handle(),
1125 )
1126 };
1127
1128 self
1129 }
1130
1131 #[inline]
1132 pub unsafe fn bind_vertex_buffers(
1133 &mut self,
1134 first_binding: u32,
1135 vertex_buffers: &[Subbuffer<[u8]>],
1136 ) -> Result<&mut Self, Box<ValidationError>> {
1137 self.validate_bind_vertex_buffers(first_binding, vertex_buffers)?;
1138
1139 Ok(unsafe { self.bind_vertex_buffers_unchecked(first_binding, vertex_buffers) })
1140 }
1141
1142 fn validate_bind_vertex_buffers(
1143 &self,
1144 first_binding: u32,
1145 vertex_buffers: &[Subbuffer<[u8]>],
1146 ) -> Result<(), Box<ValidationError>> {
1147 if !self
1148 .queue_family_properties()
1149 .queue_flags
1150 .intersects(QueueFlags::GRAPHICS)
1151 {
1152 return Err(Box::new(ValidationError {
1153 problem: "the queue family of the command buffer does not support \
1154 graphics operations"
1155 .into(),
1156 vuids: &["VUID-vkCmdBindVertexBuffers-commandBuffer-cmdpool"],
1157 ..Default::default()
1158 }));
1159 }
1160
1161 let properties = self.device().physical_device().properties();
1162
1163 if first_binding + vertex_buffers.len() as u32 > properties.max_vertex_input_bindings {
1164 return Err(Box::new(ValidationError {
1165 problem: "`first_binding + vertex_buffers.len()` is greater than the \
1166 `max_vertex_input_bindings` limit"
1167 .into(),
1168 vuids: &[
1169 "VUID-vkCmdBindVertexBuffers-firstBinding-00624",
1170 "VUID-vkCmdBindVertexBuffers-firstBinding-00625",
1171 ],
1172 ..Default::default()
1173 }));
1174 }
1175
1176 for (vertex_buffers_index, buffer) in vertex_buffers.iter().enumerate() {
1177 assert_eq!(self.device(), buffer.device());
1179
1180 if !buffer
1181 .buffer()
1182 .usage()
1183 .intersects(BufferUsage::VERTEX_BUFFER)
1184 {
1185 return Err(Box::new(ValidationError {
1186 context: format!("vertex_buffers[{}].usage()", vertex_buffers_index).into(),
1187 problem: "does not contain `BufferUsage::VERTEX_BUFFER`".into(),
1188 vuids: &["VUID-vkCmdBindVertexBuffers-pBuffers-00627"],
1189 ..Default::default()
1190 }));
1191 }
1192 }
1193
1194 Ok(())
1195 }
1196
1197 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1198 pub unsafe fn bind_vertex_buffers_unchecked(
1199 &mut self,
1200 first_binding: u32,
1201 vertex_buffers: &[Subbuffer<[u8]>],
1202 ) -> &mut Self {
1203 if vertex_buffers.is_empty() {
1204 return self;
1205 }
1206
1207 let device = self.device();
1208
1209 if device.api_version() >= Version::V1_3
1210 || device.enabled_extensions().ext_extended_dynamic_state
1211 || device.enabled_extensions().ext_shader_object
1212 {
1213 let mut buffers_vk: SmallVec<[_; 2]> = SmallVec::with_capacity(vertex_buffers.len());
1214 let mut offsets_vk: SmallVec<[_; 2]> = SmallVec::with_capacity(vertex_buffers.len());
1215 let mut sizes_vk: SmallVec<[_; 2]> = SmallVec::with_capacity(vertex_buffers.len());
1216
1217 for buffer in vertex_buffers {
1218 buffers_vk.push(buffer.buffer().handle());
1219 offsets_vk.push(buffer.offset());
1220 sizes_vk.push(buffer.size());
1221 }
1222
1223 let fns = self.device().fns();
1224 let cmd_bind_vertex_buffers2 = if device.api_version() >= Version::V1_3 {
1225 fns.v1_3.cmd_bind_vertex_buffers2
1226 } else if device.enabled_extensions().ext_extended_dynamic_state {
1227 fns.ext_extended_dynamic_state.cmd_bind_vertex_buffers2_ext
1228 } else {
1229 fns.ext_shader_object.cmd_bind_vertex_buffers2_ext
1230 };
1231
1232 unsafe {
1233 cmd_bind_vertex_buffers2(
1234 self.handle(),
1235 first_binding,
1236 buffers_vk.len() as u32,
1237 buffers_vk.as_ptr(),
1238 offsets_vk.as_ptr(),
1239 sizes_vk.as_ptr(),
1240 ptr::null(),
1241 )
1242 }
1243 } else {
1244 let mut buffers_vk: SmallVec<[_; 2]> = SmallVec::with_capacity(vertex_buffers.len());
1245 let mut offsets_vk: SmallVec<[_; 2]> = SmallVec::with_capacity(vertex_buffers.len());
1246
1247 for buffer in vertex_buffers {
1248 buffers_vk.push(buffer.buffer().handle());
1249 offsets_vk.push(buffer.offset());
1250 }
1251
1252 let fns = self.device().fns();
1253 unsafe {
1254 (fns.v1_0.cmd_bind_vertex_buffers)(
1255 self.handle(),
1256 first_binding,
1257 buffers_vk.len() as u32,
1258 buffers_vk.as_ptr(),
1259 offsets_vk.as_ptr(),
1260 )
1261 };
1262 }
1263
1264 self
1265 }
1266
1267 #[inline]
1268 pub unsafe fn push_constants<Pc>(
1269 &mut self,
1270 pipeline_layout: &PipelineLayout,
1271 offset: u32,
1272 push_constants: &Pc,
1273 ) -> Result<&mut Self, Box<ValidationError>>
1274 where
1275 Pc: BufferContents,
1276 {
1277 self.validate_push_constants(pipeline_layout, offset, push_constants)?;
1278
1279 Ok(unsafe { self.push_constants_unchecked(pipeline_layout, offset, push_constants) })
1280 }
1281
1282 fn validate_push_constants<Pc: BufferContents>(
1283 &self,
1284 pipeline_layout: &PipelineLayout,
1285 offset: u32,
1286 _push_constants: &Pc,
1287 ) -> Result<(), Box<ValidationError>> {
1288 let mut remaining_size = size_of::<Pc>();
1289
1290 if offset % 4 != 0 {
1291 return Err(Box::new(ValidationError {
1292 context: "offset".into(),
1293 problem: "is not a multiple of 4".into(),
1294 vuids: &["VUID-vkCmdPushConstants-offset-00368"],
1295 ..Default::default()
1296 }));
1297 }
1298
1299 if remaining_size % 4 != 0 {
1300 return Err(Box::new(ValidationError {
1301 context: "push_constants".into(),
1302 problem: "the size is not a multiple of 4".into(),
1303 vuids: &["VUID-vkCmdPushConstants-size-00369"],
1304 ..Default::default()
1305 }));
1306 }
1307
1308 let properties = self.device().physical_device().properties();
1309
1310 if offset >= properties.max_push_constants_size {
1311 return Err(Box::new(ValidationError {
1312 context: "offset".into(),
1313 problem: "is not less than the `max_push_constants_size` limit".into(),
1314 vuids: &["VUID-vkCmdPushConstants-offset-00370"],
1315 ..Default::default()
1316 }));
1317 }
1318
1319 if offset as usize + remaining_size > properties.max_push_constants_size as usize {
1320 return Err(Box::new(ValidationError {
1321 problem: "`offset` + the size of `push_constants` is not less than or \
1322 equal to the `max_push_constants_size` limit"
1323 .into(),
1324 vuids: &["VUID-vkCmdPushConstants-size-00371"],
1325 ..Default::default()
1326 }));
1327 }
1328
1329 let mut current_offset = offset as usize;
1330
1331 for range in pipeline_layout
1332 .push_constant_ranges_disjoint()
1333 .iter()
1334 .skip_while(|range| range.offset + range.size <= offset)
1335 {
1336 if range.offset as usize > current_offset {
1339 break;
1340 }
1341
1342 let push_size =
1345 remaining_size.min(range.offset as usize + range.size as usize - current_offset);
1346 current_offset += push_size;
1347 remaining_size -= push_size;
1348
1349 if remaining_size == 0 {
1350 break;
1351 }
1352 }
1353
1354 if remaining_size != 0 {
1355 return Err(Box::new(ValidationError {
1356 problem: "one or more bytes of `push_constants` are not within any push constant \
1357 range of `pipeline_layout`"
1358 .into(),
1359 vuids: &["VUID-vkCmdPushConstants-offset-01795"],
1360 ..Default::default()
1361 }));
1362 }
1363
1364 Ok(())
1365 }
1366
1367 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1368 pub unsafe fn push_constants_unchecked<Pc>(
1369 &mut self,
1370 pipeline_layout: &PipelineLayout,
1371 offset: u32,
1372 push_constants: &Pc,
1373 ) -> &mut Self
1374 where
1375 Pc: BufferContents,
1376 {
1377 let size = u32::try_from(size_of::<Pc>()).unwrap();
1378
1379 if size == 0 {
1380 return self;
1381 }
1382
1383 let fns = self.device().fns();
1384 let mut current_offset = offset;
1385 let mut remaining_size = size;
1386
1387 for range in pipeline_layout
1388 .push_constant_ranges_disjoint()
1389 .iter()
1390 .skip_while(|range| range.offset + range.size <= offset)
1391 {
1392 if range.offset > current_offset {
1395 break;
1396 }
1397
1398 let push_size = remaining_size.min(range.offset + range.size - current_offset);
1401 let data_offset = (current_offset - offset) as usize;
1402 debug_assert!(data_offset < size as usize);
1403 let data = unsafe { <*const _>::cast::<c_void>(push_constants).add(data_offset) };
1404
1405 unsafe {
1406 (fns.v1_0.cmd_push_constants)(
1407 self.handle(),
1408 pipeline_layout.handle(),
1409 range.stages.into(),
1410 current_offset,
1411 push_size,
1412 data,
1413 )
1414 };
1415
1416 current_offset += push_size;
1417 remaining_size -= push_size;
1418
1419 if remaining_size == 0 {
1420 break;
1421 }
1422 }
1423
1424 debug_assert!(remaining_size == 0);
1425
1426 self
1427 }
1428
1429 #[inline]
1430 pub unsafe fn push_descriptor_set(
1431 &mut self,
1432 pipeline_bind_point: PipelineBindPoint,
1433 pipeline_layout: &PipelineLayout,
1434 set_num: u32,
1435 descriptor_writes: &[WriteDescriptorSet],
1436 ) -> Result<&mut Self, Box<ValidationError>> {
1437 self.validate_push_descriptor_set(
1438 pipeline_bind_point,
1439 pipeline_layout,
1440 set_num,
1441 descriptor_writes,
1442 )?;
1443
1444 Ok(unsafe {
1445 self.push_descriptor_set_unchecked(
1446 pipeline_bind_point,
1447 pipeline_layout,
1448 set_num,
1449 descriptor_writes,
1450 )
1451 })
1452 }
1453
1454 fn validate_push_descriptor_set(
1455 &self,
1456 pipeline_bind_point: PipelineBindPoint,
1457 pipeline_layout: &PipelineLayout,
1458 set_num: u32,
1459 descriptor_writes: &[WriteDescriptorSet],
1460 ) -> Result<(), Box<ValidationError>> {
1461 if !self.device().enabled_extensions().khr_push_descriptor {
1462 return Err(Box::new(ValidationError {
1463 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
1464 "khr_push_descriptor",
1465 )])]),
1466 ..Default::default()
1467 }));
1468 }
1469
1470 pipeline_bind_point
1471 .validate_device(self.device())
1472 .map_err(|err| {
1473 err.add_context("pipeline_bind_point")
1474 .set_vuids(&["VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-parameter"])
1475 })?;
1476
1477 let queue_family_properties = self.queue_family_properties();
1478
1479 match pipeline_bind_point {
1480 PipelineBindPoint::Compute => {
1481 if !queue_family_properties
1482 .queue_flags
1483 .intersects(QueueFlags::COMPUTE)
1484 {
1485 return Err(Box::new(ValidationError {
1486 context: "self".into(),
1487 problem: "`pipeline_bind_point` is `PipelineBindPoint::Compute`, and the \
1488 queue family does not support compute operations"
1489 .into(),
1490 vuids: &[
1491 "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363",
1492 "VUID-vkCmdPushDescriptorSetKHR-commandBuffer-cmdpool",
1493 ],
1494 ..Default::default()
1495 }));
1496 }
1497 }
1498 PipelineBindPoint::Graphics => {
1499 if !queue_family_properties
1500 .queue_flags
1501 .intersects(QueueFlags::GRAPHICS)
1502 {
1503 return Err(Box::new(ValidationError {
1504 context: "self".into(),
1505 problem: "`pipeline_bind_point` is `PipelineBindPoint::Graphics`, and the \
1506 queue family does not support graphics operations"
1507 .into(),
1508 vuids: &[
1509 "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363",
1510 "VUID-vkCmdPushDescriptorSetKHR-commandBuffer-cmdpool",
1511 ],
1512 ..Default::default()
1513 }));
1514 }
1515 }
1516 PipelineBindPoint::RayTracing => {
1517 if !queue_family_properties
1518 .queue_flags
1519 .intersects(QueueFlags::COMPUTE)
1520 {
1521 return Err(Box::new(ValidationError {
1522 context: "self".into(),
1523 problem:
1524 "`pipeline_bind_point` is `PipelineBindPoint::RayTracing`, and the \
1525 queue family does not support compute operations"
1526 .into(),
1527 vuids: &[
1528 "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-02391",
1529 "VUID-vkCmdPushDescriptorSetKHR-commandBuffer-cmdpool",
1530 ],
1531 ..Default::default()
1532 }));
1533 }
1534 }
1535 }
1536
1537 assert_eq!(self.device(), pipeline_layout.device());
1539
1540 if set_num as usize > pipeline_layout.set_layouts().len() {
1541 return Err(Box::new(ValidationError {
1542 problem: "`set_num` is greater than the number of descriptor set layouts in \
1543 `pipeline_layout`"
1544 .into(),
1545 vuids: &["VUID-vkCmdPushDescriptorSetKHR-set-00364"],
1546 ..Default::default()
1547 }));
1548 }
1549
1550 let descriptor_set_layout = &pipeline_layout.set_layouts()[set_num as usize];
1551
1552 if !descriptor_set_layout
1553 .flags()
1554 .intersects(DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR)
1555 {
1556 return Err(Box::new(ValidationError {
1557 problem: "the descriptor set layout with the number `set_num` in \
1558 `pipeline_layout` was not created with the \
1559 `DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR` flag"
1560 .into(),
1561 vuids: &["VUID-vkCmdPushDescriptorSetKHR-set-00365"],
1562 ..Default::default()
1563 }));
1564 }
1565
1566 for (index, write) in descriptor_writes.iter().enumerate() {
1567 write
1568 .validate(descriptor_set_layout, 0)
1569 .map_err(|err| err.add_context(format!("descriptor_writes[{}]", index)))?;
1570 }
1571
1572 Ok(())
1573 }
1574
1575 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1576 pub unsafe fn push_descriptor_set_unchecked(
1577 &mut self,
1578 pipeline_bind_point: PipelineBindPoint,
1579 pipeline_layout: &PipelineLayout,
1580 set_num: u32,
1581 descriptor_writes: &[WriteDescriptorSet],
1582 ) -> &mut Self {
1583 if descriptor_writes.is_empty() {
1584 return self;
1585 }
1586
1587 let set_layout_bindings = &pipeline_layout.set_layouts()[set_num as usize].bindings();
1588 let writes_fields1_vk: SmallVec<[_; 8]> = descriptor_writes
1589 .iter()
1590 .map(|write| {
1591 let default_image_layout = set_layout_bindings[&write.binding()]
1592 .descriptor_type
1593 .default_image_layout();
1594 write.to_vk_fields1(default_image_layout)
1595 })
1596 .collect();
1597 let mut writes_extensions_vk: SmallVec<[_; 8]> = descriptor_writes
1598 .iter()
1599 .zip(&writes_fields1_vk)
1600 .map(|(write, fields1_vk)| write.to_vk_extensions(fields1_vk))
1601 .collect();
1602 let writes_vk: SmallVec<[_; 8]> = descriptor_writes
1603 .iter()
1604 .zip(&writes_fields1_vk)
1605 .zip(&mut writes_extensions_vk)
1606 .map(|((write, write_info_vk), write_extension_vk)| {
1607 write.to_vk(
1608 ash::vk::DescriptorSet::null(),
1609 set_layout_bindings[&write.binding()].descriptor_type,
1610 write_info_vk,
1611 write_extension_vk,
1612 )
1613 })
1614 .collect();
1615
1616 let fns = self.device().fns();
1617 unsafe {
1618 (fns.khr_push_descriptor.cmd_push_descriptor_set_khr)(
1619 self.handle(),
1620 pipeline_bind_point.into(),
1621 pipeline_layout.handle(),
1622 set_num,
1623 writes_vk.len() as u32,
1624 writes_vk.as_ptr(),
1625 )
1626 };
1627
1628 self
1629 }
1630}