vk/mem/synchronized/access.rs
1//! Direct `&self` operation access, delegating to the canonical allocator.
2//!
3//! Placement retains the owner mutex. Mapping/binding uses dynamic per-backing
4//! leases and releases the placement mutex through the native call. Exclusive
5//! services and borrowed access wait for those calls before observing/mutating
6//! their state. Native byte/GPU synchronization remains the caller's obligation.
7//!
8//! Results borrowing allocator metadata and relocation contexts remain scoped
9//! to `with_allocator`; no mutable allocator guard or borrowed result escapes.
10use super::SynchronizedAllocator;
11use crate::{
12 self as vk,
13 mem::{
14 AllocError, AllocRequest, Allocation, AllocationChain, AllocationCreateInfo, AllocationInfo,
15 Allocator, AllocatorInfo, BudgetSnapshot, CacheRange, DebugMemorySettings, DetailedStatistics,
16 DeviceMemoryCallbacks, MemoryStatistics, Pool, PoolCreateInfo, PoolStats, TrimStats,
17 },
18};
19
20impl<'device> SynchronizedAllocator<'device> {
21 fn locked<R>(
22 &self,
23 operation: impl FnOnce(&mut Allocator<'device>) -> Result<R, AllocError>,
24 ) -> Result<R, AllocError> {
25 let mut guard = self.lock_idle()?;
26 operation(&mut guard.allocator)
27 }
28
29 fn placement<R>(
30 &self,
31 operation: impl FnOnce(&mut Allocator<'device>) -> Result<R, AllocError>,
32 ) -> Result<R, AllocError> {
33 let mut guard = self.lock_owner()?;
34 operation(&mut guard.allocator)
35 }
36
37 /// Number of live allocation registrations under this allocator's lock.
38 /// # Errors
39 /// Returns SynchronizationPoisoned after a closure panic.
40 pub fn live_count(&self) -> Result<usize, AllocError> {
41 self.locked(|allocator| Ok(allocator.live_count()))
42 }
43
44 /// Observe explicit close state under this allocator's lock.
45 /// # Errors
46 /// Returns SynchronizationPoisoned after a closure panic.
47 pub fn is_closed(&self) -> Result<bool, AllocError> {
48 self.locked(|allocator| Ok(allocator.is_closed()))
49 }
50
51 /// Optional caller-configured size limit under this allocator's lock.
52 /// # Errors
53 /// Returns SynchronizationPoisoned after a closure panic.
54 pub fn max_allocation_size(&self) -> Result<Option<u64>, AllocError> {
55 self.locked(|allocator| Ok(allocator.max_allocation_size()))
56 }
57
58 /// Close the allocator under its lock; later access reports `Closed`.
59 /// Concurrent operations complete or fail before this runs.
60 /// # Errors
61 /// Same live-resource errors as `Allocator::close`, plus SynchronizationPoisoned.
62 pub fn close(&self) -> Result<(), AllocError> {
63 self.locked(Allocator::close)
64 }
65
66 /// Captured native identities under this allocator's lock.
67 /// # Errors
68 /// Same errors as `Allocator::allocator_info`, plus SynchronizationPoisoned.
69 pub fn allocator_info(&self) -> Result<AllocatorInfo, AllocError> {
70 self.locked(|allocator| crate::mem::allocator_info(allocator))
71 }
72
73 /// Queried properties of one native memory type under this allocator's lock.
74 /// # Errors
75 /// Same errors as `Allocator::memory_type_properties`, plus SynchronizationPoisoned.
76 pub fn memory_type_properties(&self, index: u32) -> Result<vk::MemoryPropertyFlags, AllocError> {
77 self.locked(|allocator| allocator.memory_type_properties(index))
78 }
79
80 /// Score memory types for one allocation request under this allocator's lock.
81 /// # Errors
82 /// Same errors as `Allocator::find_memory_type`, plus SynchronizationPoisoned.
83 pub fn find_memory_type(
84 &self,
85 bits: u32,
86 options: &AllocationCreateInfo,
87 ) -> Result<u32, AllocError> {
88 self.locked(|allocator| allocator.find_memory_type(bits, options))
89 }
90
91 /// Score memory types for one buffer's requirements under this allocator's lock.
92 /// # Errors
93 /// Same errors as `Allocator::find_memory_type_for_buffer_info`, plus SynchronizationPoisoned.
94 /// # Safety
95 /// Same create-chain and requirement query contract as
96 /// `Allocator::find_memory_type_for_buffer_info`.
97 pub unsafe fn find_memory_type_for_buffer_info(
98 &self,
99 info: &vk::BufferCreateInfo,
100 options: &AllocationCreateInfo,
101 ) -> Result<u32, AllocError> {
102 // SAFETY: identical canonical query contract.
103 unsafe { self.locked(|allocator| allocator.find_memory_type_for_buffer_info(info, options)) }
104 }
105
106 /// Score memory types for one image's requirements under this allocator's lock.
107 /// # Errors
108 /// Same errors as `Allocator::find_memory_type_for_image_info`, plus SynchronizationPoisoned.
109 /// # Safety
110 /// Same create-chain and requirement query contract as
111 /// `Allocator::find_memory_type_for_image_info`.
112 pub unsafe fn find_memory_type_for_image_info(
113 &self,
114 info: &vk::ImageCreateInfo,
115 options: &AllocationCreateInfo,
116 ) -> Result<u32, AllocError> {
117 // SAFETY: identical canonical query contract.
118 unsafe { self.locked(|allocator| allocator.find_memory_type_for_image_info(info, options)) }
119 }
120
121 /// Run `Allocator::allocate` under this allocator's lock.
122 /// # Errors
123 /// Same checked/native errors as `Allocator::allocate`, plus SynchronizationPoisoned.
124 /// # Safety
125 /// Same request/chain/import and completion contract as `Allocator::allocate`.
126 pub unsafe fn allocate(&self, request: &AllocRequest) -> Result<Allocation, AllocError> {
127 // SAFETY: identical canonical operation contract.
128 unsafe { self.placement(|allocator| allocator.allocate(request)) }
129 }
130
131 /// Run `Allocator::allocate_with_options` under this allocator's lock.
132 /// # Errors
133 /// Same checked/native errors as `Allocator::allocate_with_options`, plus SynchronizationPoisoned.
134 /// # Safety
135 /// Same requirements/options/chain contract as `Allocator::allocate_with_options`.
136 pub unsafe fn allocate_with_options(
137 &self,
138 requirements: &vk::MemoryRequirements,
139 options: &AllocationCreateInfo,
140 ) -> Result<Allocation, AllocError> {
141 // SAFETY: identical canonical operation contract.
142 unsafe { self.placement(|allocator| allocator.allocate_with_options(requirements, options)) }
143 }
144
145 /// Run `Allocator::allocate_dedicated` under this allocator's lock.
146 /// # Errors
147 /// Same checked/native errors as `Allocator::allocate_dedicated`, plus SynchronizationPoisoned.
148 /// # Safety
149 /// Same requirements/chain/import contract as `Allocator::allocate_dedicated`.
150 pub unsafe fn allocate_dedicated(
151 &self,
152 requirements: &vk::MemoryRequirements,
153 options: &AllocationCreateInfo,
154 chain: Option<AllocationChain>,
155 ) -> Result<Allocation, AllocError> {
156 // SAFETY: identical canonical operation contract.
157 unsafe {
158 self.placement(|allocator| allocator.allocate_dedicated(requirements, options, chain))
159 }
160 }
161
162 /// Run `Allocator::allocate_many` under this allocator's lock.
163 /// # Errors
164 /// Same checked/native errors as `Allocator::allocate_many`, plus SynchronizationPoisoned.
165 /// # Safety
166 /// Same requirements/options contract as `Allocator::allocate_many`.
167 pub unsafe fn allocate_many(
168 &self,
169 requirements: &vk::MemoryRequirements,
170 options: &AllocationCreateInfo,
171 count: usize,
172 ) -> Result<Vec<Allocation>, AllocError> {
173 // SAFETY: identical canonical operation contract.
174 unsafe { self.placement(|allocator| allocator.allocate_many(requirements, options, count)) }
175 }
176
177 /// Run `Allocator::free` under this allocator's lock.
178 /// # Errors
179 /// Same checked/native errors as `Allocator::free`, plus SynchronizationPoisoned.
180 /// # Safety
181 /// Same live-token, mapped-byte and completion contract as `Allocator::free`.
182 pub unsafe fn free(&self, allocation: &mut Allocation) -> Result<(), AllocError> {
183 // SAFETY: identical canonical operation contract.
184 unsafe {
185 crate::mem::allocator::native::with_allocation(self, allocation.serial, |allocator| {
186 allocator.free(allocation)
187 })
188 }
189 }
190
191 /// Run `Allocator::free_many` under this allocator's lock.
192 /// # Errors
193 /// Same checked/native errors as `Allocator::free_many`, plus SynchronizationPoisoned.
194 /// # Safety
195 /// Same live-token and completion contract as `Allocator::free_many`.
196 pub unsafe fn free_many(&self, allocations: &mut [Allocation]) -> Result<(), AllocError> {
197 // SAFETY: identical canonical operation contract.
198 unsafe { self.locked(|allocator| allocator.free_many(allocations)) }
199 }
200
201 /// Checked allocation snapshot under this allocator's lock.
202 /// # Errors
203 /// Same errors as `Allocator::allocation_info`, plus SynchronizationPoisoned.
204 pub fn allocation_info(&self, allocation: &Allocation) -> Result<AllocationInfo, AllocError> {
205 self.locked(|allocator| allocator.allocation_info(allocation))
206 }
207
208 /// Run `Allocator::set_allocation_pinned` under this allocator's lock.
209 /// # Errors
210 /// Same errors as `Allocator::set_allocation_pinned`, plus SynchronizationPoisoned.
211 pub fn set_allocation_pinned(
212 &self,
213 allocation: &Allocation,
214 pinned: bool,
215 ) -> Result<(), AllocError> {
216 self.locked(|allocator| allocator.set_allocation_pinned(allocation, pinned))
217 }
218
219 /// Run `Allocator::set_allocation_name` under this allocator's lock.
220 /// # Errors
221 /// Same errors as `Allocator::set_allocation_name`, plus SynchronizationPoisoned.
222 pub fn set_allocation_name(
223 &self,
224 allocation: &Allocation,
225 name: Option<&str>,
226 ) -> Result<(), AllocError> {
227 self.locked(|allocator| allocator.set_allocation_name(allocation, name))
228 }
229
230 /// Run `Allocator::set_allocation_user_data` under this allocator's lock.
231 /// # Errors
232 /// Same errors as `Allocator::set_allocation_user_data`, plus SynchronizationPoisoned.
233 pub fn set_allocation_user_data(
234 &self,
235 allocation: &Allocation,
236 data: usize,
237 ) -> Result<(), AllocError> {
238 self.locked(|allocator| allocator.set_allocation_user_data(allocation, data))
239 }
240
241 /// Run `Allocator::create_buffer` under this allocator's lock.
242 /// # Errors
243 /// Same transaction errors as `Allocator::create_buffer`, plus SynchronizationPoisoned.
244 /// # Safety
245 /// Same resource/allocation contract as `Allocator::create_buffer`.
246 pub unsafe fn create_buffer(
247 &self,
248 info: &vk::BufferCreateInfo,
249 required: vk::MemoryPropertyFlags,
250 preferred: vk::MemoryPropertyFlags,
251 ) -> Result<(vk::Buffer, Allocation), AllocError> {
252 // SAFETY: identical canonical operation contract.
253 unsafe { self.placement(|allocator| allocator.create_buffer(info, required, preferred)) }
254 }
255
256 /// Run `Allocator::create_buffer_with_options` under this allocator's lock.
257 /// # Errors
258 /// Same transaction errors as `Allocator::create_buffer_with_options`, plus SynchronizationPoisoned.
259 /// # Safety
260 /// Same resource/allocation contract as `Allocator::create_buffer_with_options`.
261 pub unsafe fn create_buffer_with_options(
262 &self,
263 info: &vk::BufferCreateInfo,
264 options: &AllocationCreateInfo,
265 ) -> Result<(vk::Buffer, Allocation), AllocError> {
266 // SAFETY: identical canonical operation contract.
267 unsafe { self.placement(|allocator| allocator.create_buffer_with_options(info, options)) }
268 }
269
270 /// Run `Allocator::create_dedicated_buffer` under this allocator's lock.
271 /// # Errors
272 /// Same transaction errors as `Allocator::create_dedicated_buffer`, plus SynchronizationPoisoned.
273 /// # Safety
274 /// Same resource/chain/import contract as `Allocator::create_dedicated_buffer`.
275 pub unsafe fn create_dedicated_buffer(
276 &self,
277 info: &vk::BufferCreateInfo,
278 options: &AllocationCreateInfo,
279 chain: Option<AllocationChain>,
280 ) -> Result<(vk::Buffer, Allocation), AllocError> {
281 // SAFETY: identical canonical operation contract.
282 unsafe { self.placement(|allocator| allocator.create_dedicated_buffer(info, options, chain)) }
283 }
284
285 /// Run `Allocator::destroy_buffer` under this allocator's lock.
286 /// # Errors
287 /// Same checked errors as `Allocator::destroy_buffer`, plus SynchronizationPoisoned.
288 /// # Safety
289 /// Same resource ownership and completion contract as `Allocator::destroy_buffer`.
290 pub unsafe fn destroy_buffer(
291 &self,
292 buffer: vk::Buffer,
293 allocation: &mut Allocation,
294 ) -> Result<(), AllocError> {
295 // SAFETY: identical canonical operation contract.
296 unsafe {
297 crate::mem::allocator::native::with_allocation(self, allocation.serial, |allocator| {
298 allocator.destroy_buffer(buffer, allocation)
299 })
300 }
301 }
302
303 /// Run `Allocator::create_image` under this allocator's lock.
304 /// # Errors
305 /// Same transaction errors as `Allocator::create_image`, plus SynchronizationPoisoned.
306 /// # Safety
307 /// Same resource/allocation contract as `Allocator::create_image`.
308 pub unsafe fn create_image(
309 &self,
310 info: &vk::ImageCreateInfo,
311 required: vk::MemoryPropertyFlags,
312 preferred: vk::MemoryPropertyFlags,
313 ) -> Result<(vk::Image, Allocation), AllocError> {
314 // SAFETY: identical canonical operation contract.
315 unsafe { self.placement(|allocator| allocator.create_image(info, required, preferred)) }
316 }
317
318 /// Run `Allocator::create_image_with_options` under this allocator's lock.
319 /// # Errors
320 /// Same transaction errors as `Allocator::create_image_with_options`, plus SynchronizationPoisoned.
321 /// # Safety
322 /// Same resource/allocation contract as `Allocator::create_image_with_options`.
323 pub unsafe fn create_image_with_options(
324 &self,
325 info: &vk::ImageCreateInfo,
326 options: &AllocationCreateInfo,
327 ) -> Result<(vk::Image, Allocation), AllocError> {
328 // SAFETY: identical canonical operation contract.
329 unsafe { self.placement(|allocator| allocator.create_image_with_options(info, options)) }
330 }
331
332 /// Run `Allocator::create_dedicated_image` under this allocator's lock.
333 /// # Errors
334 /// Same transaction errors as `Allocator::create_dedicated_image`, plus SynchronizationPoisoned.
335 /// # Safety
336 /// Same resource/chain/import contract as `Allocator::create_dedicated_image`.
337 pub unsafe fn create_dedicated_image(
338 &self,
339 info: &vk::ImageCreateInfo,
340 options: &AllocationCreateInfo,
341 chain: Option<AllocationChain>,
342 ) -> Result<(vk::Image, Allocation), AllocError> {
343 // SAFETY: identical canonical operation contract.
344 unsafe { self.placement(|allocator| allocator.create_dedicated_image(info, options, chain)) }
345 }
346
347 /// Run `Allocator::destroy_image` under this allocator's lock.
348 /// # Errors
349 /// Same checked errors as `Allocator::destroy_image`, plus SynchronizationPoisoned.
350 /// # Safety
351 /// Same resource ownership and completion contract as `Allocator::destroy_image`.
352 pub unsafe fn destroy_image(
353 &self,
354 image: vk::Image,
355 allocation: &mut Allocation,
356 ) -> Result<(), AllocError> {
357 // SAFETY: identical canonical operation contract.
358 unsafe {
359 crate::mem::allocator::native::with_allocation(self, allocation.serial, |allocator| {
360 allocator.destroy_image(image, allocation)
361 })
362 }
363 }
364
365 /// Run `Allocator::allocate_for_buffer` under this allocator's lock.
366 /// # Errors
367 /// Same checked/native errors as `Allocator::allocate_for_buffer`, plus SynchronizationPoisoned.
368 /// # Safety
369 /// Same external-resource and allocation contract as `Allocator::allocate_for_buffer`.
370 pub unsafe fn allocate_for_buffer(
371 &self,
372 buffer: vk::Buffer,
373 options: &AllocationCreateInfo,
374 ) -> Result<Allocation, AllocError> {
375 // SAFETY: identical canonical operation contract.
376 unsafe { self.placement(|allocator| allocator.allocate_for_buffer(buffer, options)) }
377 }
378
379 /// Run `Allocator::allocate_for_image` under this allocator's lock.
380 /// # Errors
381 /// Same checked/native errors as `Allocator::allocate_for_image`, plus SynchronizationPoisoned.
382 /// # Safety
383 /// Same external-resource and allocation contract as `Allocator::allocate_for_image`.
384 pub unsafe fn allocate_for_image(
385 &self,
386 image: vk::Image,
387 options: &AllocationCreateInfo,
388 ) -> Result<Allocation, AllocError> {
389 // SAFETY: identical canonical operation contract.
390 unsafe { self.placement(|allocator| allocator.allocate_for_image(image, options)) }
391 }
392
393 /// Run `Allocator::create_aliasing_buffer` under this allocator's lock.
394 /// # Errors
395 /// Same checked errors as `Allocator::create_aliasing_buffer`, plus SynchronizationPoisoned.
396 /// # Safety
397 /// Same alias/storage contract as `Allocator::create_aliasing_buffer`.
398 pub unsafe fn create_aliasing_buffer(
399 &self,
400 allocation: &Allocation,
401 local_offset: u64,
402 info: &vk::BufferCreateInfo,
403 ) -> Result<vk::Buffer, AllocError> {
404 // SAFETY: identical canonical operation contract.
405 unsafe {
406 self.locked(|allocator| allocator.create_aliasing_buffer(allocation, local_offset, info))
407 }
408 }
409
410 /// Run `Allocator::create_aliasing_image` under this allocator's lock.
411 /// # Errors
412 /// Same checked errors as `Allocator::create_aliasing_image`, plus SynchronizationPoisoned.
413 /// # Safety
414 /// Same alias/storage contract as `Allocator::create_aliasing_image`.
415 pub unsafe fn create_aliasing_image(
416 &self,
417 allocation: &Allocation,
418 local_offset: u64,
419 info: &vk::ImageCreateInfo,
420 ) -> Result<vk::Image, AllocError> {
421 // SAFETY: identical canonical operation contract.
422 unsafe {
423 self.locked(|allocator| allocator.create_aliasing_image(allocation, local_offset, info))
424 }
425 }
426
427 /// Run `Allocator::copy_to_allocation` under this allocator's lock.
428 /// # Errors
429 /// Same checked errors as `Allocator::copy_to_allocation`, plus SynchronizationPoisoned.
430 /// # Safety
431 /// Same mapped-range and byte-validity contract as `Allocator::copy_to_allocation`.
432 pub unsafe fn copy_to_allocation(
433 &self,
434 allocation: &Allocation,
435 offset: u64,
436 source: &[u8],
437 ) -> Result<(), AllocError> {
438 // SAFETY: identical canonical operation contract.
439 unsafe { self.locked(|allocator| allocator.copy_to_allocation(allocation, offset, source)) }
440 }
441
442 /// Run `Allocator::copy_from_allocation` under this allocator's lock.
443 /// # Errors
444 /// Same checked errors as `Allocator::copy_from_allocation`, plus SynchronizationPoisoned.
445 /// # Safety
446 /// Same mapped-range and byte-validity contract as `Allocator::copy_from_allocation`.
447 pub unsafe fn copy_from_allocation(
448 &self,
449 allocation: &Allocation,
450 offset: u64,
451 destination: &mut [u8],
452 ) -> Result<(), AllocError> {
453 // SAFETY: identical canonical operation contract.
454 unsafe {
455 self.locked(|allocator| allocator.copy_from_allocation(allocation, offset, destination))
456 }
457 }
458
459 /// Run `Allocator::bind_buffer_memory` under a live lease and this backing's mutex.
460 /// # Errors
461 /// Same checked errors as `Allocator::bind_buffer_memory`, plus SynchronizationPoisoned.
462 /// # Safety
463 /// Same native binding contract as `Allocator::bind_buffer_memory`.
464 pub unsafe fn bind_buffer_memory(
465 &self,
466 buffer: vk::Buffer,
467 allocation: &Allocation,
468 ) -> Result<(), AllocError> {
469 // SAFETY: identical canonical operation contract.
470 unsafe {
471 crate::mem::allocator::native::bind(
472 self,
473 buffer.into(),
474 allocation,
475 0,
476 std::ptr::null(),
477 false,
478 )
479 }
480 }
481
482 /// Run `Allocator::bind_image_memory` under a live lease and this backing's mutex.
483 /// # Errors
484 /// Same checked errors as `Allocator::bind_image_memory`, plus SynchronizationPoisoned.
485 /// # Safety
486 /// Same native binding contract as `Allocator::bind_image_memory`.
487 pub unsafe fn bind_image_memory(
488 &self,
489 image: vk::Image,
490 allocation: &Allocation,
491 ) -> Result<(), AllocError> {
492 // SAFETY: identical canonical operation contract.
493 unsafe {
494 crate::mem::allocator::native::bind(
495 self,
496 image.into(),
497 allocation,
498 0,
499 std::ptr::null(),
500 false,
501 )
502 }
503 }
504
505 /// Run `Allocator::bind_buffer_memory2` under a live lease and this backing's mutex.
506 /// # Errors
507 /// Same checked errors as `Allocator::bind_buffer_memory2`, plus SynchronizationPoisoned.
508 /// # Safety
509 /// Same native chain/binding contract as `Allocator::bind_buffer_memory2`.
510 pub unsafe fn bind_buffer_memory2(
511 &self,
512 buffer: vk::Buffer,
513 allocation: &Allocation,
514 local_offset: u64,
515 next: *const std::ffi::c_void,
516 ) -> Result<(), AllocError> {
517 // SAFETY: identical canonical operation contract.
518 unsafe {
519 crate::mem::allocator::native::bind(self, buffer.into(), allocation, local_offset, next, true)
520 }
521 }
522
523 /// Run `Allocator::bind_image_memory2` under a live lease and this backing's mutex.
524 /// # Errors
525 /// Same checked errors as `Allocator::bind_image_memory2`, plus SynchronizationPoisoned.
526 /// # Safety
527 /// Same native chain/binding contract as `Allocator::bind_image_memory2`.
528 pub unsafe fn bind_image_memory2(
529 &self,
530 image: vk::Image,
531 allocation: &Allocation,
532 local_offset: u64,
533 next: *const std::ffi::c_void,
534 ) -> Result<(), AllocError> {
535 // SAFETY: identical canonical operation contract.
536 unsafe {
537 crate::mem::allocator::native::bind(self, image.into(), allocation, local_offset, next, true)
538 }
539 }
540
541 /// Run `Allocator::map` under a live lease and this backing's mutex.
542 /// # Errors
543 /// Same checked/native errors as `Allocator::map`, plus SynchronizationPoisoned.
544 /// # Safety
545 /// May fail to reserve the stable backing metadata before native effects.
546 /// Same mapping, mapped-byte synchronization and completion contract as
547 /// `Allocator::map`; escaping pointers retain `SynchronizedAllocator` rules.
548 pub unsafe fn map(&self, allocation: &Allocation) -> Result<*mut std::ffi::c_void, AllocError> {
549 // SAFETY: identical canonical operation contract.
550 unsafe { crate::mem::allocator::native::map(self, allocation, true) }
551 }
552
553 /// Run `Allocator::unmap` under a live lease and this backing's mutex.
554 /// # Errors
555 /// Same checked errors as `Allocator::unmap`, plus SynchronizationPoisoned.
556 /// # Safety
557 /// Same mapped-byte and completion contract as `Allocator::unmap`.
558 pub unsafe fn unmap(&self, allocation: &Allocation) -> Result<(), AllocError> {
559 // SAFETY: identical canonical operation contract.
560 unsafe { crate::mem::allocator::native::map(self, allocation, false) }.map(|_| ())
561 }
562
563 /// Current mapping pointer for one allocation under this allocator's lock.
564 /// # Errors
565 /// Same errors as `Allocator::mapped_pointer`, plus SynchronizationPoisoned.
566 pub fn mapped_pointer(
567 &self,
568 allocation: &Allocation,
569 ) -> Result<Option<*mut std::ffi::c_void>, AllocError> {
570 self.locked(|allocator| allocator.mapped_pointer(allocation))
571 }
572
573 /// Run `Allocator::flush` under this allocator's lock.
574 /// # Errors
575 /// Same checked/native errors as `Allocator::flush`, plus SynchronizationPoisoned.
576 /// # Safety
577 /// Same cache-range and completion contract as `Allocator::flush`.
578 pub unsafe fn flush(
579 &self,
580 allocation: &Allocation,
581 offset: u64,
582 size: u64,
583 ) -> Result<(), AllocError> {
584 // SAFETY: identical canonical operation contract.
585 unsafe { self.locked(|allocator| allocator.flush(allocation, offset, size)) }
586 }
587
588 /// Run `Allocator::invalidate` under this allocator's lock.
589 /// # Errors
590 /// Same checked/native errors as `Allocator::invalidate`, plus SynchronizationPoisoned.
591 /// # Safety
592 /// Same cache-range and completion contract as `Allocator::invalidate`.
593 pub unsafe fn invalidate(
594 &self,
595 allocation: &Allocation,
596 offset: u64,
597 size: u64,
598 ) -> Result<(), AllocError> {
599 // SAFETY: identical canonical operation contract.
600 unsafe { self.locked(|allocator| allocator.invalidate(allocation, offset, size)) }
601 }
602
603 /// Run `Allocator::flush_many` under this allocator's lock.
604 /// # Errors
605 /// Same checked/native errors as `Allocator::flush_many`, plus SynchronizationPoisoned.
606 /// # Safety
607 /// Same cache-range contract as `Allocator::flush_many`.
608 pub unsafe fn flush_many(&self, ranges: &[CacheRange<'_>]) -> Result<(), AllocError> {
609 // SAFETY: identical canonical operation contract.
610 unsafe { self.locked(|allocator| allocator.flush_many(ranges)) }
611 }
612
613 /// Run `Allocator::invalidate_many` under this allocator's lock.
614 /// # Errors
615 /// Same checked/native errors as `Allocator::invalidate_many`, plus SynchronizationPoisoned.
616 /// # Safety
617 /// Same cache-range contract as `Allocator::invalidate_many`.
618 pub unsafe fn invalidate_many(&self, ranges: &[CacheRange<'_>]) -> Result<(), AllocError> {
619 // SAFETY: identical canonical operation contract.
620 unsafe { self.locked(|allocator| allocator.invalidate_many(ranges)) }
621 }
622
623 /// Run `Allocator::set_heap_limit` under this allocator's lock.
624 /// # Errors
625 /// Same errors as `Allocator::set_heap_limit`, plus SynchronizationPoisoned.
626 pub fn set_heap_limit(&self, heap: u32, limit: u64) -> Result<(), AllocError> {
627 self.locked(|allocator| allocator.set_heap_limit(heap, limit))
628 }
629
630 /// Cached budget snapshot under this allocator's lock.
631 /// # Errors
632 /// Returns SynchronizationPoisoned after a closure panic.
633 pub fn budget_snapshot(&self) -> Result<BudgetSnapshot, AllocError> {
634 self.locked(|allocator| Ok(allocator.budget_snapshot()))
635 }
636
637 /// Run `Allocator::query_budget` under this allocator's lock.
638 /// # Errors
639 /// Same errors as `Allocator::query_budget`, plus SynchronizationPoisoned.
640 /// # Safety
641 /// Same instance/physical-device and PFN contract as `Allocator::query_budget`.
642 pub unsafe fn query_budget(
643 &self,
644 instance: &vk::Instance,
645 physical: vk::PhysicalDevice,
646 ) -> Result<BudgetSnapshot, AllocError> {
647 // SAFETY: identical canonical operation contract.
648 unsafe { self.locked(|allocator| allocator.query_budget(instance, physical)) }
649 }
650
651 /// Run `Allocator::refresh_budget` under this allocator's lock.
652 /// # Errors
653 /// Same errors as `Allocator::refresh_budget`, plus SynchronizationPoisoned.
654 pub fn refresh_budget(&self) -> Result<BudgetSnapshot, AllocError> {
655 self.locked(Allocator::refresh_budget)
656 }
657
658 /// Run `Allocator::refresh_budget_with_context` under this allocator's lock.
659 /// # Errors
660 /// Same errors as `Allocator::refresh_budget_with_context`, plus SynchronizationPoisoned.
661 /// # Safety
662 /// Same context/PFN contract as `Allocator::refresh_budget_with_context`.
663 pub unsafe fn refresh_budget_with_context(
664 &self,
665 instance: &vk::Instance,
666 physical: vk::PhysicalDevice,
667 ) -> Result<BudgetSnapshot, AllocError> {
668 // SAFETY: identical canonical operation contract.
669 unsafe { self.locked(|allocator| allocator.refresh_budget_with_context(instance, physical)) }
670 }
671
672 /// Run `Allocator::heap_budgets` under this allocator's lock.
673 /// # Errors
674 /// Same errors as `Allocator::heap_budgets`, plus SynchronizationPoisoned.
675 pub fn heap_budgets(&self) -> Result<BudgetSnapshot, AllocError> {
676 self.locked(Allocator::heap_budgets)
677 }
678
679 /// Run `Allocator::set_current_frame_index` under this allocator's lock.
680 /// # Errors
681 /// Same errors as `Allocator::set_current_frame_index`, plus SynchronizationPoisoned.
682 pub fn set_current_frame_index(&self, index: u32) -> Result<(), AllocError> {
683 self.locked(|allocator| allocator.set_current_frame_index(index))
684 }
685
686 /// Current frame index under this allocator's lock.
687 /// # Errors
688 /// Returns SynchronizationPoisoned after a closure panic.
689 pub fn current_frame_index(&self) -> Result<u32, AllocError> {
690 self.locked(|allocator| Ok(allocator.current_frame_index()))
691 }
692
693 /// Run `Allocator::trim` under this allocator's lock.
694 /// # Errors
695 /// Same errors as `Allocator::trim`, plus SynchronizationPoisoned.
696 pub fn trim(&self) -> Result<TrimStats, AllocError> {
697 self.locked(Allocator::trim)
698 }
699
700 /// Run `Allocator::trim_with_budget` under this allocator's lock.
701 /// # Errors
702 /// Same errors as `Allocator::trim_with_budget`, plus SynchronizationPoisoned.
703 /// # Safety
704 /// Same instance/physical-device and PFN contract as `Allocator::trim_with_budget`.
705 pub unsafe fn trim_with_budget(
706 &self,
707 instance: &vk::Instance,
708 physical: vk::PhysicalDevice,
709 ) -> Result<TrimStats, AllocError> {
710 // SAFETY: identical canonical operation contract.
711 unsafe { self.locked(|allocator| allocator.trim_with_budget(instance, physical)) }
712 }
713
714 /// Run `Allocator::create_pool` under this allocator's lock.
715 /// # Errors
716 /// Same checked/native errors as `Allocator::create_pool`, plus SynchronizationPoisoned.
717 /// # Safety
718 /// Same policy/storage contract as `Allocator::create_pool`.
719 pub unsafe fn create_pool(&self, info: &PoolCreateInfo) -> Result<Pool, AllocError> {
720 // SAFETY: identical canonical operation contract.
721 unsafe { self.locked(|allocator| allocator.create_pool(info)) }
722 }
723
724 /// Run `Allocator::create_pool_with_chain` under this allocator's lock.
725 /// # Errors
726 /// Same checked/native errors as `Allocator::create_pool_with_chain`, plus SynchronizationPoisoned.
727 /// # Safety
728 /// Same retained-chain contract as `Allocator::create_pool_with_chain`;
729 /// the chain must also satisfy `SynchronizedAllocator::new`'s any-thread rules.
730 pub unsafe fn create_pool_with_chain(
731 &self,
732 info: &PoolCreateInfo,
733 chain: AllocationChain<'device>,
734 ) -> Result<Pool, AllocError> {
735 // SAFETY: identical canonical operation contract.
736 unsafe { self.locked(|allocator| allocator.create_pool_with_chain(info, chain)) }
737 }
738
739 /// Run `Allocator::destroy_pool` under this allocator's lock.
740 /// # Errors
741 /// Same live-resource errors as `Allocator::destroy_pool`, plus SynchronizationPoisoned.
742 pub fn destroy_pool(&self, pool: &mut Pool) -> Result<(), AllocError> {
743 self.locked(|allocator| allocator.destroy_pool(pool))
744 }
745
746 /// One pool's statistics under this allocator's lock.
747 /// # Errors
748 /// Same errors as `Allocator::pool_statistics`, plus SynchronizationPoisoned.
749 pub fn pool_statistics(&self, pool: &Pool) -> Result<PoolStats, AllocError> {
750 self.locked(|allocator| allocator.pool_statistics(pool))
751 }
752
753 /// Run `Allocator::set_pool_name` under this allocator's lock.
754 /// # Errors
755 /// Same errors as `Allocator::set_pool_name`, plus SynchronizationPoisoned.
756 pub fn set_pool_name(&self, pool: &Pool, name: Option<&str>) -> Result<(), AllocError> {
757 self.locked(|allocator| allocator.set_pool_name(pool, name))
758 }
759
760 /// Run `Allocator::set_preferred_block_size` under this allocator's lock.
761 /// # Errors
762 /// Same errors as `Allocator::set_preferred_block_size`, plus SynchronizationPoisoned.
763 pub fn set_preferred_block_size(&self, size: u64) -> Result<(), AllocError> {
764 self.locked(|allocator| allocator.set_preferred_block_size(size))
765 }
766
767 /// Run `Allocator::set_mapping_hysteresis` under this allocator's lock.
768 /// # Errors
769 /// Same errors as `Allocator::set_mapping_hysteresis`, plus SynchronizationPoisoned.
770 pub fn set_mapping_hysteresis(&self, enabled: bool) -> Result<(), AllocError> {
771 self.locked(|allocator| allocator.set_mapping_hysteresis(enabled))
772 }
773
774 /// Aggregate memory statistics under this allocator's lock.
775 /// # Errors
776 /// Same errors as `Allocator::detailed_statistics`, plus SynchronizationPoisoned.
777 pub fn detailed_statistics(&self) -> Result<MemoryStatistics, AllocError> {
778 self.locked(|allocator| allocator.detailed_statistics())
779 }
780
781 /// One pool's detailed statistics under this allocator's lock.
782 /// # Errors
783 /// Same errors as `Allocator::detailed_pool_statistics`, plus SynchronizationPoisoned.
784 pub fn detailed_pool_statistics(&self, pool: &Pool) -> Result<DetailedStatistics, AllocError> {
785 self.locked(|allocator| allocator.detailed_pool_statistics(pool))
786 }
787
788 /// Run `Allocator::write_statistics_json` under this allocator's lock.
789 /// # Errors
790 /// Same errors as `Allocator::write_statistics_json`, plus SynchronizationPoisoned.
791 pub fn write_statistics_json(
792 &self,
793 output: &mut impl std::io::Write,
794 detailed: bool,
795 ) -> Result<(), AllocError> {
796 self.locked(|allocator| allocator.write_statistics_json(output, detailed))
797 }
798
799 /// Run `Allocator::set_debug_memory_settings` under this allocator's lock.
800 /// # Errors
801 /// Same errors as `Allocator::set_debug_memory_settings`, plus SynchronizationPoisoned.
802 pub fn set_debug_memory_settings(&self, settings: DebugMemorySettings) -> Result<(), AllocError> {
803 self.locked(|allocator| allocator.set_debug_memory_settings(settings))
804 }
805
806 /// Run `Allocator::check_corruption` under this allocator's lock.
807 /// # Errors
808 /// Same checked errors as `Allocator::check_corruption`, plus SynchronizationPoisoned.
809 /// # Safety
810 /// Same guard-pattern byte-validity contract as `Allocator::check_corruption`.
811 pub unsafe fn check_corruption(&self, bits: u32) -> Result<(), AllocError> {
812 // SAFETY: identical canonical operation contract.
813 unsafe { self.locked(|allocator| allocator.check_corruption(bits)) }
814 }
815
816 /// Run `Allocator::check_pool_corruption` under this allocator's lock.
817 /// # Errors
818 /// Same checked errors as `Allocator::check_pool_corruption`, plus SynchronizationPoisoned.
819 /// # Safety
820 /// Same guard-pattern byte-validity contract as `Allocator::check_pool_corruption`.
821 pub unsafe fn check_pool_corruption(&self, pool: &Pool) -> Result<(), AllocError> {
822 // SAFETY: identical canonical operation contract.
823 unsafe { self.locked(|allocator| allocator.check_pool_corruption(pool)) }
824 }
825
826 /// Run `Allocator::set_external_memory_types` under this allocator's lock.
827 /// # Errors
828 /// Same errors as `Allocator::set_external_memory_types`, plus SynchronizationPoisoned.
829 /// # Safety
830 /// Same capability/creation contract as `Allocator::set_external_memory_types`.
831 pub unsafe fn set_external_memory_types(
832 &self,
833 types: &[vk::ExternalMemoryHandleTypeFlags],
834 ) -> Result<(), AllocError> {
835 // SAFETY: identical canonical operation contract.
836 unsafe { self.locked(|allocator| allocator.set_external_memory_types(types)) }
837 }
838
839 /// One allocation's external handle types under this allocator's lock.
840 /// # Errors
841 /// Same errors as `Allocator::external_memory_types`, plus SynchronizationPoisoned.
842 pub fn external_memory_types(
843 &self,
844 allocation: &Allocation,
845 ) -> Result<vk::ExternalMemoryHandleTypeFlags, AllocError> {
846 self.locked(|allocator| allocator.external_memory_types(allocation))
847 }
848
849 /// Run `Allocator::get_memory_fd` under this allocator's lock.
850 /// # Errors
851 /// Same checked/native errors as `Allocator::get_memory_fd`, plus SynchronizationPoisoned.
852 /// # Safety
853 /// Same external-memory and descriptor-ownership contract as `Allocator::get_memory_fd`.
854 #[cfg(unix)]
855 pub unsafe fn get_memory_fd(
856 &self,
857 allocation: &Allocation,
858 handle_type: vk::ExternalMemoryHandleTypeFlagBits,
859 ) -> Result<std::os::fd::RawFd, AllocError> {
860 // SAFETY: identical canonical operation contract.
861 unsafe { self.locked(|allocator| allocator.get_memory_fd(allocation, handle_type)) }
862 }
863
864 /// Run `Allocator::get_memory_win32_handle` under this allocator's lock.
865 /// # Errors
866 /// Same checked/native/OS errors as `Allocator::get_memory_win32_handle`, plus SynchronizationPoisoned.
867 /// # Safety
868 /// Same sharing, target-process and handle-closing contract as
869 /// `Allocator::get_memory_win32_handle`.
870 #[cfg(all(windows, feature = "platform-win32"))]
871 pub unsafe fn get_memory_win32_handle(
872 &self,
873 allocation: &Allocation,
874 handle_type: vk::ExternalMemoryHandleTypeFlagBits,
875 target_process: *mut std::ffi::c_void,
876 ) -> Result<vk::HANDLE, AllocError> {
877 // SAFETY: identical canonical operation contract.
878 unsafe {
879 self.locked(|allocator| {
880 allocator.get_memory_win32_handle(allocation, handle_type, target_process)
881 })
882 }
883 }
884
885 /// Run `Allocator::set_device_memory_callbacks` under this allocator's lock.
886 /// # Errors
887 /// Same errors as `Allocator::set_device_memory_callbacks`, plus SynchronizationPoisoned.
888 /// # Safety
889 /// Same retained-callback contract as `Allocator::set_device_memory_callbacks`;
890 /// callbacks must also satisfy `SynchronizedAllocator::new`'s any-thread rules.
891 pub unsafe fn set_device_memory_callbacks(
892 &self,
893 callbacks: Option<&'device DeviceMemoryCallbacks>,
894 ) -> Result<(), AllocError> {
895 // SAFETY: identical canonical operation contract.
896 unsafe { self.locked(|allocator| allocator.set_device_memory_callbacks(callbacks)) }
897 }
898}