1use super::*;
6
7struct Requirements {
8 memory: vk::MemoryRequirements,
9 dedication: Dedication,
10 dedicated_supported: bool,
11}
12
13unsafe fn requirements(
14 allocator: &Allocator<'_>,
15 resource: Resource,
16) -> Result<Requirements, AllocError> {
17 unsafe { requirements_with_plane(allocator, resource, None) }
19}
20
21unsafe fn requirements_with_plane(
22 allocator: &Allocator<'_>,
23 resource: Resource,
24 plane: Option<vk::ImageAspectFlagBits>,
25) -> Result<Requirements, AllocError> {
26 let route = allocator.requirements_route(matches!(resource, Resource::Image(_)))?;
27 unsafe { query_requirements(allocator.device.as_device(), route, resource, plane) }
29}
30
31unsafe fn query_requirements(
32 device: &vk::Device,
33 route: RequirementsRoute,
34 resource: Resource,
35 plane: Option<vk::ImageAspectFlagBits>,
36) -> Result<Requirements, AllocError> {
37 if plane.is_some() && matches!(route, RequirementsRoute::Legacy) {
38 return Err(AllocError::UnsupportedCapability(
39 "disjoint planes require memory requirements2",
40 ));
41 }
42 let plane_info = vk::ImagePlaneMemoryRequirementsInfo {
43 plane_aspect: plane.unwrap_or_default(),
44 ..Default::default()
45 };
46 let mut dedication = vk::MemoryDedicatedRequirements::new();
47 let mut output = vk::MemoryRequirements2 {
48 p_next: std::ptr::from_mut(&mut dedication).cast(),
49 ..Default::default()
50 };
51 unsafe {
54 match resource {
55 Resource::Buffer(buffer) => {
56 let query = vk::BufferMemoryRequirementsInfo2 {
57 buffer,
58 ..Default::default()
59 };
60 match route {
61 RequirementsRoute::Legacy => {
62 output.memory_requirements = device.get_buffer_memory_requirements(buffer)?
63 }
64 RequirementsRoute::Core => device.get_buffer_memory_requirements2(&query, &mut output)?,
65 RequirementsRoute::Khr => {
66 device.get_buffer_memory_requirements2_khr(&query, &mut output)?
67 }
68 }
69 }
70 Resource::Image(image) => {
71 let query = vk::ImageMemoryRequirementsInfo2 {
72 p_next: if plane.is_some() {
73 std::ptr::from_ref(&plane_info).cast()
74 } else {
75 std::ptr::null()
76 },
77 image,
78 ..Default::default()
79 };
80 match route {
81 RequirementsRoute::Legacy => {
82 device.get_image_memory_requirements(image, &mut output.memory_requirements)?
83 }
84 RequirementsRoute::Core => device.get_image_memory_requirements2(&query, &mut output)?,
85 RequirementsRoute::Khr => {
86 device.get_image_memory_requirements2_khr(&query, &mut output)?
87 }
88 }
89 }
90 }
91 }
92 if output.memory_requirements.size == 0 || !output.memory_requirements.alignment.is_power_of_two()
93 {
94 return Err(AllocError::InvalidRequest(
95 "invalid native resource requirements",
96 ));
97 }
98 Ok(Requirements {
99 memory: output.memory_requirements,
100 dedication: Dedication::new(&dedication),
101 dedicated_supported: !matches!(route, RequirementsRoute::Legacy),
102 })
103}
104
105pub(in crate::mem) fn plane_slot(plane: Option<vk::ImageAspectFlagBits>) -> usize {
109 match plane {
110 Some(vk::ImageAspectFlagBits::PLANE_0_BIT) => 1,
111 Some(vk::ImageAspectFlagBits::PLANE_1_BIT) => 2,
112 Some(vk::ImageAspectFlagBits::PLANE_2_BIT) => 3,
113 None => 0,
114 _ => unreachable!("canonical binding validates plane aspects"),
115 }
116}
117
118pub(super) struct Associations<'device> {
124 buffers: HostMap<'device, [u64; 4]>,
125 images: HostMap<'device, [u64; 4]>,
126}
127
128impl<'device> Associations<'device> {
129 pub fn new(host: HostMemory<'device>) -> Self {
130 Self {
131 buffers: HostMap::new(host),
132 images: HostMap::new(host),
133 }
134 }
135
136 fn registry(&self, resource: Resource) -> (&HostMap<'device, [u64; 4]>, u64) {
137 match resource {
138 Resource::Buffer(buffer) => (&self.buffers, buffer.as_raw()),
139 Resource::Image(image) => (&self.images, image.as_raw()),
140 }
141 }
142
143 fn registry_mut(&mut self, resource: Resource) -> (&mut HostMap<'device, [u64; 4]>, u64) {
144 match resource {
145 Resource::Buffer(buffer) => (&mut self.buffers, buffer.as_raw()),
146 Resource::Image(image) => (&mut self.images, image.as_raw()),
147 }
148 }
149
150 pub fn associated(&self, resource: Resource) -> bool {
152 let (registry, key) = self.registry(resource);
153 registry.get(&key).is_some()
154 }
155
156 pub fn conflicts(&self, resource: Resource, plane: Option<vk::ImageAspectFlagBits>) -> bool {
160 let (registry, key) = self.registry(resource);
161 let Some(slots) = registry.get(&key) else {
162 return false;
163 };
164 match plane {
165 None => true,
166 Some(_) => slots[0] != 0 || slots[plane_slot(plane)] != 0,
167 }
168 }
169
170 pub fn try_reserve_for(&mut self, resource: Resource) -> Result<(), AllocError> {
171 let (registry, _) = self.registry_mut(resource);
172 registry.try_reserve(1)
173 }
174
175 pub fn try_reserve(&mut self, additional: usize) -> Result<(), AllocError> {
178 self.buffers.try_reserve(additional)?;
179 self.images.try_reserve(additional)
180 }
181
182 pub fn record(
184 &mut self,
185 resource: Resource,
186 plane: Option<vk::ImageAspectFlagBits>,
187 serial: u64,
188 ) {
189 let (registry, key) = self.registry_mut(resource);
190 registry.get_or_insert_reserved_with(key, || [0; 4])[plane_slot(plane)] = serial;
191 }
192
193 pub fn release(
196 &mut self,
197 resource: Resource,
198 plane: Option<vk::ImageAspectFlagBits>,
199 serial: u64,
200 ) {
201 let (registry, key) = self.registry_mut(resource);
202 registry.remove_if(&key, |slots| {
203 let slot = plane_slot(plane);
204 if slots[slot] == serial {
205 slots[slot] = 0;
206 }
207 slots.iter().all(|owner| *owner == 0)
208 });
209 }
210}
211
212pub(super) fn associated(allocator: &Allocator<'_>, resource: Resource) -> bool {
213 if let Some(shared) = allocator.parallel_state() {
214 let domain = allocator.partition_id;
215 if shared.associated(resource, domain) {
216 return true;
217 }
218 }
219 allocator.associated.associated(resource)
220}
221
222pub(super) unsafe fn allocate_prepared_resource(
231 allocator: &mut Allocator<'_>,
232 resource: Resource,
233 options: &AllocationCreateInfo,
234 preferences: (
235 vk::MemoryPropertyFlags,
236 vk::MemoryPropertyFlags,
237 vk::MemoryPropertyFlags,
238 ),
239 class: ResourceClass,
240 device_address: bool,
241) -> Result<u64, AllocError> {
242 let (required, preferred, avoided) = preferences;
243 if allocator.parallel.is_none() {
244 allocator.associated.try_reserve_for(resource)?;
247 }
248 let claim = parallel::claim(allocator, resource, None, None)?;
249 let imported = options
250 .memory_allocate_next
251 .and_then(|chain| chain.data.import_info);
252 let requirements = if let Some(info) = imported.filter(|info| info.resource.is_some()) {
253 if import_resource(info.resource) != Some(resource) {
254 return Err(AllocError::WrongResource);
255 }
256 Requirements {
259 memory: vk::MemoryRequirements {
260 size: info.allocation_size,
261 alignment: 1,
262 memory_type_bits: info.memory_type_bits,
263 },
264 dedication: Dedication::Required,
265 dedicated_supported: true,
266 }
267 } else {
268 if options
269 .memory_allocate_next
270 .is_some_and(|chain| chain.data.import_kind.requires_info())
271 {
272 return Err(AllocError::InvalidRequest(
273 "platform resource imports require exact resource metadata",
274 ));
275 }
276 unsafe { requirements(allocator, resource) }?
278 };
279 let request = AllocRequest {
280 size: requirements.memory.size,
281 alignment: requirements
282 .memory
283 .alignment
284 .max(options.min_allocation_alignment),
285 memory_type_bits: requirements.memory.memory_type_bits & options.memory_type_bits,
286 required_flags: required,
287 preferred_flags: preferred,
288 };
289 let mut dedicated = vk::MemoryDedicatedAllocateInfo::new();
290 match resource {
291 Resource::Buffer(buffer) => dedicated.buffer = buffer,
292 Resource::Image(image) => dedicated.image = image,
293 }
294 let serial = unsafe {
296 allocate_managed(
297 allocator,
298 &request,
299 StorageOptions {
300 chain: &super::super::chain::ChainData::EMPTY,
301 dedicated: requirements.dedicated_supported.then_some(&dedicated),
302 device_address,
303 priority: options.priority,
304 within_budget: options.within_budget,
305 },
306 requirements.dedication,
307 options,
308 class,
309 avoided,
310 )
311 }?;
312 let live = allocator.live.get_mut(&serial).expect("new allocation");
313 live.resource = Some(resource);
314 live.class = if options.can_alias {
315 ResourceClass::Unknown
316 } else {
317 class
318 };
319 live.can_alias = options.can_alias;
320 if let Some(claim) = claim {
321 claim.commit(serial);
322 } else {
323 allocator.associated.record(resource, None, serial);
324 }
325 Ok(serial)
326}
327
328pub(super) unsafe fn persistent(
329 allocator: &mut Allocator<'_>,
330 allocation: &Allocation,
331 options: &AllocationCreateInfo,
332) -> Result<(), AllocError> {
333 unsafe { guard::initialize(allocator, allocation) }?;
335 if options.persistent_map {
336 unsafe { map(allocator, allocation) }?;
338 let live = allocator
339 .live
340 .get_mut(&allocation.serial)
341 .expect("new allocation");
342 live.map_count = 0;
343 live.persistent = true;
344 }
345 Ok(())
346}
347
348unsafe fn allocate_existing(
349 allocator: &mut Allocator<'_>,
350 resource: Resource,
351 options: &AllocationCreateInfo,
352) -> Result<Allocation, AllocError> {
353 allocator.ensure_open()?;
354 if associated(allocator, resource) {
355 return Err(AllocError::InvalidRequest(
356 "resource already has an allocation",
357 ));
358 }
359
360 if options.usage != super::super::MemoryUsage::Explicit {
361 return Err(AllocError::UnsupportedCapability(
362 "existing resource usage is unknown; use explicit memory flags",
363 ));
364 }
365 let preferences = super::super::policy::preferences(options, false, allocator.integrated)?;
366 let class = match resource {
367 Resource::Buffer(_) => ResourceClass::Buffer,
368 Resource::Image(_) => ResourceClass::UnknownImage,
369 };
370 let address = matches!(resource, Resource::Buffer(_)) && allocator.buffer_device_address;
371 if resource.is_null() {
372 return Err(AllocError::InvalidRequest("null resource"));
373 }
374 request::validate_options(allocator, options, preferences.0)?;
375 if options.persistent_map {
376 require(allocator.device.fp().map_memory.is_some(), "vkMapMemory")?;
377 require(
378 allocator.device.fp().unmap_memory.is_some(),
379 "vkUnmapMemory",
380 )?;
381 }
382 allocator.reserve()?;
383 let serial = unsafe {
385 allocate_prepared_resource(allocator, resource, options, preferences, class, address)
386 }?;
387 let mut allocation = allocator.published(serial);
388 if let Err(error) = unsafe { persistent(allocator, &allocation, options) } {
390 unsafe { rollback_allocation(allocator, &mut allocation) }
392 .expect("preflighted allocation rollback");
393 return Err(error);
394 }
395 Ok(allocation)
396}
397
398pub unsafe fn allocate_for_buffer(
418 allocator: &mut Allocator<'_>,
419 buffer: vk::Buffer,
420 options: &AllocationCreateInfo,
421) -> Result<Allocation, AllocError> {
422 unsafe { allocate_existing(allocator, Resource::Buffer(buffer), options) }
424}
425
426pub unsafe fn allocate_for_image(
442 allocator: &mut Allocator<'_>,
443 image: vk::Image,
444 options: &AllocationCreateInfo,
445) -> Result<Allocation, AllocError> {
446 unsafe { allocate_existing(allocator, Resource::Image(image), options) }
448}
449
450struct BindChain {
451 status: Option<*mut vk::Result>,
452 plane: Option<vk::ImageAspectFlagBits>,
453}
454
455#[inline]
456unsafe fn binding_status(next: *const std::ffi::c_void) -> Result<BindChain, AllocError> {
457 if next.is_null() {
458 return Ok(BindChain {
459 status: None,
460 plane: None,
461 });
462 }
463 unsafe { nonempty_binding_status(next) }
465}
466
467#[inline(never)]
468unsafe fn nonempty_binding_status(
469 mut next: *const std::ffi::c_void,
470) -> Result<BindChain, AllocError> {
471 let mut seen = [std::ptr::null(); 64];
472 let mut count = 0;
473 let mut status = None;
474 let mut plane = None;
475 let mut tags = [vk::StructureType::from_raw(0); 64];
476 while !next.is_null() {
477 if count == seen.len() || seen[..count].contains(&next) {
478 return Err(AllocError::InvalidRequest("cyclic/excessive bind chain"));
479 }
480 seen[count] = next;
481 let node = unsafe { &*next.cast::<vk::BaseInStructure>() };
483 if tags[..count].contains(&node.s_type) {
484 return Err(AllocError::InvalidRequest("duplicate bind chain record"));
485 }
486 tags[count] = node.s_type;
487 count += 1;
488 if node.s_type == vk::StructureType::BIND_IMAGE_PLANE_MEMORY_INFO {
489 let aspect = unsafe { (*next.cast::<vk::BindImagePlaneMemoryInfo>()).plane_aspect };
491 use crate::ImageAspectFlagBits as A;
492 if !matches!(aspect, A::PLANE_0_BIT | A::PLANE_1_BIT | A::PLANE_2_BIT) {
493 return Err(AllocError::UnsupportedCapability(
494 "ordinary disjoint image plane aspect required",
495 ));
496 }
497 plane = Some(aspect);
498 }
499 if node.s_type == vk::StructureType::BIND_MEMORY_STATUS {
500 let pointer = unsafe { (*next.cast::<vk::BindMemoryStatus>()).p_result };
502 if status.is_some() || pointer.is_null() {
503 return Err(AllocError::InvalidRequest(
504 "duplicate/null bind status output",
505 ));
506 }
507 status = Some(pointer);
508 }
509 next = node.p_next.cast();
510 }
511 Ok(BindChain { status, plane })
512}
513
514pub unsafe fn bind_buffer_memory2(
526 allocator: &mut Allocator<'_>,
527 buffer: vk::Buffer,
528 allocation: &Allocation,
529 local_offset: u64,
530 next: *const std::ffi::c_void,
531) -> Result<(), AllocError> {
532 unsafe {
534 bind_resource(
535 allocator,
536 Resource::Buffer(buffer),
537 allocation,
538 local_offset,
539 next,
540 true,
541 false,
542 )
543 }
544}
545
546pub unsafe fn bind_image_memory2(
558 allocator: &mut Allocator<'_>,
559 image: vk::Image,
560 allocation: &Allocation,
561 local_offset: u64,
562 next: *const std::ffi::c_void,
563) -> Result<(), AllocError> {
564 unsafe {
566 bind_resource(
567 allocator,
568 Resource::Image(image),
569 allocation,
570 local_offset,
571 next,
572 true,
573 false,
574 )
575 }
576}
577
578pub(super) unsafe fn bind_alias(
579 allocator: &mut Allocator<'_>,
580 resource: Resource,
581 allocation: &Allocation,
582 local_offset: u64,
583) -> Result<(), AllocError> {
584 unsafe {
586 bind_resource(
587 allocator,
588 resource,
589 allocation,
590 local_offset,
591 std::ptr::null(),
592 false,
593 true,
594 )
595 }
596}
597
598unsafe fn bind_resource(
599 allocator: &mut Allocator<'_>,
600 resource: Resource,
601 allocation: &Allocation,
602 local_offset: u64,
603 next: *const std::ffi::c_void,
604 extended: bool,
605 alias: bool,
606) -> Result<(), AllocError> {
607 let operation = unsafe {
609 prepare_bind(
610 allocator,
611 resource,
612 allocation,
613 local_offset,
614 next,
615 extended,
616 alias,
617 )
618 }?;
619 let backing = allocator.mapping(allocation);
622 unsafe { operation.execute(allocator.device.as_device()) }?;
624 drop(backing);
625 operation.commit(allocator)
626}
627
628pub(super) unsafe fn bind_prepared(
638 allocator: &mut Allocator<'_>,
639 resource: Resource,
640 allocation: &Allocation,
641) -> Result<(), AllocError> {
642 let operation = BindOperation {
643 route: RequirementsRoute::Legacy,
644 requirements_route: None,
645 resource,
646 serial: allocation.serial,
647 handle: allocation.handle,
648 native_offset: allocation.offset,
649 remaining_size: allocation.size,
650 memory_type_index: allocation.memory_type_index,
651 next: std::ptr::null(),
652 status: None,
653 plane: None,
654 alias: false,
655 claim: None,
656 };
657 let backing = allocator.mapping(allocation);
658 unsafe { operation.execute(allocator.device.as_device()) }?;
660 drop(backing);
661 operation.commit(allocator)
662}
663
664pub(super) struct BindOperation<'device> {
665 route: RequirementsRoute,
666 requirements_route: Option<RequirementsRoute>,
667 resource: Resource,
668 serial: u64,
669 handle: vk::DeviceMemory,
670 native_offset: u64,
671 remaining_size: u64,
672 memory_type_index: u32,
673 next: *const std::ffi::c_void,
674 status: Option<*mut vk::Result>,
675 pub(super) plane: Option<vk::ImageAspectFlagBits>,
676 alias: bool,
677 claim: Option<parallel::resource::Claim<'device>>,
678}
679
680pub(super) unsafe fn prepare_bind<'device>(
681 allocator: &mut Allocator<'device>,
682 resource: Resource,
683 allocation: &Allocation,
684 local_offset: u64,
685 next: *const std::ffi::c_void,
686 extended: bool,
687 alias: bool,
688) -> Result<BindOperation<'device>, AllocError> {
689 let route = if !extended {
690 RequirementsRoute::Legacy
691 } else {
692 let capabilities =
693 allocator
694 .device
695 .as_device()
696 .capabilities()
697 .ok_or(AllocError::UnsupportedCapability(
698 "extended binding requires creation metadata",
699 ))?;
700 if capabilities.api_version() >= vk::API_VERSION_1_1 {
701 RequirementsRoute::Core
702 } else if super::super::resource::extension(
703 allocator.device.as_device(),
704 c"VK_KHR_bind_memory2",
705 ) {
706 RequirementsRoute::Khr
707 } else {
708 return Err(AllocError::UnsupportedCapability(
709 "bind_memory2 is not enabled",
710 ));
711 }
712 };
713 let BindChain { status, plane } = unsafe { binding_status(next) }?;
715 let live = allocator.validate(allocation)?;
716 if live.native_users != 0 {
717 return Err(AllocError::InvalidRequest("native operation in progress"));
718 }
719 if plane.is_some() {
720 if !extended || !matches!(resource, Resource::Image(_)) || live.resource.is_some() || alias {
721 return Err(AllocError::InvalidRequest(
722 "plane binding requires unassociated raw storage and image bind2",
723 ));
724 }
725 if !allocator
726 .device
727 .as_device()
728 .capabilities()
729 .is_some_and(|caps| caps.api_version() >= vk::API_VERSION_1_1)
730 && !super::super::resource::extension(
731 allocator.device.as_device(),
732 c"VK_KHR_sampler_ycbcr_conversion",
733 ) {
734 return Err(AllocError::UnsupportedCapability(
735 "disjoint plane binding is not enabled",
736 ));
737 }
738 }
739 if resource.is_null() {
740 return Err(AllocError::InvalidRequest("null resource"));
741 }
742 if alias && !live.can_alias {
743 return Err(AllocError::UnsupportedCapability(
744 "allocation was not created for aliasing",
745 ));
746 }
747 if !alias && live.bound {
748 return Err(AllocError::InvalidRequest("allocation already bound"));
749 }
750 if !alias && live.resource.is_some_and(|target| target != resource) {
751 return Err(AllocError::WrongResource);
752 }
753 let raw = alias || live.resource.is_none();
754 let (handle, offset, size, memory_type_index) =
757 (live.handle, live.offset, live.size, live.memory_type_index);
758 if raw && allocator.associated.conflicts(resource, plane) {
761 return Err(AllocError::WrongResource);
762 }
763 allocator.associated.try_reserve_for(resource)?;
764 let claim = parallel::claim(
765 allocator,
766 resource,
767 plane,
768 (!raw).then_some(allocation.serial),
769 )?;
770 let fp = allocator.device.fp();
771 match (resource, route) {
772 (Resource::Buffer(_), RequirementsRoute::Legacy) => {
773 require(fp.bind_buffer_memory.is_some(), "vkBindBufferMemory")?
774 }
775 (Resource::Image(_), RequirementsRoute::Legacy) => {
776 require(fp.bind_image_memory.is_some(), "vkBindImageMemory")?
777 }
778 (Resource::Buffer(_), RequirementsRoute::Core) => {
779 require(fp.bind_buffer_memory2.is_some(), "vkBindBufferMemory2")?
780 }
781 (Resource::Image(_), RequirementsRoute::Core) => {
782 require(fp.bind_image_memory2.is_some(), "vkBindImageMemory2")?
783 }
784 (Resource::Buffer(_), RequirementsRoute::Khr) => require(
785 fp.bind_buffer_memory2_khr.is_some(),
786 "vkBindBufferMemory2KHR",
787 )?,
788 (Resource::Image(_), RequirementsRoute::Khr) => {
789 require(fp.bind_image_memory2_khr.is_some(), "vkBindImageMemory2KHR")?
790 }
791 }
792 let native_offset = offset
793 .checked_add(local_offset)
794 .ok_or(AllocError::InvalidRange)?;
795 if local_offset > size || (!raw && local_offset != 0) {
796 return Err(AllocError::InvalidRange);
797 }
798 let requirements_route = if raw {
799 Some(allocator.requirements_route(matches!(resource, Resource::Image(_)))?)
800 } else {
801 None
802 };
803 Ok(BindOperation {
804 route,
805 requirements_route,
806 resource,
807 serial: allocation.serial,
808 handle,
809 native_offset,
810 remaining_size: size - local_offset,
811 memory_type_index,
812 next,
813 status,
814 plane,
815 alias,
816 claim,
817 })
818}
819
820impl BindOperation<'_> {
821 pub(super) unsafe fn execute(&self, device: &vk::Device) -> Result<(), AllocError> {
822 let (route, resource, handle, native_offset, next, status, plane) = (
823 self.route,
824 self.resource,
825 self.handle,
826 self.native_offset,
827 self.next,
828 self.status,
829 self.plane,
830 );
831
832 if let Some(requirements_route) = self.requirements_route {
833 let requirements =
835 unsafe { query_requirements(device, requirements_route, resource, plane) }?;
836 if requirements.dedication == Dedication::Required {
837 return Err(AllocError::UnsupportedCapability(
838 "raw allocation cannot satisfy required resource dedication",
839 ));
840 }
841 if requirements.memory.memory_type_bits & (1 << self.memory_type_index) == 0 {
842 return Err(AllocError::NoCompatibleMemoryType);
843 }
844 if requirements.memory.size > self.remaining_size
845 || !native_offset.is_multiple_of(requirements.memory.alignment)
846 {
847 return Err(AllocError::InvalidRange);
848 }
849 }
850 if let Some(status) = status {
851 unsafe {
853 *status = vk::Result::NOT_READY;
854 }
855 }
856 unsafe {
858 match resource {
859 Resource::Buffer(buffer) => {
860 let info = vk::BindBufferMemoryInfo {
861 buffer,
862 memory: handle,
863 memory_offset: native_offset,
864 p_next: next,
865 ..Default::default()
866 };
867 match route {
868 RequirementsRoute::Legacy => {
869 device.bind_buffer_memory(buffer, handle, native_offset)?
870 }
871 RequirementsRoute::Core => device.bind_buffer_memory2(&[info])?,
872 RequirementsRoute::Khr => device.bind_buffer_memory2_khr(&[info])?,
873 }
874 }
875 Resource::Image(image) => {
876 let info = vk::BindImageMemoryInfo {
877 image,
878 memory: handle,
879 memory_offset: native_offset,
880 p_next: next,
881 ..Default::default()
882 };
883 match route {
884 RequirementsRoute::Legacy => device.bind_image_memory(image, handle, native_offset)?,
885 RequirementsRoute::Core => device.bind_image_memory2(&[info])?,
886 RequirementsRoute::Khr => device.bind_image_memory2_khr(&[info])?,
887 }
888 }
889 }
890 }
891 if let Some(status) = status {
892 let result = unsafe { *status };
894 if result != vk::Result::SUCCESS {
895 return Err(
896 if result.as_raw() < 0 {
897 CallError::Vulkan(result)
898 } else {
899 CallError::InvalidOutput("native binding did not publish success status")
900 }
901 .into(),
902 );
903 }
904 }
905 Ok(())
906 }
907
908 pub(super) fn commit(self, allocator: &mut Allocator<'_>) -> Result<(), AllocError> {
909 if self.alias {
910 return Ok(());
911 }
912 let live = allocator
913 .live
914 .get_mut(&self.serial)
915 .expect("validated allocation");
916 let already_associated = live.resource == Some(self.resource) && live.plane == self.plane;
917 live.resource = Some(self.resource);
918 live.plane = self.plane;
919 live.bound = true;
920 if let Some(claim) = self.claim {
921 claim.commit(self.serial);
922 } else if !already_associated {
923 allocator
924 .associated
925 .record(self.resource, self.plane, self.serial);
926 }
927 Ok(())
928 }
929}
930
931pub unsafe fn bind_buffer_memory(
943 allocator: &mut Allocator<'_>,
944 buffer: vk::Buffer,
945 allocation: &Allocation,
946) -> Result<(), AllocError> {
947 unsafe {
949 bind_resource(
950 allocator,
951 Resource::Buffer(buffer),
952 allocation,
953 0,
954 std::ptr::null(),
955 false,
956 false,
957 )
958 }
959}
960
961pub unsafe fn bind_image_memory(
969 allocator: &mut Allocator<'_>,
970 image: vk::Image,
971 allocation: &Allocation,
972) -> Result<(), AllocError> {
973 unsafe {
975 bind_resource(
976 allocator,
977 Resource::Image(image),
978 allocation,
979 0,
980 std::ptr::null(),
981 false,
982 false,
983 )
984 }
985}
986
987impl Allocator<'_> {
988 pub unsafe fn bind_buffer_memory2(
992 &mut self,
993 buffer: vk::Buffer,
994 allocation: &Allocation,
995 local_offset: u64,
996 next: *const std::ffi::c_void,
997 ) -> Result<(), AllocError> {
998 unsafe { bind_buffer_memory2(self, buffer, allocation, local_offset, next) }
1000 }
1001
1002 pub unsafe fn bind_image_memory2(
1006 &mut self,
1007 image: vk::Image,
1008 allocation: &Allocation,
1009 local_offset: u64,
1010 next: *const std::ffi::c_void,
1011 ) -> Result<(), AllocError> {
1012 unsafe { bind_image_memory2(self, image, allocation, local_offset, next) }
1014 }
1015 pub unsafe fn allocate_for_buffer(
1019 &mut self,
1020 buffer: vk::Buffer,
1021 options: &AllocationCreateInfo,
1022 ) -> Result<Allocation, AllocError> {
1023 unsafe { allocate_for_buffer(self, buffer, options) }
1025 }
1026
1027 pub unsafe fn allocate_for_image(
1031 &mut self,
1032 image: vk::Image,
1033 options: &AllocationCreateInfo,
1034 ) -> Result<Allocation, AllocError> {
1035 unsafe { allocate_for_image(self, image, options) }
1037 }
1038
1039 pub unsafe fn bind_buffer_memory(
1043 &mut self,
1044 buffer: vk::Buffer,
1045 allocation: &Allocation,
1046 ) -> Result<(), AllocError> {
1047 unsafe { bind_buffer_memory(self, buffer, allocation) }
1049 }
1050
1051 pub unsafe fn bind_image_memory(
1055 &mut self,
1056 image: vk::Image,
1057 allocation: &Allocation,
1058 ) -> Result<(), AllocError> {
1059 unsafe { bind_image_memory(self, image, allocation) }
1061 }
1062}
1063
1064#[cfg(test)]
1065#[path = "../../../test/rs/mem/test_associated.rs"]
1066mod tests;