Skip to main content

vulkano/memory/
sparse.rs

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/// Parameters to execute sparse bind operations on a queue.
17#[derive(Clone, Debug)]
18pub struct BindSparseInfo {
19    /// The semaphores to wait for before beginning the execution of this batch of
20    /// sparse bind operations.
21    ///
22    /// The default value is empty.
23    pub wait_semaphores: Vec<Arc<Semaphore>>,
24
25    /// The bind operations to perform for buffers.
26    ///
27    /// The default value is empty.
28    pub buffer_binds: Vec<SparseBufferMemoryBindInfo>,
29
30    /// The bind operations to perform for images with an opaque memory layout.
31    ///
32    /// This should be used for mip tail regions, the metadata aspect, and for the normal regions
33    /// of images that do not have the `SPARSE_RESIDENCY` flag set.
34    ///
35    /// The default value is empty.
36    pub image_opaque_binds: Vec<SparseImageOpaqueMemoryBindInfo>,
37
38    /// The bind operations to perform for images with a known memory layout.
39    ///
40    /// This type of sparse bind can only be used for images that have the `SPARSE_RESIDENCY`
41    /// flag set.
42    /// Only the normal texel regions can be bound this way, not the mip tail regions or metadata
43    /// aspect.
44    ///
45    /// The default value is empty.
46    pub image_binds: Vec<SparseImageMemoryBindInfo>,
47
48    /// The semaphores to signal after the execution of this batch of sparse bind operations
49    /// has completed.
50    ///
51    /// The default value is empty.
52    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/// Parameters for sparse bind operations on a buffer.
236#[derive(Clone, Debug)]
237pub struct SparseBufferMemoryBindInfo {
238    /// The buffer to perform the binding operations on.
239    ///
240    /// There is no default value.
241    pub buffer: Arc<Buffer>,
242
243    /// The bind operations to perform.
244    ///
245    /// The default value is empty.
246    pub binds: Vec<SparseBufferMemoryBind>,
247
248    pub _ne: crate::NonExhaustive,
249}
250
251impl SparseBufferMemoryBindInfo {
252    /// Returns a `SparseBufferMemoryBindInfo` with the specified `buffer`.
253    #[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                // vuids: TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/2253
277                ..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                    // vuids: TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/2255,
335                    ..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                    // vuids: TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/2255,
349                    ..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/// Parameters for a single sparse bind operation on a buffer.
451#[derive(Clone, Debug)]
452pub struct SparseBufferMemoryBind {
453    /// The offset in bytes from the start of the buffer's memory, where memory is to be (un)bound.
454    ///
455    /// The default value is `0`.
456    pub offset: DeviceSize,
457
458    /// The size in bytes of the memory to be (un)bound.
459    ///
460    /// The default value is `0`, which must be overridden.
461    pub size: DeviceSize,
462
463    /// If `Some`, specifies the memory and an offset into that memory that is to be bound.
464    /// The provided memory must match the buffer's memory requirements.
465    ///
466    /// If `None`, specifies that existing memory at the specified location is to be unbound.
467    ///
468    /// The default value is `None`.
469    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/// Parameters for sparse bind operations on parts of an image with an opaque memory layout.
567///
568/// This type of sparse bind should be used for mip tail regions, the metadata aspect, and for the
569/// normal regions of images that do not have the `sparse_residency` flag set.
570#[derive(Clone, Debug)]
571pub struct SparseImageOpaqueMemoryBindInfo {
572    /// The image to perform the binding operations on.
573    ///
574    /// There is no default value.
575    pub image: Arc<Image>,
576
577    /// The bind operations to perform.
578    ///
579    /// The default value is empty.
580    pub binds: Vec<SparseImageOpaqueMemoryBind>,
581
582    pub _ne: crate::NonExhaustive,
583}
584
585impl SparseImageOpaqueMemoryBindInfo {
586    /// Returns a `SparseImageOpaqueMemoryBindInfo` with the specified `image`.
587    #[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                // vuids: TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/2253
611                ..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]; // TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/2259
621        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                // VkSparseMemoryBind spec:
642                // If flags contains VK_SPARSE_MEMORY_BIND_METADATA_BIT,
643                // the binding range must be within the mip tail region of the metadata aspect.
644                // This metadata region is defined by:
645                // metadataRegion = [base, base + imageMipTailSize)
646                // base = imageMipTailOffset + imageMipTailStride × n
647
648                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                        // vuids?
664                        ..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                // VkSparseMemoryBind spec:
744                // If flags does not contain VK_SPARSE_MEMORY_BIND_METADATA_BIT,
745                // the binding range must be within the range [0,VkMemoryRequirements::size).
746
747                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                    // vuids: TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/2255,
783                    ..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                    // vuids: TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/2255,
797                    ..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/// Parameters for a single sparse bind operation on parts of an image with an opaque memory
902/// layout.
903///
904/// This type of sparse bind should be used for mip tail regions, the metadata aspect, and for the
905/// normal regions of images that do not have the `SPARSE_RESIDENCY` flag set.
906#[derive(Clone, Debug)]
907pub struct SparseImageOpaqueMemoryBind {
908    /// The offset in bytes from the start of the image's memory, where memory is to be (un)bound.
909    ///
910    /// The default value is `0`.
911    pub offset: DeviceSize,
912
913    /// The size in bytes of the memory to be (un)bound.
914    ///
915    /// The default value is `0`, which must be overridden.
916    pub size: DeviceSize,
917
918    /// If `Some`, specifies the memory and an offset into that memory that is to be bound.
919    /// The provided memory must match the image's memory requirements.
920    ///
921    /// If `None`, specifies that existing memory at the specified location is to be unbound.
922    ///
923    /// The default value is `None`.
924    pub memory: Option<(Arc<DeviceMemory>, DeviceSize)>,
925
926    /// Sets whether the binding should apply to the metadata aspect of the image, or to the
927    /// normal texel data.
928    ///
929    /// The default value is `false`.
930    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/// Parameters for sparse bind operations on parts of an image with a known memory layout.
1035///
1036/// This type of sparse bind can only be used for images that have the `sparse_residency` flag set.
1037/// Only the normal texel regions can be bound this way, not the mip tail regions or metadata
1038/// aspect.
1039#[derive(Clone, Debug)]
1040pub struct SparseImageMemoryBindInfo {
1041    /// The image to perform the binding operations on.
1042    ///
1043    /// There is no default value.
1044    pub image: Arc<Image>,
1045
1046    /// The bind operations to perform.
1047    ///
1048    /// The default value is empty.
1049    pub binds: Vec<SparseImageMemoryBind>,
1050
1051    pub _ne: crate::NonExhaustive,
1052}
1053
1054impl SparseImageMemoryBindInfo {
1055    /// Returns a `SparseImageMemoryBindInfo` with the specified `image`.
1056    #[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                // vuids: TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/2253
1080                ..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                        // vuids: https://github.com/KhronosGroup/Vulkan-Docs/issues/2254
1175                        ..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                    // vuids: TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/2258
1188                    ..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            // Only subsample if there are no other aspects.
1237            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                    // VUID? See https://github.com/KhronosGroup/Vulkan-Docs/issues/2490
1255                    ..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                    // VUID? See https://github.com/KhronosGroup/Vulkan-Docs/issues/2490
1271                    ..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                    // VUID? See https://github.com/KhronosGroup/Vulkan-Docs/issues/2490
1287                    ..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]; // TODO: what to do about disjoint images?
1349
1350                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/// Parameters for a single sparse bind operation on parts of an image with a known memory layout.
1447///
1448/// This type of sparse bind can only be used for images that have the `SPARSE_RESIDENCY` flag set.
1449/// Only the normal texel regions can be bound this way, not the mip tail regions or metadata
1450/// aspect.
1451#[derive(Clone, Debug)]
1452pub struct SparseImageMemoryBind {
1453    /// The aspects of the image where memory is to be (un)bound.
1454    ///
1455    /// The default value is `ImageAspects::empty()`, which must be overridden.
1456    pub aspects: ImageAspects,
1457
1458    /// The mip level of the image where memory is to be (un)bound.
1459    ///
1460    /// The default value is `0`.
1461    pub mip_level: u32,
1462
1463    /// The array layer of the image where memory is to be (un)bound.
1464    ///
1465    /// The default value is `0`.
1466    pub array_layer: u32,
1467
1468    /// The offset in texels (or for compressed images, texel blocks) from the origin of the image,
1469    /// where memory is to be (un)bound.
1470    ///
1471    /// This must be a multiple of the
1472    /// [`SparseImageFormatProperties::image_granularity`](crate::image::SparseImageFormatProperties::image_granularity)
1473    /// value of the image.
1474    ///
1475    /// The default value is `[0; 3]`.
1476    pub offset: [u32; 3],
1477
1478    /// The extent in texels (or for compressed images, texel blocks) of the image where
1479    /// memory is to be (un)bound.
1480    ///
1481    /// This must be a multiple of the
1482    /// [`SparseImageFormatProperties::image_granularity`](crate::image::SparseImageFormatProperties::image_granularity)
1483    /// value of the image, or `offset + extent` for that dimension must equal the image's total
1484    /// extent.
1485    ///
1486    /// The default value is `[0; 3]`, which must be overridden.
1487    pub extent: [u32; 3],
1488
1489    /// If `Some`, specifies the memory and an offset into that memory that is to be bound.
1490    /// The provided memory must match the image's memory requirements.
1491    ///
1492    /// If `None`, specifies that existing memory at the specified location is to be unbound.
1493    ///
1494    /// The default value is `None`.
1495    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                    // vuids?
1545                    ..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        // VUID-VkSparseImageMemoryBind-memory-01104
1578        // If the sparseResidencyAliased feature is not enabled, and if any other resources are
1579        // bound to ranges of memory, the range of memory being bound must not overlap with
1580        // those bound ranges
1581
1582        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}