/// Hints for allocator to decide on allocation strategy. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pubenum Dedicated { /// Allocation directly from device.\ /// Very slow. /// Count of allocations is limited.\ /// Use with caution.\ /// Must be used if resource has to be bound to dedicated memory object.
Required,
/// Hint for allocator that dedicated memory object is preferred.\ /// Should be used if it is known that resource placed in dedicated memory object /// would allow for better performance.\ /// Implementation is allowed to return block to shared memory object.
Preferred,
}
impl<M> GpuAllocator<M> where
M: MemoryBounds + 'static,
{ /// Creates new instance of `GpuAllocator`. /// Provided `DeviceProperties` should match properties of `MemoryDevice` that will be used /// with created `GpuAllocator` instance. #[cfg_attr(feature = "tracing", tracing::instrument)] pubfn new(config: Config, props: DeviceProperties<'_>) -> Self {
assert!(
props.non_coherent_atom_size.is_power_of_two(), "`non_coherent_atom_size` must be power of two"
);
assert!(
isize::try_from(props.non_coherent_atom_size).is_ok(), "`non_coherent_atom_size` must fit host address space"
);
/// Allocates memory block from specified `device` according to the `request`. /// /// # Safety /// /// * `device` must be one with `DeviceProperties` that were provided to create this `GpuAllocator` instance. /// * Same `device` instance must be used for all interactions with one `GpuAllocator` instance /// and memory blocks allocated from it. #[cfg_attr(feature = "tracing", tracing::instrument(skip(self, device)))] pubunsafefn alloc(
&mutself,
device: &impl MemoryDevice<M>,
request: Request,
) -> Result<MemoryBlock<M>, AllocationError> { self.alloc_internal(device, request, None)
}
/// Allocates memory block from specified `device` according to the `request`. /// This function allows user to force specific allocation strategy. /// Improper use can lead to suboptimal performance or too large overhead. /// Prefer `GpuAllocator::alloc` if doubt. /// /// # Safety /// /// * `device` must be one with `DeviceProperties` that were provided to create this `GpuAllocator` instance. /// * Same `device` instance must be used for all interactions with one `GpuAllocator` instance /// and memory blocks allocated from it. #[cfg_attr(feature = "tracing", tracing::instrument(skip(self, device)))] pubunsafefn alloc_with_dedicated(
&mutself,
device: &impl MemoryDevice<M>,
request: Request,
dedicated: Dedicated,
) -> Result<MemoryBlock<M>, AllocationError> { self.alloc_internal(device, request, Some(dedicated))
}
if request.usage.contains(UsageFlags::DEVICE_ADDRESS) {
assert!(self.buffer_device_address, "`DEVICE_ADDRESS` cannot be requested when `DeviceProperties::buffer_device_address` is false");
}
if request.size > self.max_memory_allocation_size { return Err(AllocationError::OutOfDeviceMemory);
}
/// Creates a memory block from an existing memory allocation, transferring ownership to the allocator. /// /// This function allows the [`GpuAllocator`] to manage memory allocated outside of the typical /// [`GpuAllocator::alloc`] family of functions. /// /// # Usage /// /// If you need to import external memory, such as a Win32 `HANDLE` or a Linux `dmabuf`, import the device /// memory using the graphics api and platform dependent functions. Once that is done, call this function /// to make the [`GpuAllocator`] take ownership of the imported memory. /// /// When calling this function, you **must** ensure there are [enough remaining allocations](GpuAllocator::remaining_allocations). /// /// # Safety /// /// - The `memory` must be allocated with the same device that was provided to create this [`GpuAllocator`] /// instance. /// - The `memory` must be valid. /// - The `props`, `offset` and `size` must match the properties, offset and size of the memory allocation. /// - The memory must have been allocated with the specified `memory_type`. /// - There must be enough remaining allocations. /// - The memory allocation must not come from an existing memory block created by this allocator. /// - The underlying memory object must be deallocated using the returned [`MemoryBlock`] with /// [`GpuAllocator::dealloc`]. pubunsafefn import_memory(
&mutself,
memory: M,
memory_type: u32,
props: MemoryPropertyFlags,
offset: u64,
size: u64,
) -> MemoryBlock<M> { // Get the heap which the imported memory is from. let heap = self
.memory_types
.get(memory_type as usize)
.expect("Invalid memory type specified when importing memory")
.heap; let heap = &mutself.memory_heaps[heap as usize];
assert_ne!( self.allocations_remains, 0, "Out of allocations when importing a memory block. Ensure you check GpuAllocator::remaining_allocations before import."
); self.allocations_remains -= 1;
let atom_mask = if host_visible_non_coherent(props) { self.non_coherent_atom_mask
} else { 0
};
/// Deallocates memory block previously allocated from this `GpuAllocator` instance. /// /// # Safety /// /// * Memory block must have been allocated by this `GpuAllocator` instance /// * `device` must be one with `DeviceProperties` that were provided to create this `GpuAllocator` instance /// * Same `device` instance must be used for all interactions with one `GpuAllocator` instance /// and memory blocks allocated from it #[cfg_attr(feature = "tracing", tracing::instrument(skip(self, device)))] pubunsafefn dealloc(&mutself, device: &impl MemoryDevice<M>, block: MemoryBlock<M>) { let memory_type = block.memory_type(); let offset = block.offset(); let size = block.size(); let flavor = block.deallocate(); match flavor {
MemoryBlockFlavor::Dedicated { memory } => { let heap = self.memory_types[memory_type as usize].heap;
device.deallocate_memory(memory); self.allocations_remains += 1; self.memory_heaps[heap as usize].dealloc(size);
}
MemoryBlockFlavor::Buddy {
chunk,
ptr,
index,
memory,
} => { let heap = self.memory_types[memory_type as usize].heap; let heap = &mutself.memory_heaps[heap as usize];
let allocator = self.buddy_allocators[memory_type as usize]
.as_mut()
.expect("Allocator should exist");
allocator.dealloc(
device,
BuddyBlock {
memory,
ptr,
offset,
size,
chunk,
index,
},
heap,
&mutself.allocations_remains,
);
}
MemoryBlockFlavor::FreeList { chunk, ptr, memory } => { let heap = self.memory_types[memory_type as usize].heap; let heap = &mutself.memory_heaps[heap as usize];
let allocator = self.freelist_allocators[memory_type as usize]
.as_mut()
.expect("Allocator should exist");
/// Returns the maximum allocation size supported. pubfn max_allocation_size(&self) -> u64 { self.max_memory_allocation_size
}
/// Returns the number of remaining available allocations. /// /// This may be useful if you need know if the allocator can allocate a number of allocations ahead of /// time. This function is also useful for ensuring you do not allocate too much memory outside allocator /// (such as external memory). pubfn remaining_allocations(&self) -> u32 { self.allocations_remains
}
/// Sets the number of remaining available allocations. /// /// # Safety /// /// The caller is responsible for ensuring the number of remaining allocations does not exceed how many /// remaining allocations there actually are on the memory device. pubunsafefn set_remaining_allocations(&mutself, remaining: u32) { self.allocations_remains = remaining;
}
/// Deallocates leftover memory objects. /// Should be used before dropping. /// /// # Safety /// /// * `device` must be one with `DeviceProperties` that were provided to create this `GpuAllocator` instance /// * Same `device` instance must be used for all interactions with one `GpuAllocator` instance /// and memory blocks allocated from it #[cfg_attr(feature = "tracing", tracing::instrument(skip(self, device)))] pubunsafefn cleanup(&mutself, device: &impl MemoryDevice<M>) { for (index, allocator) inself
.freelist_allocators
.iter_mut()
.enumerate()
.filter_map(|(index, allocator)| Some((index, allocator.as_mut()?)))
{ let memory_type = &self.memory_types[index]; let heap = memory_type.heap; let heap = &mutself.memory_heaps[heap as usize];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.