1use super::{DeviceMemory, MemoryPropertyFlags};
2use crate::{
3 buffer::{Buffer, BufferCreateFlags},
4 device::{Device, DeviceOwned},
5 image::{
6 mip_level_extent, Image, ImageAspects, ImageCreateFlags, SparseImageFormatProperties,
7 SparseImageMemoryRequirements,
8 },
9 memory::{is_aligned, MemoryRequirements},
10 sync::semaphore::Semaphore,
11 DeviceSize, ValidationError, VulkanObject as _,
12};
13use smallvec::SmallVec;
14use std::sync::Arc;
15
16#[derive(Clone, Debug)]
18pub struct BindSparseInfo {
19 pub wait_semaphores: Vec<Arc<Semaphore>>,
24
25 pub buffer_binds: Vec<SparseBufferMemoryBindInfo>,
29
30 pub image_opaque_binds: Vec<SparseImageOpaqueMemoryBindInfo>,
37
38 pub image_binds: Vec<SparseImageMemoryBindInfo>,
47
48 pub signal_semaphores: Vec<Arc<Semaphore>>,
53
54 pub _ne: crate::NonExhaustive,
55}
56
57impl Default for BindSparseInfo {
58 #[inline]
59 fn default() -> Self {
60 Self {
61 wait_semaphores: Vec::new(),
62 buffer_binds: Vec::new(),
63 image_opaque_binds: Vec::new(),
64 image_binds: Vec::new(),
65 signal_semaphores: Vec::new(),
66 _ne: crate::NonExhaustive(()),
67 }
68 }
69}
70
71impl BindSparseInfo {
72 pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
73 let &Self {
74 ref wait_semaphores,
75 ref buffer_binds,
76 ref image_opaque_binds,
77 ref image_binds,
78 ref signal_semaphores,
79 _ne: _,
80 } = self;
81
82 for semaphore in wait_semaphores {
83 assert_eq!(device, semaphore.device().as_ref());
84 }
85
86 for (index, buffer_bind_info) in buffer_binds.iter().enumerate() {
87 buffer_bind_info
88 .validate(device)
89 .map_err(|err| err.add_context(format!("buffer_binds[{}]", index)))?;
90 }
91
92 for (index, image_opaque_bind_info) in image_opaque_binds.iter().enumerate() {
93 image_opaque_bind_info
94 .validate(device)
95 .map_err(|err| err.add_context(format!("image_opaque_binds[{}]", index)))?;
96 }
97
98 for (index, image_bind_info) in image_binds.iter().enumerate() {
99 image_bind_info
100 .validate(device)
101 .map_err(|err| err.add_context(format!("image_binds[{}]", index)))?;
102 }
103
104 for semaphore in signal_semaphores {
105 assert_eq!(device, semaphore.device().as_ref());
106 }
107
108 Ok(())
109 }
110
111 pub(crate) fn to_vk<'a>(
112 &self,
113 fields1_vk: &'a BindSparseInfoFields1Vk<'_>,
114 ) -> ash::vk::BindSparseInfo<'a> {
115 let BindSparseInfoFields1Vk {
116 wait_semaphores_vk,
117 buffer_bind_infos_vk,
118 image_opaque_bind_infos_vk,
119 image_bind_infos_vk,
120 signal_semaphores_vk,
121 } = fields1_vk;
122
123 ash::vk::BindSparseInfo::default()
124 .wait_semaphores(wait_semaphores_vk)
125 .buffer_binds(buffer_bind_infos_vk)
126 .image_opaque_binds(image_opaque_bind_infos_vk)
127 .image_binds(image_bind_infos_vk)
128 .signal_semaphores(signal_semaphores_vk)
129 }
130
131 pub(crate) fn to_vk_fields1<'a>(
132 &self,
133 fields2_vk: &'a BindSparseInfoFields2Vk,
134 ) -> BindSparseInfoFields1Vk<'a> {
135 let &BindSparseInfo {
136 ref wait_semaphores,
137 ref buffer_binds,
138 ref image_opaque_binds,
139 ref image_binds,
140 ref signal_semaphores,
141 _ne: _,
142 } = self;
143 let BindSparseInfoFields2Vk {
144 buffer_bind_infos_fields1_vk,
145 image_opaque_bind_infos_fields1_vk,
146 image_bind_infos_fields1_vk,
147 } = fields2_vk;
148
149 let wait_semaphores_vk = wait_semaphores
150 .iter()
151 .map(|semaphore| semaphore.handle())
152 .collect();
153
154 let buffer_bind_infos_vk = buffer_binds
155 .iter()
156 .zip(buffer_bind_infos_fields1_vk)
157 .map(|(buffer_bind_info, fields1_vk)| buffer_bind_info.to_vk(fields1_vk))
158 .collect();
159
160 let image_opaque_bind_infos_vk = image_opaque_binds
161 .iter()
162 .zip(image_opaque_bind_infos_fields1_vk)
163 .map(|(image_opaque_bind_info, fields1_vk)| image_opaque_bind_info.to_vk(fields1_vk))
164 .collect();
165
166 let image_bind_infos_vk = image_binds
167 .iter()
168 .zip(image_bind_infos_fields1_vk)
169 .map(|(image_bind_info, fields1_vk)| image_bind_info.to_vk(fields1_vk))
170 .collect();
171
172 let signal_semaphores_vk = signal_semaphores
173 .iter()
174 .map(|semaphore| semaphore.handle())
175 .collect();
176
177 BindSparseInfoFields1Vk {
178 wait_semaphores_vk,
179 buffer_bind_infos_vk,
180 image_opaque_bind_infos_vk,
181 image_bind_infos_vk,
182 signal_semaphores_vk,
183 }
184 }
185
186 pub(crate) fn to_vk_fields2(&self) -> BindSparseInfoFields2Vk {
187 let &Self {
188 wait_semaphores: _,
189 ref buffer_binds,
190 ref image_opaque_binds,
191 ref image_binds,
192 signal_semaphores: _,
193 _ne: _,
194 } = self;
195
196 let buffer_bind_infos_fields1_vk = buffer_binds
197 .iter()
198 .map(SparseBufferMemoryBindInfo::to_vk_fields1)
199 .collect();
200
201 let image_opaque_bind_infos_fields1_vk = image_opaque_binds
202 .iter()
203 .map(SparseImageOpaqueMemoryBindInfo::to_vk_fields1)
204 .collect();
205
206 let image_bind_infos_fields1_vk = image_binds
207 .iter()
208 .map(SparseImageMemoryBindInfo::to_vk_fields1)
209 .collect();
210
211 BindSparseInfoFields2Vk {
212 buffer_bind_infos_fields1_vk,
213 image_opaque_bind_infos_fields1_vk,
214 image_bind_infos_fields1_vk,
215 }
216 }
217}
218
219pub(crate) struct BindSparseInfoFields1Vk<'a> {
220 pub(crate) wait_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
221 pub(crate) buffer_bind_infos_vk: SmallVec<[ash::vk::SparseBufferMemoryBindInfo<'a>; 4]>,
222 pub(crate) image_opaque_bind_infos_vk:
223 SmallVec<[ash::vk::SparseImageOpaqueMemoryBindInfo<'a>; 4]>,
224 pub(crate) image_bind_infos_vk: SmallVec<[ash::vk::SparseImageMemoryBindInfo<'a>; 4]>,
225 pub(crate) signal_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
226}
227
228pub(crate) struct BindSparseInfoFields2Vk {
229 pub(crate) buffer_bind_infos_fields1_vk: SmallVec<[SparseBufferMemoryBindInfoFields1Vk; 4]>,
230 pub(crate) image_opaque_bind_infos_fields1_vk:
231 SmallVec<[SparseImageOpaqueMemoryBindInfoFields1Vk; 4]>,
232 pub(crate) image_bind_infos_fields1_vk: SmallVec<[SparseImageMemoryBindInfoFields1Vk; 4]>,
233}
234
235#[derive(Clone, Debug)]
237pub struct SparseBufferMemoryBindInfo {
238 pub buffer: Arc<Buffer>,
242
243 pub binds: Vec<SparseBufferMemoryBind>,
247
248 pub _ne: crate::NonExhaustive,
249}
250
251impl SparseBufferMemoryBindInfo {
252 #[inline]
254 pub fn new(buffer: Arc<Buffer>) -> Self {
255 Self {
256 buffer,
257 binds: Vec::new(),
258 _ne: crate::NonExhaustive(()),
259 }
260 }
261
262 pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
263 let &Self {
264 ref buffer,
265 ref binds,
266 _ne: _,
267 } = self;
268
269 assert_eq!(device, buffer.device().as_ref());
270 assert!(!binds.is_empty());
271
272 if !buffer.flags().intersects(BufferCreateFlags::SPARSE_BINDING) {
273 return Err(Box::new(ValidationError {
274 context: "buffer.flags()".into(),
275 problem: "does not contain `BufferCreateFlags::SPARSE_BINDING`".into(),
276 ..Default::default()
278 }));
279 }
280
281 let &MemoryRequirements {
282 layout,
283 memory_type_bits,
284 prefers_dedicated_allocation: _,
285 requires_dedicated_allocation: _,
286 } = buffer.memory_requirements();
287 let external_memory_handle_types = buffer.external_memory_handle_types();
288
289 for (index, bind) in binds.iter().enumerate() {
290 bind.validate(device)
291 .map_err(|err| err.add_context(format!("binds[{}]", index)))?;
292
293 let &SparseBufferMemoryBind {
294 offset,
295 size,
296 ref memory,
297 _ne: _,
298 } = bind;
299
300 if offset >= layout.size() {
301 return Err(Box::new(ValidationError {
302 problem: format!(
303 "`binds[{}].offset` is not less than \
304 `buffer.memory_requirements().layout.size()`",
305 index
306 )
307 .into(),
308 vuids: &["VUID-VkSparseMemoryBind-resourceOffset-01099"],
309 ..Default::default()
310 }));
311 }
312
313 if size > layout.size() - offset {
314 return Err(Box::new(ValidationError {
315 problem: format!(
316 "`binds[{0}].offset + binds[{0}].size` is greater than \
317 `buffer.memory_requirements().layout.size()`",
318 index
319 )
320 .into(),
321 vuids: &["VUID-VkSparseMemoryBind-size-01100"],
322 ..Default::default()
323 }));
324 }
325
326 if !is_aligned(offset, layout.alignment()) {
327 return Err(Box::new(ValidationError {
328 problem: format!(
329 "`binds[{}].offset` is not aligned according to \
330 `buffer.memory_requirements().layout.alignment()`",
331 index
332 )
333 .into(),
334 ..Default::default()
336 }));
337 }
338
339 if !(size == layout.size() - offset || is_aligned(size, layout.alignment())) {
340 return Err(Box::new(ValidationError {
341 problem: format!(
342 "`binds[{0}].offset + binds[{0}].size` is not equal to \
343 `buffer.memory_requirements().layout.size()`, but is not aligned \
344 according to `buffer.memory_requirements().layout.alignment()`",
345 index
346 )
347 .into(),
348 ..Default::default()
350 }));
351 }
352
353 if let &Some((ref memory, memory_offset)) = memory {
354 if !is_aligned(memory_offset, layout.alignment()) {
355 return Err(Box::new(ValidationError {
356 problem: format!(
357 "`binds[{}].memory.1` is not aligned according to \
358 `buffer.memory_requirements().layout.alignment()`",
359 index
360 )
361 .into(),
362 vuids: &["VUID-VkSparseMemoryBind-memory-01096"],
363 ..Default::default()
364 }));
365 }
366
367 if memory_type_bits & (1 << memory.memory_type_index()) == 0 {
368 return Err(Box::new(ValidationError {
369 problem: format!(
370 "`binds[{}].memory.0.memory_type_index()` is not a bit set in \
371 `buffer.memory_requirements().memory_type_bits`",
372 index
373 )
374 .into(),
375 vuids: &["VUID-VkSparseMemoryBind-memory-01096"],
376 ..Default::default()
377 }));
378 }
379
380 if !memory.export_handle_types().is_empty() {
381 if !external_memory_handle_types.intersects(memory.export_handle_types()) {
382 return Err(Box::new(ValidationError {
383 problem: format!(
384 "`binds[{}].memory.0.export_handle_types()` is not empty, but \
385 it does not share at least one memory type with \
386 `buffer.external_memory_handle_types()`",
387 index
388 )
389 .into(),
390 vuids: &["VUID-VkSparseMemoryBind-memory-02730"],
391 ..Default::default()
392 }));
393 }
394 }
395
396 if let Some(handle_type) = memory.imported_handle_type() {
397 if !external_memory_handle_types.intersects(handle_type.into()) {
398 return Err(Box::new(ValidationError {
399 problem: format!(
400 "`binds[{}].memory.0` is imported, but \
401 `buffer.external_memory_handle_types()` \
402 does not contain the imported handle type",
403 index
404 )
405 .into(),
406 vuids: &["VUID-VkSparseMemoryBind-memory-02731"],
407 ..Default::default()
408 }));
409 }
410 }
411 }
412 }
413
414 Ok(())
415 }
416
417 pub(crate) fn to_vk<'a>(
418 &self,
419 fields1_vk: &'a SparseBufferMemoryBindInfoFields1Vk,
420 ) -> ash::vk::SparseBufferMemoryBindInfo<'a> {
421 let Self {
422 buffer,
423 binds: _,
424 _ne: _,
425 } = self;
426 let SparseBufferMemoryBindInfoFields1Vk { binds_vk } = fields1_vk;
427
428 ash::vk::SparseBufferMemoryBindInfo::default()
429 .buffer(buffer.handle())
430 .binds(binds_vk)
431 }
432
433 pub(crate) fn to_vk_fields1(&self) -> SparseBufferMemoryBindInfoFields1Vk {
434 let Self {
435 buffer: _,
436 binds,
437 _ne: _,
438 } = self;
439
440 let binds_vk = binds.iter().map(SparseBufferMemoryBind::to_vk).collect();
441
442 SparseBufferMemoryBindInfoFields1Vk { binds_vk }
443 }
444}
445
446pub(crate) struct SparseBufferMemoryBindInfoFields1Vk {
447 pub(crate) binds_vk: SmallVec<[ash::vk::SparseMemoryBind; 4]>,
448}
449
450#[derive(Clone, Debug)]
452pub struct SparseBufferMemoryBind {
453 pub offset: DeviceSize,
457
458 pub size: DeviceSize,
462
463 pub memory: Option<(Arc<DeviceMemory>, DeviceSize)>,
470
471 pub _ne: crate::NonExhaustive,
472}
473
474impl Default for SparseBufferMemoryBind {
475 fn default() -> Self {
476 Self {
477 offset: 0,
478 size: 0,
479 memory: None,
480 _ne: crate::NonExhaustive(()),
481 }
482 }
483}
484
485impl SparseBufferMemoryBind {
486 pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
487 let &Self {
488 offset: _,
489 size,
490 ref memory,
491 _ne: _,
492 } = self;
493
494 if size == 0 {
495 return Err(Box::new(ValidationError {
496 context: "size".into(),
497 problem: "is zero".into(),
498 vuids: &["VUID-VkSparseMemoryBind-size-01098"],
499 ..Default::default()
500 }));
501 }
502
503 if let &Some((ref memory, memory_offset)) = memory {
504 let memory_type = &device.physical_device().memory_properties().memory_types
505 [memory.memory_type_index() as usize];
506
507 if memory_type
508 .property_flags
509 .intersects(MemoryPropertyFlags::LAZILY_ALLOCATED)
510 {
511 return Err(Box::new(ValidationError {
512 problem: "`memory.0.memory_type_index()` refers to a memory type whose \
513 `property_flags` contains `MemoryPropertyFlags::LAZILY_ALLOCATED`"
514 .into(),
515 vuids: &["VUID-VkSparseMemoryBind-memory-01097"],
516 ..Default::default()
517 }));
518 }
519
520 if memory_offset >= memory.allocation_size() {
521 return Err(Box::new(ValidationError {
522 problem: "`memory.1` is not less than `memory.0.allocation_size()`".into(),
523 vuids: &["VUID-VkSparseMemoryBind-memoryOffset-01101"],
524 ..Default::default()
525 }));
526 }
527
528 if size > memory.allocation_size() - memory_offset {
529 return Err(Box::new(ValidationError {
530 problem: "`size` is greater than `memory.0.allocation_size()` minus \
531 `memory.1`"
532 .into(),
533 vuids: &["VUID-VkSparseMemoryBind-size-01102"],
534 ..Default::default()
535 }));
536 }
537 }
538
539 Ok(())
540 }
541
542 pub(crate) fn to_vk(&self) -> ash::vk::SparseMemoryBind {
543 let &Self {
544 offset,
545 size,
546 ref memory,
547 _ne: _,
548 } = self;
549
550 let (memory, memory_offset) = memory
551 .as_ref()
552 .map_or_else(Default::default, |(memory, memory_offset)| {
553 (memory.handle(), *memory_offset)
554 });
555
556 ash::vk::SparseMemoryBind {
557 resource_offset: offset,
558 size,
559 memory,
560 memory_offset,
561 flags: ash::vk::SparseMemoryBindFlags::empty(),
562 }
563 }
564}
565
566#[derive(Clone, Debug)]
571pub struct SparseImageOpaqueMemoryBindInfo {
572 pub image: Arc<Image>,
576
577 pub binds: Vec<SparseImageOpaqueMemoryBind>,
581
582 pub _ne: crate::NonExhaustive,
583}
584
585impl SparseImageOpaqueMemoryBindInfo {
586 #[inline]
588 pub fn new(image: Arc<Image>) -> Self {
589 Self {
590 image,
591 binds: Vec::new(),
592 _ne: crate::NonExhaustive(()),
593 }
594 }
595
596 pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
597 let &Self {
598 ref image,
599 ref binds,
600 _ne: crate::NonExhaustive(()),
601 } = self;
602
603 assert_eq!(device, image.device().as_ref());
604 assert!(!binds.is_empty());
605
606 if !image.flags().intersects(ImageCreateFlags::SPARSE_BINDING) {
607 return Err(Box::new(ValidationError {
608 context: "image.flags()".into(),
609 problem: "does not contain `ImageCreateFlags::SPARSE_BINDING`".into(),
610 ..Default::default()
612 }));
613 }
614
615 let &MemoryRequirements {
616 layout,
617 memory_type_bits,
618 prefers_dedicated_allocation: _,
619 requires_dedicated_allocation: _,
620 } = &image.memory_requirements()[0]; let metadata_memory_requirements = image.sparse_memory_requirements().iter().find(|reqs| {
622 reqs.format_properties
623 .aspects
624 .intersects(ImageAspects::METADATA)
625 });
626 let external_memory_handle_types = image.external_memory_handle_types();
627
628 for (index, bind) in binds.iter().enumerate() {
629 bind.validate(device)
630 .map_err(|err| err.add_context(format!("binds[{}]", index)))?;
631
632 let &SparseImageOpaqueMemoryBind {
633 offset,
634 size,
635 ref memory,
636 metadata,
637 _ne: _,
638 } = bind;
639
640 if metadata {
641 let &SparseImageMemoryRequirements {
649 format_properties: _,
650 image_mip_tail_first_lod: _,
651 image_mip_tail_size,
652 image_mip_tail_offset,
653 image_mip_tail_stride,
654 } = metadata_memory_requirements.ok_or_else(|| {
655 Box::new(ValidationError {
656 problem: format!(
657 "`binds[{}].metadata` is `true`, but there is no \
658 `SparseImageMemoryRequirements` element in `image.memory()` where \
659 `format_properties.aspects` contains `ImageAspects::METADATA`",
660 index
661 )
662 .into(),
663 ..Default::default()
665 })
666 })?;
667
668 let offset_from_mip_tail = offset.checked_sub(image_mip_tail_offset);
669
670 if let Some(image_mip_tail_stride) = image_mip_tail_stride {
671 let (array_layer, offset_from_array_layer) = offset_from_mip_tail
672 .map(|offset_from_mip_tail| {
673 (
674 offset_from_mip_tail / image_mip_tail_stride,
675 offset_from_mip_tail % image_mip_tail_stride,
676 )
677 })
678 .filter(|&(array_layer, offset_from_array_layer)| {
679 array_layer < image.array_layers() as DeviceSize
680 && offset_from_array_layer < image_mip_tail_size
681 })
682 .ok_or_else(|| {
683 Box::new(ValidationError {
684 problem: format!(
685 "`binds[{0}].metadata` is `true`, but `binds[{0}].offset` \
686 does not fall within the metadata mip tail binding range \
687 for any array layer of `image`",
688 index
689 )
690 .into(),
691 vuids: &["VUID-VkSparseImageOpaqueMemoryBindInfo-pBinds-01103"],
692 ..Default::default()
693 })
694 })?;
695
696 if size > image_mip_tail_size - offset_from_array_layer {
697 return Err(Box::new(ValidationError {
698 problem: format!(
699 "`binds[{0}].metadata` is `true`, and `binds[{0}].offset` \
700 falls within the metadata mip tail binding range for \
701 array layer {1} of `image`, but \
702 `binds[{0}].offset + binds[{0}].size` is greater than the \
703 end of that binding range",
704 index, array_layer
705 )
706 .into(),
707 vuids: &["VUID-VkSparseImageOpaqueMemoryBindInfo-pBinds-01103"],
708 ..Default::default()
709 }));
710 }
711 } else {
712 let offset_from_mip_tail = offset_from_mip_tail
713 .filter(|&offset_from_mip_tail| offset_from_mip_tail < image_mip_tail_size)
714 .ok_or_else(|| {
715 Box::new(ValidationError {
716 problem: format!(
717 "`binds[{0}].metadata` is `true`, but `binds[{0}].offset` \
718 does not fall within the metadata mip tail binding range \
719 of `image`",
720 index
721 )
722 .into(),
723 vuids: &["VUID-VkSparseImageOpaqueMemoryBindInfo-pBinds-01103"],
724 ..Default::default()
725 })
726 })?;
727
728 if size > image_mip_tail_size - offset_from_mip_tail {
729 return Err(Box::new(ValidationError {
730 problem: format!(
731 "`binds[{0}].metadata` is `true`, but \
732 `binds[{0}].offset + binds[{0}].size` is greater than \
733 the end of the metadata mip tail binding range of `image`",
734 index,
735 )
736 .into(),
737 vuids: &["VUID-VkSparseImageOpaqueMemoryBindInfo-pBinds-01103"],
738 ..Default::default()
739 }));
740 }
741 }
742 } else {
743 if offset >= layout.size() {
748 return Err(Box::new(ValidationError {
749 problem: format!(
750 "`binds[{}].offset` is not less than \
751 `image.memory_requirements()[0].layout.size()`",
752 index
753 )
754 .into(),
755 vuids: &["VUID-VkSparseMemoryBind-resourceOffset-01099"],
756 ..Default::default()
757 }));
758 }
759
760 if size > layout.size() - offset {
761 return Err(Box::new(ValidationError {
762 problem: format!(
763 "`binds[{0}].offset + binds[{0}].size` is greater than \
764 `image.memory_requirements()[0].layout.size()`",
765 index
766 )
767 .into(),
768 vuids: &["VUID-VkSparseMemoryBind-size-01100"],
769 ..Default::default()
770 }));
771 }
772 }
773
774 if !is_aligned(offset, layout.alignment()) {
775 return Err(Box::new(ValidationError {
776 problem: format!(
777 "`binds[{}].offset` is not aligned according to \
778 `image.memory_requirements()[0].layout.alignment()`",
779 index
780 )
781 .into(),
782 ..Default::default()
784 }));
785 }
786
787 if !(size == layout.size() - offset || is_aligned(size, layout.alignment())) {
788 return Err(Box::new(ValidationError {
789 problem: format!(
790 "`binds[{0}].offset + binds[{}].size` is not equal to \
791 `image.memory_requirements()[0].layout.size()`, but is not aligned \
792 according to `image.memory_requirements()[0].layout.alignment()`",
793 index
794 )
795 .into(),
796 ..Default::default()
798 }));
799 }
800
801 if let &Some((ref memory, memory_offset)) = memory {
802 if !is_aligned(memory_offset, layout.alignment()) {
803 return Err(Box::new(ValidationError {
804 problem: format!(
805 "`binds[{}].memory.1` is not aligned according to \
806 `image.memory_requirements()[0].layout.alignment()`",
807 index
808 )
809 .into(),
810 vuids: &["VUID-VkSparseMemoryBind-memory-01096"],
811 ..Default::default()
812 }));
813 }
814
815 if memory_type_bits & (1 << memory.memory_type_index()) == 0 {
816 return Err(Box::new(ValidationError {
817 problem: format!(
818 "`binds[{}].memory.0.memory_type_index()` is not a bit set in \
819 `image.memory_requirements()[0].memory_type_bits`",
820 index
821 )
822 .into(),
823 vuids: &["VUID-VkSparseMemoryBind-memory-01096"],
824 ..Default::default()
825 }));
826 }
827
828 if !memory.export_handle_types().is_empty() {
829 if !external_memory_handle_types.intersects(memory.export_handle_types()) {
830 return Err(Box::new(ValidationError {
831 problem: format!(
832 "`binds[{}].memory.0.export_handle_types()` is not empty, but \
833 it does not share at least one memory type with \
834 `image.external_memory_handle_types()`",
835 index
836 )
837 .into(),
838 vuids: &["VUID-VkSparseMemoryBind-memory-02730"],
839 ..Default::default()
840 }));
841 }
842 }
843
844 if let Some(handle_type) = memory.imported_handle_type() {
845 if !external_memory_handle_types.intersects(handle_type.into()) {
846 return Err(Box::new(ValidationError {
847 problem: format!(
848 "`binds[{}].memory.0` is imported, but \
849 `image.external_memory_handle_types()` \
850 does not contain the imported handle type",
851 index
852 )
853 .into(),
854 vuids: &["VUID-VkSparseMemoryBind-memory-02731"],
855 ..Default::default()
856 }));
857 }
858 }
859 }
860 }
861
862 Ok(())
863 }
864
865 pub(crate) fn to_vk<'a>(
866 &self,
867 fields1_vk: &'a SparseImageOpaqueMemoryBindInfoFields1Vk,
868 ) -> ash::vk::SparseImageOpaqueMemoryBindInfo<'a> {
869 let Self {
870 image,
871 binds: _,
872 _ne: _,
873 } = self;
874 let SparseImageOpaqueMemoryBindInfoFields1Vk { binds_vk } = fields1_vk;
875
876 ash::vk::SparseImageOpaqueMemoryBindInfo::default()
877 .image(image.handle())
878 .binds(binds_vk)
879 }
880
881 pub(crate) fn to_vk_fields1(&self) -> SparseImageOpaqueMemoryBindInfoFields1Vk {
882 let Self {
883 image: _,
884 binds,
885 _ne: _,
886 } = self;
887
888 let binds_vk = binds
889 .iter()
890 .map(SparseImageOpaqueMemoryBind::to_vk)
891 .collect();
892
893 SparseImageOpaqueMemoryBindInfoFields1Vk { binds_vk }
894 }
895}
896
897pub(crate) struct SparseImageOpaqueMemoryBindInfoFields1Vk {
898 pub(crate) binds_vk: SmallVec<[ash::vk::SparseMemoryBind; 4]>,
899}
900
901#[derive(Clone, Debug)]
907pub struct SparseImageOpaqueMemoryBind {
908 pub offset: DeviceSize,
912
913 pub size: DeviceSize,
917
918 pub memory: Option<(Arc<DeviceMemory>, DeviceSize)>,
925
926 pub metadata: bool,
931
932 pub _ne: crate::NonExhaustive,
933}
934
935impl Default for SparseImageOpaqueMemoryBind {
936 fn default() -> Self {
937 Self {
938 offset: 0,
939 size: 0,
940 memory: None,
941 metadata: false,
942 _ne: crate::NonExhaustive(()),
943 }
944 }
945}
946
947impl SparseImageOpaqueMemoryBind {
948 pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
949 let &Self {
950 offset: _,
951 size,
952 ref memory,
953 metadata: _,
954 _ne: _,
955 } = self;
956
957 if size == 0 {
958 return Err(Box::new(ValidationError {
959 context: "size".into(),
960 problem: "is zero".into(),
961 vuids: &["VUID-VkSparseMemoryBind-size-01098"],
962 ..Default::default()
963 }));
964 }
965
966 if let &Some((ref memory, memory_offset)) = memory {
967 let memory_type = &device.physical_device().memory_properties().memory_types
968 [memory.memory_type_index() as usize];
969
970 if memory_type
971 .property_flags
972 .intersects(MemoryPropertyFlags::LAZILY_ALLOCATED)
973 {
974 return Err(Box::new(ValidationError {
975 problem: "`memory.0.memory_type_index()` refers to a memory type whose \
976 `property_flags` contains `MemoryPropertyFlags::LAZILY_ALLOCATED`"
977 .into(),
978 vuids: &["VUID-VkSparseMemoryBind-memory-01097"],
979 ..Default::default()
980 }));
981 }
982
983 if memory_offset >= memory.allocation_size() {
984 return Err(Box::new(ValidationError {
985 problem: "`memory.1` is not less than `memory.0.allocation_size()`".into(),
986 vuids: &["VUID-VkSparseMemoryBind-memoryOffset-01101"],
987 ..Default::default()
988 }));
989 }
990
991 if size > memory.allocation_size() - memory_offset {
992 return Err(Box::new(ValidationError {
993 problem: "`size` is greater than `memory.0.allocation_size()` minus \
994 `memory.1`"
995 .into(),
996 vuids: &["VUID-VkSparseMemoryBind-size-01102"],
997 ..Default::default()
998 }));
999 }
1000 }
1001
1002 Ok(())
1003 }
1004
1005 pub(crate) fn to_vk(&self) -> ash::vk::SparseMemoryBind {
1006 let &Self {
1007 offset,
1008 size,
1009 ref memory,
1010 metadata,
1011 _ne: _,
1012 } = self;
1013
1014 let (memory, memory_offset) = memory
1015 .as_ref()
1016 .map_or_else(Default::default, |(memory, memory_offset)| {
1017 (memory.handle(), *memory_offset)
1018 });
1019
1020 ash::vk::SparseMemoryBind {
1021 resource_offset: offset,
1022 size,
1023 memory,
1024 memory_offset,
1025 flags: if metadata {
1026 ash::vk::SparseMemoryBindFlags::METADATA
1027 } else {
1028 ash::vk::SparseMemoryBindFlags::empty()
1029 },
1030 }
1031 }
1032}
1033
1034#[derive(Clone, Debug)]
1040pub struct SparseImageMemoryBindInfo {
1041 pub image: Arc<Image>,
1045
1046 pub binds: Vec<SparseImageMemoryBind>,
1050
1051 pub _ne: crate::NonExhaustive,
1052}
1053
1054impl SparseImageMemoryBindInfo {
1055 #[inline]
1057 pub fn new(image: Arc<Image>) -> Self {
1058 Self {
1059 image,
1060 binds: Vec::new(),
1061 _ne: crate::NonExhaustive(()),
1062 }
1063 }
1064
1065 pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1066 let &Self {
1067 ref image,
1068 ref binds,
1069 _ne: _,
1070 } = self;
1071
1072 assert_eq!(device, image.device().as_ref());
1073 assert!(!binds.is_empty());
1074
1075 if !image.flags().intersects(ImageCreateFlags::SPARSE_BINDING) {
1076 return Err(Box::new(ValidationError {
1077 context: "image.flags()".into(),
1078 problem: "does not contain `ImageCreateFlags::SPARSE_BINDING`".into(),
1079 ..Default::default()
1081 }));
1082 }
1083
1084 if !image.flags().intersects(ImageCreateFlags::SPARSE_RESIDENCY) {
1085 return Err(Box::new(ValidationError {
1086 context: "image.flags()".into(),
1087 problem: "does not contain `ImageCreateFlags::SPARSE_RESIDENCY`".into(),
1088 vuids: &["VUID-VkSparseImageMemoryBindInfo-image-02901"],
1089 ..Default::default()
1090 }));
1091 }
1092
1093 let image_format_subsampled_extent = image
1094 .format()
1095 .ycbcr_chroma_sampling()
1096 .map_or(image.extent(), |s| s.subsampled_extent(image.extent()));
1097 let external_memory_handle_types = image.external_memory_handle_types();
1098
1099 for (index, bind) in binds.iter().enumerate() {
1100 bind.validate(device)
1101 .map_err(|err| err.add_context(format!("binds[{}]", index)))?;
1102
1103 let &SparseImageMemoryBind {
1104 aspects,
1105 mip_level,
1106 array_layer,
1107 offset,
1108 extent,
1109 ref memory,
1110 _ne: _,
1111 } = bind;
1112
1113 if mip_level >= image.mip_levels() {
1114 return Err(Box::new(ValidationError {
1115 problem: format!(
1116 "`binds[{}].mip_level` is not less than `image.mip_levels()`",
1117 index
1118 )
1119 .into(),
1120 vuids: &["VUID-VkSparseImageMemoryBind-subresource-01106"],
1121 ..Default::default()
1122 }));
1123 }
1124
1125 if array_layer >= image.array_layers() {
1126 return Err(Box::new(ValidationError {
1127 problem: format!(
1128 "`binds[{}].array_layer` is not less than `image.array_layers()`",
1129 index
1130 )
1131 .into(),
1132 vuids: &["VUID-VkSparseImageMemoryBind-subresource-01106"],
1133 ..Default::default()
1134 }));
1135 }
1136
1137 if !image.format().aspects().contains(aspects) {
1138 return Err(Box::new(ValidationError {
1139 problem: format!(
1140 "`binds[{}].aspects` is not a subset of the aspects of the \
1141 format of `image`",
1142 index
1143 )
1144 .into(),
1145 vuids: &["VUID-VkSparseImageMemoryBind-subresource-01106"],
1146 ..Default::default()
1147 }));
1148 }
1149
1150 let &SparseImageMemoryRequirements {
1151 format_properties:
1152 SparseImageFormatProperties {
1153 aspects,
1154 image_granularity,
1155 flags: _,
1156 },
1157 image_mip_tail_first_lod,
1158 image_mip_tail_size: _,
1159 image_mip_tail_offset: _,
1160 image_mip_tail_stride: _,
1161 } = image
1162 .sparse_memory_requirements()
1163 .iter()
1164 .find(|reqs| reqs.format_properties.aspects == aspects)
1165 .ok_or_else(|| {
1166 Box::new(ValidationError {
1167 problem: format!(
1168 "there is no `SparseImageMemoryRequirements` element in \
1169 `image.memory()` where `format_properties.aspects` equals \
1170 binds[{}].aspects",
1171 index
1172 )
1173 .into(),
1174 ..Default::default()
1176 })
1177 })?;
1178
1179 if mip_level >= image_mip_tail_first_lod {
1180 return Err(Box::new(ValidationError {
1181 problem: format!(
1182 "`binds[{}].mip_level` is not less than \
1183 `SparseImageMemoryRequirements::image_mip_tail_first_lod` for `image`",
1184 index
1185 )
1186 .into(),
1187 ..Default::default()
1189 }));
1190 }
1191
1192 if offset[0] % image_granularity[0] != 0 {
1193 return Err(Box::new(ValidationError {
1194 problem: format!(
1195 "`binds[{}].offset[0]` is not a multiple of \
1196 `SparseImageMemoryRequirements::format_properties.image_granularity[0]` \
1197 for `image`",
1198 index
1199 )
1200 .into(),
1201 vuids: &["VUID-VkSparseImageMemoryBind-offset-01107"],
1202 ..Default::default()
1203 }));
1204 }
1205
1206 if offset[1] % image_granularity[1] != 0 {
1207 return Err(Box::new(ValidationError {
1208 problem: format!(
1209 "`binds[{}].offset[1]` is not a multiple of `
1210 `SparseImageMemoryRequirements::format_properties.image_granularity[1]` \
1211 for `image`",
1212 index
1213 )
1214 .into(),
1215 vuids: &["VUID-VkSparseImageMemoryBind-offset-01109"],
1216 ..Default::default()
1217 }));
1218 }
1219
1220 if offset[2] % image_granularity[2] != 0 {
1221 return Err(Box::new(ValidationError {
1222 problem: format!(
1223 "`binds[{}].offset[2]` is not a multiple of `
1224 `SparseImageMemoryRequirements::format_properties.image_granularity[2]` \
1225 for `image`",
1226 index
1227 )
1228 .into(),
1229 vuids: &["VUID-VkSparseImageMemoryBind-offset-01111"],
1230 ..Default::default()
1231 }));
1232 }
1233
1234 let mut subresource_extent = mip_level_extent(image.extent(), mip_level).unwrap();
1235
1236 if aspects.intersects(ImageAspects::PLANE_1 | ImageAspects::PLANE_2)
1238 && (aspects - (ImageAspects::PLANE_1 | ImageAspects::PLANE_2)).is_empty()
1239 {
1240 subresource_extent = image_format_subsampled_extent;
1241 }
1242
1243 if offset[0]
1244 .checked_add(extent[0])
1245 .map_or(true, |sum| sum > subresource_extent[0])
1246 {
1247 return Err(Box::new(ValidationError {
1248 problem: format!(
1249 "`binds[{0}].offset[0]` + `binds[{0}].extent[0]` is greater than the \
1250 width of the selected subresource of `image`",
1251 index
1252 )
1253 .into(),
1254 ..Default::default()
1256 }));
1257 }
1258
1259 if offset[1]
1260 .checked_add(extent[1])
1261 .map_or(true, |sum| sum > subresource_extent[1])
1262 {
1263 return Err(Box::new(ValidationError {
1264 problem: format!(
1265 "`binds[{0}].offset[1]` + `binds[{0}].extent[1]` is greater than the \
1266 height of the selected subresource of `image`",
1267 index
1268 )
1269 .into(),
1270 ..Default::default()
1272 }));
1273 }
1274
1275 if offset[2]
1276 .checked_add(extent[2])
1277 .map_or(true, |sum| sum > subresource_extent[2])
1278 {
1279 return Err(Box::new(ValidationError {
1280 problem: format!(
1281 "`binds[{0}].offset[2]` + `binds[{0}].extent[2]` is greater than the \
1282 depth of the selected subresource of `image`",
1283 index
1284 )
1285 .into(),
1286 ..Default::default()
1288 }));
1289 }
1290
1291 if !(offset[0] + extent[0] == subresource_extent[0]
1292 || extent[0] % image_granularity[0] == 0)
1293 {
1294 return Err(Box::new(ValidationError {
1295 problem: format!(
1296 "`binds[{0}].offset[0]` + `binds[{0}].extent[0]` is not equal to the \
1297 width of the selected subresource of `image`, but it is not a multiple of \
1298 `SparseImageMemoryRequirements::format_properties.image_granularity[0]` \
1299 for `image`",
1300 index
1301 )
1302 .into(),
1303 vuids: &["VUID-VkSparseImageMemoryBind-extent-01108"],
1304 ..Default::default()
1305 }));
1306 }
1307
1308 if !(offset[1] + extent[1] == subresource_extent[1]
1309 || extent[1] % image_granularity[1] == 0)
1310 {
1311 return Err(Box::new(ValidationError {
1312 problem: format!(
1313 "`binds[{0}].offset[1]` + `binds[{0}].extent[1]` is not equal to the \
1314 height of the selected subresource of `image`, but it is not a multiple of \
1315 `SparseImageMemoryRequirements::format_properties.image_granularity[1]` \
1316 for `image`",
1317 index
1318 )
1319 .into(),
1320 vuids: &["VUID-VkSparseImageMemoryBind-extent-01110"],
1321 ..Default::default()
1322 }));
1323 }
1324
1325 if !(offset[2] + extent[2] == subresource_extent[2]
1326 || extent[2] % image_granularity[2] == 0)
1327 {
1328 return Err(Box::new(ValidationError {
1329 problem: format!(
1330 "`binds[{0}].offset[2]` + `binds[{0}].extent[2]` is not equal to the \
1331 depth of the selected subresource of `image`, but it is not a multiple of \
1332 `SparseImageMemoryRequirements::format_properties.image_granularity[2]` \
1333 for `image`",
1334 index
1335 )
1336 .into(),
1337 vuids: &["VUID-VkSparseImageMemoryBind-extent-01112"],
1338 ..Default::default()
1339 }));
1340 }
1341
1342 if let &Some((ref memory, memory_offset)) = memory {
1343 let &MemoryRequirements {
1344 layout,
1345 memory_type_bits,
1346 prefers_dedicated_allocation: _,
1347 requires_dedicated_allocation: _,
1348 } = &image.memory_requirements()[0]; if !is_aligned(memory_offset, layout.alignment()) {
1351 return Err(Box::new(ValidationError {
1352 problem: format!(
1353 "`binds[{}].memory.1` is not aligned according to \
1354 `image.memory_requirements()[0].layout.alignment()`",
1355 index
1356 )
1357 .into(),
1358 vuids: &["VUID-VkSparseImageMemoryBind-memory-01105"],
1359 ..Default::default()
1360 }));
1361 }
1362
1363 if memory_type_bits & (1 << memory.memory_type_index()) == 0 {
1364 return Err(Box::new(ValidationError {
1365 problem: format!(
1366 "`binds[{}].memory.0.memory_type_index()` is not a bit set in \
1367 `image.memory_requirements()[0].memory_type_bits`",
1368 index
1369 )
1370 .into(),
1371 vuids: &["VUID-VkSparseImageMemoryBind-memory-01105"],
1372 ..Default::default()
1373 }));
1374 }
1375
1376 if !memory.export_handle_types().is_empty() {
1377 if !external_memory_handle_types.intersects(memory.export_handle_types()) {
1378 return Err(Box::new(ValidationError {
1379 problem: format!(
1380 "`binds[{}].memory.0.export_handle_types()` is not empty, but \
1381 it does not share at least one memory type with \
1382 `image.external_memory_handle_types()`",
1383 index
1384 )
1385 .into(),
1386 vuids: &["VUID-VkSparseImageMemoryBind-memory-02732"],
1387 ..Default::default()
1388 }));
1389 }
1390 }
1391
1392 if let Some(handle_type) = memory.imported_handle_type() {
1393 if !external_memory_handle_types.intersects(handle_type.into()) {
1394 return Err(Box::new(ValidationError {
1395 problem: format!(
1396 "`binds[{}].memory.0` is imported, but \
1397 `image.external_memory_handle_types()` \
1398 does not contain the imported handle type",
1399 index
1400 )
1401 .into(),
1402 vuids: &["VUID-VkSparseImageMemoryBind-memory-02733"],
1403 ..Default::default()
1404 }));
1405 }
1406 }
1407 }
1408 }
1409
1410 Ok(())
1411 }
1412
1413 pub(crate) fn to_vk<'a>(
1414 &self,
1415 fields1_vk: &'a SparseImageMemoryBindInfoFields1Vk,
1416 ) -> ash::vk::SparseImageMemoryBindInfo<'a> {
1417 let Self {
1418 image,
1419 binds: _,
1420 _ne: _,
1421 } = self;
1422 let SparseImageMemoryBindInfoFields1Vk { binds_vk } = fields1_vk;
1423
1424 ash::vk::SparseImageMemoryBindInfo::default()
1425 .image(image.handle())
1426 .binds(binds_vk)
1427 }
1428
1429 pub(crate) fn to_vk_fields1(&self) -> SparseImageMemoryBindInfoFields1Vk {
1430 let Self {
1431 image: _,
1432 binds,
1433 _ne: _,
1434 } = self;
1435
1436 let binds_vk = binds.iter().map(SparseImageMemoryBind::to_vk).collect();
1437
1438 SparseImageMemoryBindInfoFields1Vk { binds_vk }
1439 }
1440}
1441
1442pub(crate) struct SparseImageMemoryBindInfoFields1Vk {
1443 pub(crate) binds_vk: SmallVec<[ash::vk::SparseImageMemoryBind; 4]>,
1444}
1445
1446#[derive(Clone, Debug)]
1452pub struct SparseImageMemoryBind {
1453 pub aspects: ImageAspects,
1457
1458 pub mip_level: u32,
1462
1463 pub array_layer: u32,
1467
1468 pub offset: [u32; 3],
1477
1478 pub extent: [u32; 3],
1488
1489 pub memory: Option<(Arc<DeviceMemory>, DeviceSize)>,
1496
1497 pub _ne: crate::NonExhaustive,
1498}
1499
1500impl Default for SparseImageMemoryBind {
1501 fn default() -> Self {
1502 Self {
1503 aspects: ImageAspects::empty(),
1504 mip_level: 0,
1505 array_layer: 0,
1506 offset: [0; 3],
1507 extent: [0; 3],
1508 memory: None,
1509 _ne: crate::NonExhaustive(()),
1510 }
1511 }
1512}
1513
1514impl SparseImageMemoryBind {
1515 pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1516 let &Self {
1517 aspects,
1518 mip_level: _,
1519 array_layer: _,
1520 offset: _,
1521 extent,
1522 ref memory,
1523 _ne: _,
1524 } = self;
1525
1526 aspects.validate_device(device).map_err(|err| {
1527 err.add_context("aspects")
1528 .set_vuids(&["VUID-VkImageSubresource-aspectMask-parameter"])
1529 })?;
1530
1531 if aspects.is_empty() {
1532 return Err(Box::new(ValidationError {
1533 context: "aspects".into(),
1534 problem: "is empty".into(),
1535 vuids: &["VUID-VkImageSubresource-aspectMask-requiredbitmask"],
1536 ..Default::default()
1537 }));
1538 }
1539
1540 if let &Some((ref memory, memory_offset)) = memory {
1541 if memory_offset >= memory.allocation_size() {
1542 return Err(Box::new(ValidationError {
1543 problem: "`memory.1` is not less than `memory.0.allocation_size()`".into(),
1544 ..Default::default()
1546 }));
1547 }
1548 }
1549
1550 if extent[0] == 0 {
1551 return Err(Box::new(ValidationError {
1552 context: "extent[0]".into(),
1553 problem: "is zero".into(),
1554 vuids: &["VUID-VkSparseImageMemoryBind-extent-09388"],
1555 ..Default::default()
1556 }));
1557 }
1558
1559 if extent[1] == 0 {
1560 return Err(Box::new(ValidationError {
1561 context: "extent[1]".into(),
1562 problem: "is zero".into(),
1563 vuids: &["VUID-VkSparseImageMemoryBind-extent-09389"],
1564 ..Default::default()
1565 }));
1566 }
1567
1568 if extent[2] == 0 {
1569 return Err(Box::new(ValidationError {
1570 context: "extent[2]".into(),
1571 problem: "is zero".into(),
1572 vuids: &["VUID-VkSparseImageMemoryBind-extent-09390"],
1573 ..Default::default()
1574 }));
1575 }
1576
1577 Ok(())
1583 }
1584
1585 pub(crate) fn to_vk(&self) -> ash::vk::SparseImageMemoryBind {
1586 let &Self {
1587 aspects,
1588 mip_level,
1589 array_layer,
1590 offset,
1591 extent,
1592 ref memory,
1593 _ne: _,
1594 } = self;
1595
1596 let (memory, memory_offset) = memory
1597 .as_ref()
1598 .map_or_else(Default::default, |(memory, memory_offset)| {
1599 (memory.handle(), *memory_offset)
1600 });
1601
1602 ash::vk::SparseImageMemoryBind {
1603 subresource: ash::vk::ImageSubresource {
1604 aspect_mask: aspects.into(),
1605 mip_level,
1606 array_layer,
1607 },
1608 offset: ash::vk::Offset3D {
1609 x: offset[0] as i32,
1610 y: offset[1] as i32,
1611 z: offset[2] as i32,
1612 },
1613 extent: ash::vk::Extent3D {
1614 width: extent[0],
1615 height: extent[1],
1616 depth: extent[2],
1617 },
1618 memory,
1619 memory_offset,
1620 flags: ash::vk::SparseMemoryBindFlags::empty(),
1621 }
1622 }
1623}