1use super::{
9 AllocError, AllocRequest, Allocation, AllocationCreateInfo, AllocationPolicy, AllocatorStats,
10 MemoryTypeSelector,
11 block::{Block, Mapping},
12 tlsf::Tlsf,
13};
14use crate::{core as vk, core::Device, load::CallError};
15use std::{collections::HashMap, sync::Arc};
16
17struct Live {
18 serial: u64,
19 handle: vk::DeviceMemory,
20 size: u64,
21 reserved_size: u64,
22 mapped: bool,
23 persistent: bool,
24 buffer: Option<vk::Buffer>,
25 placement: Option<(usize, u64)>,
26 mapping: Mapping,
27}
28
29#[derive(Clone, Copy)]
30enum RequirementsRoute {
31 Legacy,
32 Core,
33 Khr,
34}
35
36pub struct Allocator<'device> {
41 device: &'device Device,
42 selector: MemoryTypeSelector,
43 owner: Arc<()>,
44 next_serial: u64,
45 live: HashMap<u64, Live>,
46 blocks: Vec<Block>,
47 native_count: usize,
48 native_bytes: u64,
49 heap_bytes: [u64; 16],
50 allocation_limit: u32,
51 allocation_size_limit: Option<u64>,
52 closed: bool,
53}
54
55impl<'device> Allocator<'device> {
56 pub unsafe fn new(
67 device: &'device Device,
68 properties: vk::PhysicalDeviceMemoryProperties,
69 atom: u64,
70 ) -> Result<Self, AllocError> {
71 let selector = MemoryTypeSelector::new(properties, atom)?;
72 require(device.fp().allocate_memory.is_some(), "vkAllocateMemory")?;
73 require(device.fp().free_memory.is_some(), "vkFreeMemory")?;
74 Ok(Self {
75 device,
76 selector,
77 owner: Arc::new(()),
78 next_serial: 1,
79 live: HashMap::new(),
80 blocks: Vec::new(),
81 native_count: 0,
82 native_bytes: 0,
83 heap_bytes: [0; 16],
84 allocation_limit: u32::MAX,
85 allocation_size_limit: None,
86 closed: false,
87 })
88 }
89
90 pub unsafe fn new_from_physical_device(
104 instance: &vk::Instance,
105 physical_device: vk::PhysicalDevice,
106 device: &'device Device,
107 ) -> Result<Self, AllocError> {
108 let parent = instance
109 .capabilities()
110 .ok_or(AllocError::UnsupportedCapability(
111 "instance creation metadata is required",
112 ))?;
113 let capabilities = device
114 .capabilities()
115 .ok_or(AllocError::UnsupportedCapability(
116 "device creation metadata is required",
117 ))?;
118 if !capabilities.matches_instance(parent) {
119 return Err(AllocError::InvalidProperties(
120 "device/instance metadata disagree",
121 ));
122 }
123 if physical_device.is_null() {
124 return Err(AllocError::InvalidProperties("null physical device"));
125 }
126 let properties = unsafe { instance.get_physical_device_properties(physical_device) }?;
128 let maintenance3 = capabilities
131 .device_extensions()
132 .is_some_and(|mut extensions| extensions.any(|name| name == c"VK_KHR_maintenance3"));
133 let allocation_size_limit = if capabilities.api_version() >= vk::API_VERSION_1_1 || maintenance3
134 {
135 let mut limits = vk::PhysicalDeviceMaintenance3Properties::default();
136 let mut output = vk::PhysicalDeviceProperties2 {
137 p_next: std::ptr::from_mut(&mut limits).cast(),
138 ..Default::default()
139 };
140 if parent.instance_api_version() >= vk::API_VERSION_1_1 {
141 unsafe { instance.get_physical_device_properties2(physical_device, &mut output) }?;
143 } else if parent
144 .instance_extensions()
145 .any(|name| name == c"VK_KHR_get_physical_device_properties2")
146 {
147 unsafe { instance.get_physical_device_properties2_khr(physical_device, &mut output) }?;
150 } else {
151 return Err(AllocError::UnsupportedCapability(
152 "maintenance3 requires properties2",
153 ));
154 }
155 if limits.max_memory_allocation_size == 0 {
156 return Err(AllocError::InvalidProperties(
157 "zero native allocation-size limit",
158 ));
159 }
160 Some(limits.max_memory_allocation_size)
161 } else {
162 None
163 };
164 let memory = unsafe { instance.get_physical_device_memory_properties(physical_device) }?;
166 if properties.limits.max_memory_allocation_count == 0 {
167 return Err(AllocError::InvalidProperties(
168 "zero native allocation limit",
169 ));
170 }
171 let mut allocator =
173 unsafe { Self::new(device, memory, properties.limits.non_coherent_atom_size) }?;
174 allocator.allocation_limit = properties.limits.max_memory_allocation_count;
175 allocator.allocation_size_limit = allocation_size_limit;
176 allocator.buffer_route()?;
178 Ok(allocator)
179 }
180
181 pub fn live_count(&self) -> usize {
182 self.live.len()
183 }
184
185 pub fn is_closed(&self) -> bool {
186 self.closed
187 }
188
189 pub fn max_allocation_size(&self) -> Option<u64> {
193 self.allocation_size_limit
194 }
195
196 pub fn close(&mut self) -> Result<(), AllocError> {
198 close(self)
199 }
200
201 pub unsafe fn allocate(&mut self, request: &AllocRequest) -> Result<Allocation, AllocError> {
206 unsafe { allocate(self, request) }
208 }
209
210 pub unsafe fn free(&mut self, allocation: &mut Allocation) -> Result<(), AllocError> {
213 unsafe { free(self, allocation) }
215 }
216
217 pub unsafe fn map(
221 &mut self,
222 allocation: &Allocation,
223 ) -> Result<*mut std::ffi::c_void, AllocError> {
224 unsafe { map(self, allocation) }
226 }
227
228 pub unsafe fn unmap(&mut self, allocation: &Allocation) -> Result<(), AllocError> {
231 unsafe { unmap(self, allocation) }
233 }
234
235 pub unsafe fn flush(
238 &self,
239 allocation: &Allocation,
240 offset: u64,
241 size: u64,
242 ) -> Result<(), AllocError> {
243 unsafe { flush(self, allocation, offset, size) }
245 }
246
247 pub unsafe fn invalidate(
250 &self,
251 allocation: &Allocation,
252 offset: u64,
253 size: u64,
254 ) -> Result<(), AllocError> {
255 unsafe { invalidate(self, allocation, offset, size) }
257 }
258
259 pub unsafe fn create_buffer(
264 &mut self,
265 info: &vk::BufferCreateInfo,
266 required: vk::MemoryPropertyFlags,
267 preferred: vk::MemoryPropertyFlags,
268 ) -> Result<(vk::Buffer, Allocation), AllocError> {
269 unsafe { create_buffer(self, info, required, preferred) }
271 }
272
273 pub unsafe fn destroy_buffer(
277 &mut self,
278 buffer: vk::Buffer,
279 allocation: &mut Allocation,
280 ) -> Result<(), AllocError> {
281 unsafe { destroy_buffer(self, buffer, allocation) }
283 }
284
285 pub unsafe fn create_buffer_with_options(
289 &mut self,
290 info: &vk::BufferCreateInfo,
291 options: &AllocationCreateInfo,
292 ) -> Result<(vk::Buffer, Allocation), AllocError> {
293 unsafe { create_buffer_with_options(self, info, options) }
295 }
296
297 pub fn mapped_pointer(
299 &self,
300 allocation: &Allocation,
301 ) -> Result<Option<*mut std::ffi::c_void>, AllocError> {
302 mapped_pointer(self, allocation)
303 }
304
305 pub fn statistics(&self) -> AllocatorStats {
306 statistics(self)
307 }
308
309 fn ensure_open(&self) -> Result<(), AllocError> {
310 if self.closed {
311 Err(AllocError::Closed)
312 } else {
313 Ok(())
314 }
315 }
316
317 fn validate(&self, allocation: &Allocation) -> Result<&Live, AllocError> {
318 self.ensure_open()?;
319 if !Arc::ptr_eq(&self.owner, &allocation.owner) {
320 return Err(AllocError::WrongAllocator);
321 }
322 self
323 .live
324 .get(&allocation.serial)
325 .filter(|live| live.serial == allocation.serial && live.handle == allocation.handle)
326 .ok_or(AllocError::UnknownAllocation)
327 }
328
329 fn reserve(&mut self) -> Result<(), AllocError> {
330 self.ensure_open()?;
331 self
332 .next_serial
333 .checked_add(1)
334 .ok_or(AllocError::SerialExhausted)?;
335 self
336 .live
337 .try_reserve(1)
338 .map_err(|_| AllocError::HostAllocationFailed)
339 }
340
341 fn validate_size(&self, size: u64) -> Result<(), AllocError> {
342 if let Some(limit) = self.allocation_size_limit
343 && size > limit
344 {
345 return Err(AllocError::AllocationTooLarge {
346 requested: size,
347 limit,
348 });
349 }
350 Ok(())
351 }
352
353 fn check_native(&self, size: u64, index: u32) -> Result<(), AllocError> {
354 self.validate_size(size)?;
355 if self.native_count >= self.allocation_limit as usize {
356 return Err(AllocError::AllocationLimit);
357 }
358 let heap = self.selector.properties.memory_types[index as usize].heap_index as usize;
359 let available = self.selector.properties.memory_heaps[heap].size - self.heap_bytes[heap];
360 if size > available {
361 return Err(AllocError::OutOfSpace);
362 }
363 self
364 .native_bytes
365 .checked_add(size)
366 .ok_or(AllocError::InvalidRange)?;
367 Ok(())
368 }
369
370 fn add_native(&mut self, size: u64, index: u32) {
371 let heap = self.selector.properties.memory_types[index as usize].heap_index as usize;
372 self.native_count += 1;
373 self.native_bytes += size;
374 self.heap_bytes[heap] += size;
375 }
376
377 fn remove_native(&mut self, size: u64, index: u32) {
378 let heap = self.selector.properties.memory_types[index as usize].heap_index as usize;
379 self.native_count -= 1;
380 self.native_bytes -= size;
381 self.heap_bytes[heap] -= size;
382 }
383
384 fn mapping(&self, allocation: &Allocation) -> &Mapping {
385 if self.live[&allocation.serial].placement.is_some() {
386 &self
387 .blocks
388 .iter()
389 .find(|b| b.handle == allocation.handle)
390 .expect("live block")
391 .mapping
392 } else {
393 &self.live[&allocation.serial].mapping
394 }
395 }
396
397 fn mapping_mut(&mut self, allocation: &Allocation) -> &mut Mapping {
398 if self.live[&allocation.serial].placement.is_some() {
399 &mut self
400 .blocks
401 .iter_mut()
402 .find(|b| b.handle == allocation.handle)
403 .expect("live block")
404 .mapping
405 } else {
406 &mut self
407 .live
408 .get_mut(&allocation.serial)
409 .expect("validated live region")
410 .mapping
411 }
412 }
413
414 fn contains_memory(&self, memory: vk::DeviceMemory) -> bool {
415 self.blocks.iter().any(|b| b.handle == memory)
416 || self.live.values().any(|live| live.handle == memory)
417 }
418
419 fn buffer_route(&self) -> Result<RequirementsRoute, AllocError> {
420 let capabilities = self
421 .device
422 .capabilities()
423 .ok_or(AllocError::UnsupportedCapability(
424 "managed buffers require device creation metadata",
425 ))?;
426 if capabilities.api_version() >= vk::API_VERSION_1_1 {
427 require(
428 self.device.fp().get_buffer_memory_requirements2.is_some(),
429 "vkGetBufferMemoryRequirements2",
430 )?;
431 return Ok(RequirementsRoute::Core);
432 }
433 let enabled = |name| {
434 capabilities
435 .device_extensions()
436 .is_some_and(|mut extensions| extensions.any(|extension| extension == name))
437 };
438 if enabled(c"VK_KHR_dedicated_allocation") {
439 if !enabled(c"VK_KHR_get_memory_requirements2") {
440 return Err(AllocError::UnsupportedCapability(
441 "dedication requires VK_KHR_get_memory_requirements2",
442 ));
443 }
444 require(
445 self
446 .device
447 .fp()
448 .get_buffer_memory_requirements2_khr
449 .is_some(),
450 "vkGetBufferMemoryRequirements2KHR",
451 )?;
452 Ok(RequirementsRoute::Khr)
453 } else {
454 require(
455 self.device.fp().get_buffer_memory_requirements.is_some(),
456 "vkGetBufferMemoryRequirements",
457 )?;
458 Ok(RequirementsRoute::Legacy)
459 }
460 }
461}
462
463fn require(present: bool, name: &'static str) -> Result<(), AllocError> {
464 if present {
465 Ok(())
466 } else {
467 Err(CallError::MissingCommand(name).into())
468 }
469}
470
471pub fn close(allocator: &mut Allocator<'_>) -> Result<(), AllocError> {
473 if !allocator.live.is_empty() {
474 return Err(AllocError::LiveAllocations);
475 }
476 allocator.closed = true;
477 Ok(())
478}
479
480pub unsafe fn allocate(
485 allocator: &mut Allocator<'_>,
486 request: &AllocRequest,
487) -> Result<Allocation, AllocError> {
488 unsafe { allocate_storage(allocator, request, None) }
490}
491
492unsafe fn allocate_storage(
493 allocator: &mut Allocator<'_>,
494 request: &AllocRequest,
495 dedicated: Option<&vk::MemoryDedicatedAllocateInfo>,
496) -> Result<Allocation, AllocError> {
497 allocator.ensure_open()?;
498 allocator.validate_size(request.size)?;
499 if request.required_flags.as_raw() & vk::MemoryPropertyFlagBits::PROTECTED_BIT.as_raw() != 0 {
500 return Err(AllocError::UnsupportedCapability("protected allocation"));
501 }
502 if allocator.native_count >= allocator.allocation_limit as usize {
503 return Err(AllocError::AllocationLimit);
504 }
505 allocator.reserve()?;
506 let mut bits = request.memory_type_bits;
507 let mut last = None;
508 loop {
509 let candidate = AllocRequest {
510 memory_type_bits: bits,
511 ..*request
512 };
513 let index = match allocator.selector.find_memory_type(&candidate) {
514 Ok(index) => index,
515 Err(error) => return Err(last.unwrap_or(error)),
516 };
517 bits &= !(1 << index);
518 if let Err(error) = allocator.check_native(request.size, index) {
519 if error == AllocError::OutOfSpace {
520 last = Some(error);
521 continue;
522 }
523 return Err(error);
524 }
525 let info = vk::MemoryAllocateInfo {
526 allocation_size: request.size,
527 memory_type_index: index,
528 p_next: dedicated.map_or(std::ptr::null(), |info| std::ptr::from_ref(info).cast()),
529 ..Default::default()
530 };
531 let handle = match unsafe { allocator.device.allocate_memory(&info, None) } {
533 Ok(handle) => handle,
534 Err(error) if recoverable(&error) => {
535 last = Some(error.into());
536 continue;
537 }
538 Err(error) => return Err(error.into()),
539 };
540 if handle.is_null() || allocator.contains_memory(handle) {
541 return Err(
542 CallError::InvalidOutput("allocator returned a null or already-live memory handle").into(),
543 );
544 }
545 allocator.add_native(request.size, index);
546 return Ok(publish(
547 allocator,
548 Region {
549 handle,
550 index,
551 size: request.size,
552 reserved_size: request.size,
553 offset: 0,
554 block_size: request.size,
555 placement: None,
556 },
557 ));
558 }
559}
560
561fn recoverable(error: &CallError) -> bool {
562 matches!(error, CallError::Vulkan(result) if *result == vk::Result::ERROR_OUT_OF_DEVICE_MEMORY || *result == vk::Result::ERROR_OUT_OF_HOST_MEMORY)
563}
564
565struct Region {
567 handle: vk::DeviceMemory,
568 index: u32,
569 size: u64,
570 reserved_size: u64,
571 offset: u64,
572 block_size: u64,
573 placement: Option<(usize, u64)>,
574}
575
576fn publish(allocator: &mut Allocator<'_>, region: Region) -> Allocation {
577 let Region {
578 handle,
579 index,
580 size,
581 reserved_size,
582 offset,
583 block_size,
584 placement,
585 } = region;
586 let serial = allocator.next_serial;
587 allocator.next_serial += 1;
588 allocator.live.insert(
589 serial,
590 Live {
591 serial,
592 handle,
593 size,
594 reserved_size,
595 mapped: false,
596 persistent: false,
597 buffer: None,
598 placement,
599 mapping: Mapping::default(),
600 },
601 );
602 let memory = allocator.selector.properties.memory_types[index as usize];
603 Allocation {
604 handle,
605 size,
606 reserved_size,
607 offset,
608 block_size,
609 memory_type_index: index,
610 heap_index: memory.heap_index,
611 flags: memory.property_flags,
612 atom: allocator.selector.atom,
613 owner: allocator.owner.clone(),
614 serial,
615 }
616}
617
618pub unsafe fn free(
623 allocator: &mut Allocator<'_>,
624 allocation: &mut Allocation,
625) -> Result<(), AllocError> {
626 let live = allocator.validate(allocation)?;
627 if live.mapped {
628 return Err(AllocError::AlreadyMapped);
629 }
630 let placement = live.placement;
631 let persistent = live.persistent;
632 if persistent {
633 let device = allocator.device;
634 unsafe {
636 allocator
637 .mapping_mut(allocation)
638 .release(device, allocation.handle)
639 }?;
640 }
641 if let Some((index, generation)) = placement {
642 let block_index = allocator
643 .blocks
644 .iter()
645 .position(|b| b.handle == allocation.handle)
646 .expect("live block");
647 let block = &mut allocator.blocks[block_index];
648 block
649 .metadata
650 .free(index, generation)
651 .expect("validated private placement");
652 if block.metadata.statistics().allocation_count == 0 {
653 debug_assert_eq!(block.mapping.references, 0);
654 unsafe { allocator.device.free_memory(allocation.handle, None) }?;
656 let block = allocator.blocks.remove(block_index);
657 allocator.remove_native(block.size, block.memory_type_index);
658 }
659 } else {
660 unsafe { allocator.device.free_memory(allocation.handle, None) }?;
662 allocator.remove_native(allocation.block_size, allocation.memory_type_index);
663 }
664 allocator.live.remove(&allocation.serial);
665 allocation.handle = vk::DeviceMemory::NULL;
666 Ok(())
667}
668
669pub unsafe fn map(
675 allocator: &mut Allocator<'_>,
676 allocation: &Allocation,
677) -> Result<*mut std::ffi::c_void, AllocError> {
678 if allocator.validate(allocation)?.mapped {
679 return Err(AllocError::AlreadyMapped);
680 }
681 if !allocation.is_host_visible() {
682 return Err(AllocError::NotHostVisible);
683 }
684 let device = allocator.device;
685 let base = unsafe {
687 allocator
688 .mapping_mut(allocation)
689 .acquire(device, allocation.handle, allocation.block_size)
690 }?;
691 allocator
692 .live
693 .get_mut(&allocation.serial)
694 .expect("validated live region")
695 .mapped = true;
696 Ok(
699 base
700 .cast::<u8>()
701 .wrapping_add(allocation.offset as usize)
702 .cast(),
703 )
704}
705
706pub unsafe fn unmap(
710 allocator: &mut Allocator<'_>,
711 allocation: &Allocation,
712) -> Result<(), AllocError> {
713 if !allocator.validate(allocation)?.mapped {
714 return Err(AllocError::NotMapped);
715 }
716 let device = allocator.device;
717 unsafe {
719 allocator
720 .mapping_mut(allocation)
721 .release(device, allocation.handle)
722 }?;
723 allocator
724 .live
725 .get_mut(&allocation.serial)
726 .expect("validated live region")
727 .mapped = false;
728 Ok(())
729}
730
731pub fn mapped_pointer(
734 allocator: &Allocator<'_>,
735 allocation: &Allocation,
736) -> Result<Option<*mut std::ffi::c_void>, AllocError> {
737 let live = allocator.validate(allocation)?;
738 if !live.mapped && !live.persistent {
739 return Ok(None);
740 }
741 Ok(Some(
742 allocator
743 .mapping(allocation)
744 .pointer
745 .cast::<u8>()
746 .wrapping_add(allocation.offset as usize)
747 .cast(),
748 ))
749}
750
751pub fn statistics(allocator: &Allocator<'_>) -> AllocatorStats {
753 AllocatorStats {
754 allocation_count: allocator.live.len(),
755 native_allocation_count: allocator.native_count,
756 pooled_block_count: allocator.blocks.len(),
757 allocation_bytes: allocator.live.values().map(|v| v.size).sum(),
758 reserved_bytes: allocator.live.values().map(|v| v.reserved_size).sum(),
759 native_bytes: allocator.native_bytes,
760 mapped_native_count: allocator
761 .blocks
762 .iter()
763 .filter(|b| b.mapping.references != 0)
764 .count()
765 + allocator
766 .live
767 .values()
768 .filter(|v| v.placement.is_none() && v.mapping.references != 0)
769 .count(),
770 }
771}
772
773pub unsafe fn flush(
777 allocator: &Allocator<'_>,
778 allocation: &Allocation,
779 offset: u64,
780 size: u64,
781) -> Result<(), AllocError> {
782 let live = allocator.validate(allocation)?;
783 if !live.mapped && !live.persistent {
784 return Err(AllocError::NotMapped);
785 }
786 if let Some(range) = allocation.mapped_range(offset, size)? {
787 unsafe { allocator.device.flush_mapped_memory_ranges(&[range]) }?;
789 }
790 Ok(())
791}
792
793pub unsafe fn invalidate(
797 allocator: &Allocator<'_>,
798 allocation: &Allocation,
799 offset: u64,
800 size: u64,
801) -> Result<(), AllocError> {
802 let live = allocator.validate(allocation)?;
803 if !live.mapped && !live.persistent {
804 return Err(AllocError::NotMapped);
805 }
806 if let Some(range) = allocation.mapped_range(offset, size)? {
807 unsafe { allocator.device.invalidate_mapped_memory_ranges(&[range]) }?;
809 }
810 Ok(())
811}
812
813pub unsafe fn create_buffer(
824 allocator: &mut Allocator<'_>,
825 info: &vk::BufferCreateInfo,
826 required: vk::MemoryPropertyFlags,
827 preferred: vk::MemoryPropertyFlags,
828) -> Result<(vk::Buffer, Allocation), AllocError> {
829 let options = AllocationCreateInfo {
830 required_flags: required,
831 preferred_flags: preferred,
832 ..Default::default()
833 };
834 unsafe { create_buffer_with_options(allocator, info, &options) }
836}
837
838pub unsafe fn create_buffer_with_options(
849 allocator: &mut Allocator<'_>,
850 info: &vk::BufferCreateInfo,
851 options: &AllocationCreateInfo,
852) -> Result<(vk::Buffer, Allocation), AllocError> {
853 let mut required = options.required_flags;
854 if options.persistent_map {
855 required = required | vk::MemoryPropertyFlagBits::HOST_VISIBLE_BIT;
856 }
857 let preferred = options.preferred_flags;
858 allocator.ensure_open()?;
859 allocator.validate_size(info.size)?;
860 if !info.p_next.is_null()
861 || info.flags.as_raw() != 0
862 || info.size == 0
863 || info.usage.as_raw() == 0
864 || info.usage.as_raw()
865 & (vk::BufferUsageFlagBits::SHADER_DEVICE_ADDRESS_BIT.as_raw()
866 | vk::BufferUsageFlagBits::TILE_MEMORY_BIT_QCOM.as_raw())
867 != 0
868 {
869 return Err(AllocError::InvalidRequest("ordinary nonempty buffers only"));
870 }
871 if required.as_raw() & vk::MemoryPropertyFlagBits::PROTECTED_BIT.as_raw() != 0 {
872 return Err(AllocError::UnsupportedCapability("protected allocation"));
873 }
874 if let AllocationPolicy::Pooled { block_size: 0 } = options.policy {
875 return Err(AllocError::InvalidRequest(
876 "pooled block size must be nonzero",
877 ));
878 }
879 if options.policy == AllocationPolicy::Separate
880 && allocator.native_count >= allocator.allocation_limit as usize
881 {
882 return Err(AllocError::AllocationLimit);
883 }
884 if options.persistent_map {
885 require(allocator.device.fp().map_memory.is_some(), "vkMapMemory")?;
886 require(
887 allocator.device.fp().unmap_memory.is_some(),
888 "vkUnmapMemory",
889 )?;
890 }
891 let route = allocator.buffer_route()?;
892 let fp = allocator.device.fp();
893 require(fp.create_buffer.is_some(), "vkCreateBuffer")?;
894 require(fp.destroy_buffer.is_some(), "vkDestroyBuffer")?;
895 require(fp.bind_buffer_memory.is_some(), "vkBindBufferMemory")?;
896 allocator.reserve()?;
897 let buffer = unsafe { allocator.device.create_buffer(info, None) }?;
899 if buffer.is_null() {
900 return Err(CallError::InvalidOutput("vkCreateBuffer returned a null handle").into());
901 }
902 let mut dedication = vk::MemoryDedicatedRequirements::default();
903 let mut requirements2 = vk::MemoryRequirements2 {
904 p_next: std::ptr::from_mut(&mut dedication).cast(),
905 ..Default::default()
906 };
907 let query = vk::BufferMemoryRequirementsInfo2 {
908 buffer,
909 ..Default::default()
910 };
911 let requirements = unsafe {
913 match route {
914 RequirementsRoute::Legacy => allocator.device.get_buffer_memory_requirements(buffer),
915 RequirementsRoute::Core => allocator
916 .device
917 .get_buffer_memory_requirements2(&query, &mut requirements2)
918 .map(|()| requirements2.memory_requirements),
919 RequirementsRoute::Khr => allocator
920 .device
921 .get_buffer_memory_requirements2_khr(&query, &mut requirements2)
922 .map(|()| requirements2.memory_requirements),
923 }
924 };
925 let request = requirements.map(|requirements| AllocRequest {
926 size: requirements.size,
927 alignment: requirements.alignment,
928 memory_type_bits: requirements.memory_type_bits & options.memory_type_bits,
929 required_flags: required,
930 preferred_flags: preferred,
931 });
932 let dedicated = vk::MemoryDedicatedAllocateInfo {
933 buffer,
934 ..Default::default()
935 };
936 let dedicated = match route {
937 RequirementsRoute::Legacy => None,
938 _ => Some(&dedicated),
939 };
940 let result = match request {
942 Ok(request) => {
943 let force_separate = dedication.requires_dedicated_allocation != 0
944 || dedication.prefers_dedicated_allocation != 0;
945 if let AllocationPolicy::Pooled { block_size } = options.policy
946 && !force_separate
947 && request.size <= block_size
948 {
949 unsafe { allocate_pooled(allocator, &request, block_size, options.strategy) }
951 } else {
952 unsafe { allocate_storage(allocator, &request, dedicated) }
954 }
955 }
956 Err(error) => Err(error.into()),
957 };
958 let mut allocation = match result {
959 Ok(allocation) => allocation,
960 Err(error) => {
961 unsafe { allocator.device.destroy_buffer(buffer, None) }.expect("preflighted cleanup");
963 return Err(error);
964 }
965 };
966 if options.persistent_map {
967 if let Err(error) = unsafe { map(allocator, &allocation) } {
969 unsafe {
971 allocator
972 .device
973 .destroy_buffer(buffer, None)
974 .expect("preflighted cleanup");
975 free(allocator, &mut allocation).expect("preflighted allocation rollback");
976 }
977 return Err(error);
978 }
979 let live = allocator
980 .live
981 .get_mut(&allocation.serial)
982 .expect("new allocation");
983 live.mapped = false;
984 live.persistent = true;
985 }
986 if let Err(error) = unsafe {
988 allocator
989 .device
990 .bind_buffer_memory(buffer, allocation.handle, allocation.offset)
991 } {
992 unsafe {
994 allocator
995 .device
996 .destroy_buffer(buffer, None)
997 .expect("preflighted cleanup");
998 free(allocator, &mut allocation).expect("preflighted allocation rollback");
999 }
1000 return Err(error.into());
1001 }
1002 allocator.live.get_mut(&allocation.serial).unwrap().buffer = Some(buffer);
1003 Ok((buffer, allocation))
1004}
1005
1006unsafe fn allocate_pooled(
1011 allocator: &mut Allocator<'_>,
1012 request: &AllocRequest,
1013 block_size: u64,
1014 strategy: super::PlacementStrategy,
1015) -> Result<Allocation, AllocError> {
1016 allocator.validate_size(block_size)?;
1017 let mut bits = request.memory_type_bits;
1018 let mut last = None;
1019 loop {
1020 let candidate = AllocRequest {
1021 memory_type_bits: bits,
1022 ..*request
1023 };
1024 let index = match allocator.selector.find_memory_type(&candidate) {
1025 Ok(index) => index,
1026 Err(error) => return Err(last.unwrap_or(error)),
1027 };
1028 bits &= !(1 << index);
1029 let flags = allocator.selector.properties.memory_types[index as usize].property_flags;
1030 let noncoherent = flags.as_raw()
1031 & (vk::MemoryPropertyFlagBits::HOST_VISIBLE_BIT.as_raw()
1032 | vk::MemoryPropertyFlagBits::HOST_COHERENT_BIT.as_raw())
1033 == vk::MemoryPropertyFlagBits::HOST_VISIBLE_BIT.as_raw();
1034 let atom = if noncoherent {
1035 allocator.selector.atom
1036 } else {
1037 1
1038 };
1039 let alignment = request.alignment.max(atom);
1040 if !alignment.is_power_of_two() || !request.alignment.is_power_of_two() || request.size == 0 {
1041 return Err(AllocError::InvalidRequest(
1042 "invalid native buffer requirements",
1043 ));
1044 }
1045 let reserved = request
1046 .size
1047 .checked_add(atom - 1)
1048 .map(|v| v & !(atom - 1))
1049 .ok_or(AllocError::InvalidRange)?;
1050 if reserved > block_size {
1051 last = Some(AllocError::OutOfSpace);
1053 continue;
1054 }
1055 for block in &mut allocator.blocks {
1056 if block.memory_type_index != index || block.size != block_size {
1057 continue;
1058 }
1059 let placement = match block.metadata.allocate(reserved, alignment, strategy) {
1060 Ok(placement) => placement,
1061 Err(AllocError::OutOfSpace) => continue,
1062 Err(error) => return Err(error),
1063 };
1064 let offset = block
1065 .metadata
1066 .info(placement.0, placement.1)
1067 .expect("new placement")
1068 .offset;
1069 let handle = block.handle;
1070 return Ok(publish(
1071 allocator,
1072 Region {
1073 handle,
1074 index,
1075 size: request.size,
1076 reserved_size: reserved,
1077 offset,
1078 block_size,
1079 placement: Some(placement),
1080 },
1081 ));
1082 }
1083 if let Err(error) = allocator.check_native(block_size, index) {
1084 if error == AllocError::OutOfSpace || error == AllocError::AllocationLimit {
1086 last = Some(error);
1087 continue;
1088 }
1089 return Err(error);
1090 }
1091 allocator
1092 .blocks
1093 .try_reserve(1)
1094 .map_err(|_| AllocError::HostAllocationFailed)?;
1095 let mut metadata = Tlsf::new(block_size)?;
1096 let placement = metadata.allocate(reserved, alignment, strategy)?;
1097 let info = vk::MemoryAllocateInfo {
1098 allocation_size: block_size,
1099 memory_type_index: index,
1100 ..Default::default()
1101 };
1102 let handle = match unsafe { allocator.device.allocate_memory(&info, None) } {
1104 Ok(handle) => handle,
1105 Err(error) if recoverable(&error) => {
1106 last = Some(error.into());
1107 continue;
1108 }
1109 Err(error) => return Err(error.into()),
1110 };
1111 if handle.is_null() || allocator.contains_memory(handle) {
1112 return Err(
1113 CallError::InvalidOutput("allocator returned a null or already-live memory handle").into(),
1114 );
1115 }
1116 allocator.blocks.push(Block {
1117 handle,
1118 size: block_size,
1119 memory_type_index: index,
1120 metadata,
1121 mapping: Mapping::default(),
1122 });
1123 allocator.add_native(block_size, index);
1124 return Ok(publish(
1125 allocator,
1126 Region {
1127 handle,
1128 index,
1129 size: request.size,
1130 reserved_size: reserved,
1131 offset: 0,
1132 block_size,
1133 placement: Some(placement),
1134 },
1135 ));
1136 }
1137}
1138
1139pub unsafe fn destroy_buffer(
1143 allocator: &mut Allocator<'_>,
1144 buffer: vk::Buffer,
1145 allocation: &mut Allocation,
1146) -> Result<(), AllocError> {
1147 let live = allocator.validate(allocation)?;
1148 if live.buffer != Some(buffer) {
1149 return Err(AllocError::WrongResource);
1150 }
1151 if live.mapped {
1152 return Err(AllocError::AlreadyMapped);
1153 }
1154 require(
1156 allocator.device.fp().destroy_buffer.is_some(),
1157 "vkDestroyBuffer",
1158 )?;
1159 require(allocator.device.fp().free_memory.is_some(), "vkFreeMemory")?;
1160 unsafe {
1162 allocator.device.destroy_buffer(buffer, None)?;
1163 free(allocator, allocation)
1164 }
1165}
1166
1167#[cfg(test)]
1168#[path = "../../../test/rs/memory/test_lifecycle.rs"]
1169mod tests;