1use super::*;
6
7#[derive(Clone, Copy)]
9pub struct CacheRange<'a> {
10 pub allocation: &'a Allocation,
11 pub offset: u64,
12 pub size: u64,
13}
14
15impl<'a> CacheRange<'a> {
16 #[inline]
18 #[must_use]
19 pub fn new(allocation: &'a Allocation) -> Self {
20 Self {
21 allocation,
22 offset: 0,
23 size: vk::WHOLE_SIZE,
24 }
25 }
26
27 #[inline]
29 #[must_use]
30 pub fn set_allocation(mut self, value: &'a Allocation) -> Self {
31 self.allocation = value;
32 self
33 }
34
35 #[inline]
37 #[must_use]
38 pub fn set_offset(mut self, value: u64) -> Self {
39 self.offset = value;
40 self
41 }
42
43 #[inline]
45 #[must_use]
46 pub fn set_size(mut self, value: u64) -> Self {
47 self.size = value;
48 self
49 }
50}
51
52pub unsafe fn allocate_many(
61 allocator: &mut Allocator<'_>,
62 requirements: &vk::MemoryRequirements,
63 options: &AllocationCreateInfo,
64 count: usize,
65) -> Result<Vec<Allocation>, AllocError> {
66 if count > 1
67 && options
68 .memory_allocate_next
69 .is_some_and(|chain| chain.data.imports)
70 {
71 return Err(AllocError::InvalidRequest(
72 "one imported handle cannot back multiple allocations",
73 ));
74 }
75 allocator.ensure_open()?;
76 allocator
77 .next_serial
78 .checked_add(u64::try_from(count).map_err(|_| AllocError::SerialExhausted)?)
79 .ok_or(AllocError::SerialExhausted)?;
80 let mut allocations = Vec::new();
81 allocations
82 .try_reserve_exact(count)
83 .map_err(|_| AllocError::HostAllocationFailed)?;
84 for _ in 0..count {
85 match unsafe { allocate_with_options(allocator, requirements, options) } {
87 Ok(allocation) => allocations.push(allocation),
88 Err(error) => {
89 for allocation in allocations.iter_mut().rev() {
90 unsafe { rollback_allocation(allocator, allocation) }.expect("unpublished page rollback");
92 }
93 return Err(error);
94 }
95 }
96 }
97 Ok(allocations)
98}
99
100pub unsafe fn free_many(
109 allocator: &mut Allocator<'_>,
110 allocations: &mut [Allocation],
111) -> Result<(), AllocError> {
112 allocator.ensure_open()?;
113 for (index, allocation) in allocations.iter().enumerate() {
114 if allocator.validate(allocation)?.map_count != 0 {
115 return Err(AllocError::AlreadyMapped);
116 }
117 if allocations[..index]
118 .iter()
119 .any(|previous| previous.serial == allocation.serial)
120 {
121 return Err(AllocError::InvalidRequest(
122 "duplicate allocation in release batch",
123 ));
124 }
125 }
126 for allocation in allocations {
127 unsafe { free(allocator, allocation) }?;
129 }
130 Ok(())
131}
132
133fn cache_ranges<'device>(
134 allocator: &Allocator<'device>,
135 ranges: &[CacheRange<'_>],
136) -> Result<HostVec<'device, vk::MappedMemoryRange<'static>>, AllocError> {
137 allocator.ensure_open()?;
138 let mut native = HostVec::new(allocator.host);
139 native
140 .try_reserve_exact(ranges.len())
141 .map_err(|_| AllocError::HostAllocationFailed)?;
142 for range in ranges {
143 let live = allocator.validate(range.allocation)?;
144 if live.map_count == 0 && !live.persistent {
145 return Err(AllocError::NotMapped);
146 }
147 if let Some(range) = range.allocation.mapped_range(range.offset, range.size)? {
148 native.push_reserved(range);
149 }
150 }
151 u32::try_from(native.len()).map_err(|_| AllocError::InvalidRange)?;
152 Ok(native)
153}
154
155pub unsafe fn flush_many(
161 allocator: &Allocator<'_>,
162 ranges: &[CacheRange<'_>],
163) -> Result<(), AllocError> {
164 let native = cache_ranges(allocator, ranges)?;
165 if !native.is_empty() {
166 unsafe { allocator.device.flush_mapped_memory_ranges(&native) }?;
168 }
169 Ok(())
170}
171
172pub unsafe fn invalidate_many(
178 allocator: &Allocator<'_>,
179 ranges: &[CacheRange<'_>],
180) -> Result<(), AllocError> {
181 let native = cache_ranges(allocator, ranges)?;
182 if !native.is_empty() {
183 unsafe { allocator.device.invalidate_mapped_memory_ranges(&native) }?;
185 }
186 Ok(())
187}
188
189fn copy_range(
190 allocator: &Allocator<'_>,
191 allocation: &Allocation,
192 offset: u64,
193 length: usize,
194 write: bool,
195) -> Result<u64, AllocError> {
196 allocator.validate(allocation)?;
197 let size = u64::try_from(length).map_err(|_| AllocError::InvalidRange)?;
198 if offset
199 .checked_add(size)
200 .is_none_or(|end| end > allocation.size)
201 {
202 return Err(AllocError::InvalidRange);
203 }
204 if size != 0 && allocation.mapped_range(offset, size)?.is_some() {
205 if write {
206 require(
207 allocator.device.fp().flush_mapped_memory_ranges.is_some(),
208 "vkFlushMappedMemoryRanges",
209 )?;
210 } else {
211 require(
212 allocator
213 .device
214 .as_device()
215 .fp()
216 .invalidate_mapped_memory_ranges
217 .is_some(),
218 "vkInvalidateMappedMemoryRanges",
219 )?;
220 }
221 }
222 Ok(size)
223}
224
225pub unsafe fn copy_to_allocation(
236 allocator: &mut Allocator<'_>,
237 allocation: &Allocation,
238 offset: u64,
239 source: &[u8],
240) -> Result<(), AllocError> {
241 let size = copy_range(allocator, allocation, offset, source.len(), true)?;
242 if size == 0 {
243 return Ok(());
244 }
245 let pointer_offset = usize::try_from(offset).map_err(|_| AllocError::InvalidRange)?;
246 let pointer = unsafe { map(allocator, allocation) }?;
248 unsafe {
250 std::ptr::copy(
251 source.as_ptr(),
252 pointer.cast::<u8>().add(pointer_offset),
253 source.len(),
254 )
255 };
256 let result = unsafe { flush(allocator, allocation, offset, size) };
258 let cleanup = unsafe { unmap(allocator, allocation) };
260 result.and(cleanup)
261}
262
263pub unsafe fn copy_from_allocation(
270 allocator: &mut Allocator<'_>,
271 allocation: &Allocation,
272 offset: u64,
273 destination: &mut [u8],
274) -> Result<(), AllocError> {
275 let size = copy_range(allocator, allocation, offset, destination.len(), false)?;
276 if size == 0 {
277 return Ok(());
278 }
279 let pointer_offset = usize::try_from(offset).map_err(|_| AllocError::InvalidRange)?;
280 let pointer = unsafe { map(allocator, allocation) }?;
282 let result = unsafe { invalidate(allocator, allocation, offset, size) };
284 if result.is_ok() {
285 unsafe {
287 std::ptr::copy(
288 pointer.cast::<u8>().add(pointer_offset),
289 destination.as_mut_ptr(),
290 destination.len(),
291 )
292 };
293 }
294 let cleanup = unsafe { unmap(allocator, allocation) };
296 result.and(cleanup)
297}
298
299fn name_copy<'callbacks>(
300 host: HostMemory<'callbacks>,
301 name: Option<&str>,
302) -> Result<Option<HostString<'callbacks>>, AllocError> {
303 name
304 .map(|name| HostString::new_from_str(host, name))
305 .transpose()
306}
307
308pub fn allocation_name<'a>(
310 allocator: &'a Allocator<'_>,
311 allocation: &Allocation,
312) -> Result<Option<&'a str>, AllocError> {
313 Ok(allocator.validate(allocation)?.name.as_deref())
314}
315
316pub fn set_allocation_name(
320 allocator: &mut Allocator<'_>,
321 allocation: &Allocation,
322 name: Option<&str>,
323) -> Result<(), AllocError> {
324 allocator.validate(allocation)?;
325 let name = name_copy(allocator.host, name)?;
326 allocator
327 .live
328 .get_mut(&allocation.serial)
329 .expect("validated allocation")
330 .name = name;
331 Ok(())
332}
333
334pub fn set_allocation_user_data(
336 allocator: &mut Allocator<'_>,
337 allocation: &Allocation,
338 data: usize,
339) -> Result<(), AllocError> {
340 allocator.validate(allocation)?;
341 allocator
342 .live
343 .get_mut(&allocation.serial)
344 .expect("validated allocation")
345 .user_data = data;
346 Ok(())
347}
348
349pub fn pool_name<'a>(
351 allocator: &'a Allocator<'_>,
352 pool: &Pool,
353) -> Result<Option<&'a str>, AllocError> {
354 Ok(pool::validate(allocator, pool)?.name.as_deref())
355}
356
357pub fn set_pool_name(
359 allocator: &mut Allocator<'_>,
360 pool: &Pool,
361 name: Option<&str>,
362) -> Result<(), AllocError> {
363 pool::validate(allocator, pool)?;
364 let name = name_copy(allocator.host, name)?;
365 allocator
366 .pools
367 .get_mut(&pool.serial)
368 .expect("validated pool")
369 .name = name;
370 Ok(())
371}
372
373#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
375pub struct DetailedStatistics {
376 pub native_count: usize,
377 pub native_bytes: u64,
378 pub allocation_count: usize,
379 pub allocation_bytes: u64,
380 pub reserved_bytes: u64,
381 pub free_range_count: usize,
382 pub free_bytes: u64,
383 pub allocation_size_min: Option<u64>,
384 pub allocation_size_max: Option<u64>,
385 pub free_range_size_min: Option<u64>,
386 pub free_range_size_max: Option<u64>,
387}
388
389#[derive(Clone, Debug, Default, PartialEq, Eq)]
391pub struct MemoryStatistics {
392 pub total: DetailedStatistics,
393 pub memory_types: [DetailedStatistics; 32],
394 pub heaps: [DetailedStatistics; 16],
395}
396
397impl MemoryStatistics {
398 #[inline]
400 #[must_use]
401 pub fn new() -> Self {
402 Self::default()
403 }
404
405 #[inline]
407 #[must_use]
408 pub fn set_total(mut self, value: DetailedStatistics) -> Self {
409 self.total = value;
410 self
411 }
412
413 #[inline]
415 #[must_use]
416 pub fn set_memory_types(mut self, value: [DetailedStatistics; 32]) -> Self {
417 self.memory_types = value;
418 self
419 }
420
421 #[inline]
423 #[must_use]
424 pub fn set_heaps(mut self, value: [DetailedStatistics; 16]) -> Self {
425 self.heaps = value;
426 self
427 }
428}
429
430impl DetailedStatistics {
431 #[inline]
433 #[must_use]
434 pub fn new() -> Self {
435 Self::default()
436 }
437
438 #[inline]
440 #[must_use]
441 pub fn set_native_count(mut self, value: usize) -> Self {
442 self.native_count = value;
443 self
444 }
445
446 #[inline]
448 #[must_use]
449 pub fn set_native_bytes(mut self, value: u64) -> Self {
450 self.native_bytes = value;
451 self
452 }
453
454 #[inline]
456 #[must_use]
457 pub fn set_allocation_count(mut self, value: usize) -> Self {
458 self.allocation_count = value;
459 self
460 }
461
462 #[inline]
464 #[must_use]
465 pub fn set_allocation_bytes(mut self, value: u64) -> Self {
466 self.allocation_bytes = value;
467 self
468 }
469
470 #[inline]
472 #[must_use]
473 pub fn set_reserved_bytes(mut self, value: u64) -> Self {
474 self.reserved_bytes = value;
475 self
476 }
477
478 #[inline]
480 #[must_use]
481 pub fn set_free_range_count(mut self, value: usize) -> Self {
482 self.free_range_count = value;
483 self
484 }
485
486 #[inline]
488 #[must_use]
489 pub fn set_free_bytes(mut self, value: u64) -> Self {
490 self.free_bytes = value;
491 self
492 }
493
494 #[inline]
496 #[must_use]
497 pub fn set_allocation_size_min(mut self, value: Option<u64>) -> Self {
498 self.allocation_size_min = value;
499 self
500 }
501
502 #[inline]
504 #[must_use]
505 pub fn set_allocation_size_max(mut self, value: Option<u64>) -> Self {
506 self.allocation_size_max = value;
507 self
508 }
509
510 #[inline]
512 #[must_use]
513 pub fn set_free_range_size_min(mut self, value: Option<u64>) -> Self {
514 self.free_range_size_min = value;
515 self
516 }
517
518 #[inline]
520 #[must_use]
521 pub fn set_free_range_size_max(mut self, value: Option<u64>) -> Self {
522 self.free_range_size_max = value;
523 self
524 }
525
526 fn include(&mut self, other: Self) {
527 self.native_count += other.native_count;
528 self.native_bytes += other.native_bytes;
529 self.allocation_count += other.allocation_count;
530 self.allocation_bytes += other.allocation_bytes;
531 self.reserved_bytes += other.reserved_bytes;
532 self.free_range_count += other.free_range_count;
533 self.free_bytes += other.free_bytes;
534 for (target, value, minimum) in [
535 (
536 &mut self.allocation_size_min,
537 other.allocation_size_min,
538 true,
539 ),
540 (
541 &mut self.allocation_size_max,
542 other.allocation_size_max,
543 false,
544 ),
545 (
546 &mut self.free_range_size_min,
547 other.free_range_size_min,
548 true,
549 ),
550 (
551 &mut self.free_range_size_max,
552 other.free_range_size_max,
553 false,
554 ),
555 ] {
556 if let Some(value) = value {
557 *target = Some(target.map_or(value, |old| {
558 if minimum {
559 old.min(value)
560 } else {
561 old.max(value)
562 }
563 }));
564 }
565 }
566 }
567}
568
569pub fn detailed_statistics(allocator: &Allocator<'_>) -> Result<MemoryStatistics, AllocError> {
577 collect_statistics(allocator, None)
578}
579
580pub fn detailed_pool_statistics(
582 allocator: &Allocator<'_>,
583 pool: &Pool,
584) -> Result<DetailedStatistics, AllocError> {
585 pool::validate(allocator, pool)?;
586 Ok(collect_statistics(allocator, Some(pool.serial))?.total)
587}
588
589fn collect_statistics(
590 allocator: &Allocator<'_>,
591 pool_filter: Option<u64>,
592) -> Result<MemoryStatistics, AllocError> {
593 allocator.ensure_open()?;
594 let mut result = MemoryStatistics::new();
595 for block in &allocator.blocks {
596 if pool_filter.is_some() && block.pool != pool_filter {
597 continue;
598 }
599 let stats = &mut result.memory_types[block.memory_type_index as usize];
600 stats.native_count += 1;
601 stats.native_bytes += block.size;
602 block.metadata.for_each_free(|_, size| {
603 stats.free_range_count += 1;
604 stats.free_bytes += size;
605 stats.free_range_size_min = Some(stats.free_range_size_min.map_or(size, |old| old.min(size)));
606 stats.free_range_size_max = Some(stats.free_range_size_max.map_or(size, |old| old.max(size)));
607 });
608 }
609 for live in allocator.live.values() {
610 if pool_filter.is_some() && live.pool != pool_filter {
611 continue;
612 }
613 let stats = &mut result.memory_types[live.memory_type_index as usize];
614 if live.placement.is_none() {
615 stats.native_count += 1;
616 stats.native_bytes += live.size;
617 }
618 stats.allocation_count += 1;
619 stats.allocation_bytes += live.size;
620 stats.reserved_bytes += live.reserved_size;
621 stats.allocation_size_min = Some(
622 stats
623 .allocation_size_min
624 .map_or(live.size, |old| old.min(live.size)),
625 );
626 stats.allocation_size_max = Some(
627 stats
628 .allocation_size_max
629 .map_or(live.size, |old| old.max(live.size)),
630 );
631 }
632 for index in 0..allocator.selector.properties.memory_type_count as usize {
633 let stats = result.memory_types[index];
634 result.total.include(stats);
635 result.heaps[allocator.selector.properties.memory_types[index].heap_index as usize]
636 .include(stats);
637 }
638 Ok(result)
639}
640
641pub fn write_statistics_json(
649 allocator: &Allocator<'_>,
650 output: &mut impl std::io::Write,
651 detailed: bool,
652) -> Result<(), AllocError> {
653 let stats = detailed_statistics(allocator)?;
654 let mut allocations = HostVec::new(allocator.host);
655 if detailed {
656 allocations
657 .try_reserve_exact(allocator.live.len())
658 .map_err(|_| AllocError::HostAllocationFailed)?;
659 for entry in allocator.live.iter() {
660 allocations.push_reserved(entry);
661 }
662 allocations.sort_unstable_by_key(|(serial, _)| **serial);
663 }
664 let mut pools = HostVec::new(allocator.host);
665 pools
666 .try_reserve_exact(allocator.pools.len())
667 .map_err(|_| AllocError::HostAllocationFailed)?;
668 for entry in allocator.pools.iter() {
669 pools.push_reserved(entry);
670 }
671 pools.sort_unstable_by_key(|(serial, _)| **serial);
672 fn quote(out: &mut impl std::io::Write, text: &str) -> std::io::Result<()> {
673 out.write_all(b"\"")?;
674 for value in text.chars() {
675 match value {
676 '"' => out.write_all(b"\\\"")?,
677 '\\' => out.write_all(b"\\\\")?,
678 value if value <= '\u{1f}' => write!(out, "\\u{:04x}", u32::from(value))?,
679 value => {
680 let mut bytes = [0; 4];
681 out.write_all(value.encode_utf8(&mut bytes).as_bytes())?;
682 }
683 }
684 }
685 out.write_all(b"\"")
686 }
687 fn number(out: &mut impl std::io::Write, value: Option<u64>) -> std::io::Result<()> {
688 if let Some(value) = value {
689 write!(out, "{value}")
690 } else {
691 out.write_all(b"null")
692 }
693 }
694 fn statistics(out: &mut impl std::io::Write, stats: &DetailedStatistics) -> std::io::Result<()> {
695 write!(
696 out,
697 "{{\"native_count\":{},\"native_bytes\":{},\"allocation_count\":{},\"allocation_bytes\":{},\"reserved_bytes\":{},\"free_range_count\":{},\"free_bytes\":{},\"allocation_size_min\":",
698 stats.native_count,
699 stats.native_bytes,
700 stats.allocation_count,
701 stats.allocation_bytes,
702 stats.reserved_bytes,
703 stats.free_range_count,
704 stats.free_bytes
705 )?;
706 number(out, stats.allocation_size_min)?;
707 out.write_all(b",\"allocation_size_max\":")?;
708 number(out, stats.allocation_size_max)?;
709 out.write_all(b",\"free_range_size_min\":")?;
710 number(out, stats.free_range_size_min)?;
711 out.write_all(b",\"free_range_size_max\":")?;
712 number(out, stats.free_range_size_max)?;
713 out.write_all(b"}")
714 }
715 let written = (|| -> std::io::Result<()> {
716 output.write_all(b"{\"schema\":\"vk.memory.statistics.v1\",\"total\":")?;
717 statistics(output, &stats.total)?;
718 output.write_all(b",\"memory_types\":[")?;
719 for index in 0..allocator.selector.properties.memory_type_count as usize {
720 if index != 0 {
721 output.write_all(b",")?;
722 }
723 statistics(output, &stats.memory_types[index])?;
724 }
725 output.write_all(b"],\"heaps\":[")?;
726 for index in 0..allocator.selector.properties.memory_heap_count as usize {
727 if index != 0 {
728 output.write_all(b",")?;
729 }
730 statistics(output, &stats.heaps[index])?;
731 }
732 output.write_all(b"],\"pools\":[")?;
733 for (index, (serial, pool)) in pools.iter().enumerate() {
734 if index != 0 {
735 output.write_all(b",")?;
736 }
737 write!(
738 output,
739 "{{\"id\":{serial},\"memory_type\":{},\"name\":",
740 pool.info.memory_type_index
741 )?;
742 if let Some(name) = &pool.name {
743 quote(output, name)?;
744 } else {
745 output.write_all(b"null")?;
746 }
747 output.write_all(b"}")?;
748 }
749 output.write_all(b"]")?;
750 if detailed {
751 output.write_all(b",\"allocations\":[")?;
752 for (index, (serial, live)) in allocations.iter().enumerate() {
753 if index != 0 {
754 output.write_all(b",")?;
755 }
756 write!(
757 output,
758 "{{\"id\":{serial},\"offset\":{},\"size\":{},\"reserved_size\":{},\"memory_type\":{},\"user_data\":{},\"map_count\":{},\"persistent\":{},\"pinned\":{},\"name\":",
759 live.offset,
760 live.size,
761 live.reserved_size,
762 live.memory_type_index,
763 live.user_data,
764 live.map_count,
765 live.persistent,
766 live.pinned
767 )?;
768 if let Some(name) = &live.name {
769 quote(output, name)?;
770 } else {
771 output.write_all(b"null")?;
772 }
773 output.write_all(b"}")?;
774 }
775 output.write_all(b"],\"blocks\":[")?;
776 for (index, block) in allocator.blocks.iter().enumerate() {
777 if index != 0 {
778 output.write_all(b",")?;
779 }
780 write!(
781 output,
782 "{{\"memory_type\":{},\"size\":{},\"free_ranges\":[",
783 block.memory_type_index, block.size
784 )?;
785 let mut first = true;
786 let mut error = None;
787 block.metadata.for_each_free(|offset, size| {
788 if error.is_some() {
789 return;
790 }
791 let result = (|| {
792 if !first {
793 output.write_all(b",")?;
794 }
795 first = false;
796 write!(output, "[{offset},{size}]")
797 })();
798 if let Err(failure) = result {
799 error = Some(failure);
800 }
801 });
802 if let Some(error) = error {
803 return Err(error);
804 }
805 output.write_all(b"]}")?;
806 }
807 output.write_all(b"]")?;
808 }
809 output.write_all(b"}\n")
810 })();
811 written.map_err(|error| AllocError::Output {
812 kind: error.kind(),
813 code: error.raw_os_error(),
814 })
815}
816
817impl Allocator<'_> {
818 pub fn detailed_pool_statistics(&self, pool: &Pool) -> Result<DetailedStatistics, AllocError> {
820 detailed_pool_statistics(self, pool)
821 }
822
823 pub fn write_statistics_json(
825 &self,
826 output: &mut impl std::io::Write,
827 detailed: bool,
828 ) -> Result<(), AllocError> {
829 write_statistics_json(self, output, detailed)
830 }
831
832 pub fn detailed_statistics(&self) -> Result<MemoryStatistics, AllocError> {
834 detailed_statistics(self)
835 }
836
837 pub unsafe fn allocate_many(
841 &mut self,
842 requirements: &vk::MemoryRequirements,
843 options: &AllocationCreateInfo,
844 count: usize,
845 ) -> Result<Vec<Allocation>, AllocError> {
846 unsafe { allocate_many(self, requirements, options, count) }
848 }
849
850 pub unsafe fn free_many(&mut self, allocations: &mut [Allocation]) -> Result<(), AllocError> {
854 unsafe { free_many(self, allocations) }
856 }
857
858 pub unsafe fn flush_many(&self, ranges: &[CacheRange<'_>]) -> Result<(), AllocError> {
862 unsafe { flush_many(self, ranges) }
864 }
865
866 pub unsafe fn invalidate_many(&self, ranges: &[CacheRange<'_>]) -> Result<(), AllocError> {
870 unsafe { invalidate_many(self, ranges) }
872 }
873
874 pub unsafe fn copy_to_allocation(
878 &mut self,
879 allocation: &Allocation,
880 offset: u64,
881 source: &[u8],
882 ) -> Result<(), AllocError> {
883 unsafe { copy_to_allocation(self, allocation, offset, source) }
885 }
886
887 pub unsafe fn copy_from_allocation(
891 &mut self,
892 allocation: &Allocation,
893 offset: u64,
894 destination: &mut [u8],
895 ) -> Result<(), AllocError> {
896 unsafe { copy_from_allocation(self, allocation, offset, destination) }
898 }
899
900 pub fn allocation_name<'a>(
902 &'a self,
903 allocation: &Allocation,
904 ) -> Result<Option<&'a str>, AllocError> {
905 allocation_name(self, allocation)
906 }
907
908 pub fn set_allocation_name(
910 &mut self,
911 allocation: &Allocation,
912 name: Option<&str>,
913 ) -> Result<(), AllocError> {
914 set_allocation_name(self, allocation, name)
915 }
916
917 pub fn set_allocation_user_data(
919 &mut self,
920 allocation: &Allocation,
921 data: usize,
922 ) -> Result<(), AllocError> {
923 set_allocation_user_data(self, allocation, data)
924 }
925
926 pub fn pool_name<'a>(&'a self, pool: &Pool) -> Result<Option<&'a str>, AllocError> {
928 pool_name(self, pool)
929 }
930
931 pub fn set_pool_name(&mut self, pool: &Pool, name: Option<&str>) -> Result<(), AllocError> {
933 set_pool_name(self, pool, name)
934 }
935}
936
937pub unsafe fn create_aliasing_buffer(
950 allocator: &mut Allocator<'_>,
951 allocation: &Allocation,
952 local_offset: u64,
953 info: &vk::BufferCreateInfo,
954) -> Result<vk::Buffer, AllocError> {
955 if !allocator.validate(allocation)?.can_alias {
956 return Err(AllocError::UnsupportedCapability(
957 "allocation was not created for aliasing",
958 ));
959 }
960 unsafe { request::validate_buffer(allocator, info) }?;
962 let required_exports = unsafe { external::required_resource_types(info.p_next) };
964 if !allocator.validate(allocation)?.imported
965 && external::exports(allocator, allocation)?.as_raw() & required_exports.as_raw()
966 != required_exports.as_raw()
967 {
968 return Err(AllocError::InvalidRequest(
969 "alias resource export types do not match backing memory",
970 ));
971 }
972 require(
973 allocator.device.fp().create_buffer.is_some(),
974 "vkCreateBuffer",
975 )?;
976 require(
977 allocator.device.fp().destroy_buffer.is_some(),
978 "vkDestroyBuffer",
979 )?;
980 let buffer = unsafe { allocator.device.create_buffer(info, allocator.callbacks) }?;
982 if buffer.is_null() || binding::associated(allocator, Resource::Buffer(buffer)) {
983 return Err(CallError::InvalidOutput("alias buffer is null or already live").into());
984 }
985 if let Err(error) = unsafe {
987 binding::bind_alias(
988 allocator,
989 Resource::Buffer(buffer),
990 allocation,
991 local_offset,
992 )
993 } {
994 unsafe { allocator.device.destroy_buffer(buffer, allocator.callbacks) }
996 .expect("preflighted alias cleanup");
997 return Err(error);
998 }
999 Ok(buffer)
1000}
1001
1002pub unsafe fn create_aliasing_image(
1010 allocator: &mut Allocator<'_>,
1011 allocation: &Allocation,
1012 local_offset: u64,
1013 info: &vk::ImageCreateInfo,
1014) -> Result<vk::Image, AllocError> {
1015 if !allocator.validate(allocation)?.can_alias {
1016 return Err(AllocError::UnsupportedCapability(
1017 "allocation was not created for aliasing",
1018 ));
1019 }
1020 if info.flags.as_raw() & vk::ImageCreateFlagBits::ALIAS_BIT.as_raw() == 0 {
1021 return Err(AllocError::InvalidRequest("alias images require ALIAS_BIT"));
1022 }
1023 unsafe { request::validate_image(allocator, info) }?;
1025 let required_exports = unsafe { external::required_resource_types(info.p_next) };
1027 if !allocator.validate(allocation)?.imported
1028 && external::exports(allocator, allocation)?.as_raw() & required_exports.as_raw()
1029 != required_exports.as_raw()
1030 {
1031 return Err(AllocError::InvalidRequest(
1032 "alias resource export types do not match backing memory",
1033 ));
1034 }
1035 require(
1036 allocator.device.fp().create_image.is_some(),
1037 "vkCreateImage",
1038 )?;
1039 require(
1040 allocator.device.fp().destroy_image.is_some(),
1041 "vkDestroyImage",
1042 )?;
1043 let image = unsafe { allocator.device.create_image(info, allocator.callbacks) }?;
1045 if image.is_null() || binding::associated(allocator, Resource::Image(image)) {
1046 return Err(CallError::InvalidOutput("alias image is null or already live").into());
1047 }
1048 if let Err(error) =
1050 unsafe { binding::bind_alias(allocator, Resource::Image(image), allocation, local_offset) }
1051 {
1052 unsafe { allocator.device.destroy_image(image, allocator.callbacks) }
1054 .expect("preflighted alias cleanup");
1055 return Err(error);
1056 }
1057 Ok(image)
1058}
1059
1060impl Allocator<'_> {
1061 pub fn allocation_callbacks(&self) -> Option<&vk::AllocationCallbacks> {
1063 self.callbacks
1064 }
1065
1066 pub unsafe fn create_aliasing_buffer(
1070 &mut self,
1071 allocation: &Allocation,
1072 local_offset: u64,
1073 info: &vk::BufferCreateInfo,
1074 ) -> Result<vk::Buffer, AllocError> {
1075 unsafe { create_aliasing_buffer(self, allocation, local_offset, info) }
1077 }
1078
1079 pub unsafe fn create_aliasing_image(
1083 &mut self,
1084 allocation: &Allocation,
1085 local_offset: u64,
1086 info: &vk::ImageCreateInfo,
1087 ) -> Result<vk::Image, AllocError> {
1088 unsafe { create_aliasing_image(self, allocation, local_offset, info) }
1090 }
1091}
1092
1093pub fn allocator_info(
1095 allocator: &Allocator<'_>,
1096) -> Result<super::super::AllocatorInfo, AllocError> {
1097 allocator.ensure_open()?;
1098 Ok(super::super::AllocatorInfo {
1099 device: allocator.device.handle(),
1100 instance: allocator.instance_handle,
1101 physical_device: allocator.physical_device,
1102 api_version: allocator
1103 .device
1104 .as_device()
1105 .capabilities()
1106 .map(|caps| caps.api_version()),
1107 })
1108}
1109
1110pub fn memory_properties<'a>(
1112 allocator: &'a Allocator<'_>,
1113) -> Result<&'a vk::PhysicalDeviceMemoryProperties, AllocError> {
1114 allocator.ensure_open()?;
1115 Ok(&allocator.selector.properties)
1116}
1117
1118pub fn physical_device_properties<'a>(
1120 allocator: &'a Allocator<'_>,
1121) -> Result<Option<&'a vk::PhysicalDeviceProperties>, AllocError> {
1122 allocator.ensure_open()?;
1123 Ok(allocator.physical_properties.as_ref())
1124}
1125
1126pub fn memory_type_properties(
1128 allocator: &Allocator<'_>,
1129 index: u32,
1130) -> Result<vk::MemoryPropertyFlags, AllocError> {
1131 allocator.ensure_open()?;
1132 if index >= allocator.selector.properties.memory_type_count {
1133 return Err(AllocError::InvalidRequest("absent memory type"));
1134 }
1135 Ok(allocator.selector.properties.memory_types[index as usize].property_flags)
1136}
1137
1138impl<'device> Allocator<'device> {
1139 pub unsafe fn set_device_memory_callbacks(
1146 &mut self,
1147 callbacks: Option<&'device super::super::DeviceMemoryCallbacks>,
1148 ) -> Result<(), AllocError> {
1149 self.ensure_open()?;
1150 self.ensure_global()?;
1151 if self.native_count != 0 || !self.live.is_empty() {
1152 return Err(AllocError::LiveAllocations);
1153 }
1154 if !self.pools.is_empty() {
1155 return Err(AllocError::LivePools);
1156 }
1157 self.device_memory_callbacks = callbacks;
1158 Ok(())
1159 }
1160
1161 pub fn info(&self) -> Result<super::super::AllocatorInfo, AllocError> {
1163 allocator_info(self)
1164 }
1165
1166 pub fn memory_properties(&self) -> Result<&vk::PhysicalDeviceMemoryProperties, AllocError> {
1168 memory_properties(self)
1169 }
1170
1171 pub fn physical_device_properties(
1173 &self,
1174 ) -> Result<Option<&vk::PhysicalDeviceProperties>, AllocError> {
1175 physical_device_properties(self)
1176 }
1177
1178 pub fn memory_type_properties(&self, index: u32) -> Result<vk::MemoryPropertyFlags, AllocError> {
1180 memory_type_properties(self, index)
1181 }
1182}