//! This crate provides a fully written in Rust memory allocator for Vulkan and DirectX 12. //! //! # [Windows-rs] and [winapi] //! //! `gpu-allocator` recently migrated from [winapi] to [windows-rs] but still provides convenient helpers to convert to and from [winapi] types, enabled when compiling with the `public-winapi` crate feature. //! //! [Windows-rs]: https://github.com/microsoft/windows-rs //! [winapi]: https://github.com/retep998/winapi-rs //! //! # Setting up the Vulkan memory allocator //! //! ```no_run //! # #[cfg(feature = "vulkan")] //! # fn main() { //! use gpu_allocator::vulkan::*; //! # use ash::vk; //! # let device = todo!(); //! # let instance = todo!(); //! # let physical_device = todo!(); //! //! let mut allocator = Allocator::new(&AllocatorCreateDesc { //! instance, //! device, //! physical_device, //! debug_settings: Default::default(), //! buffer_device_address: true, // Ideally, check the BufferDeviceAddressFeatures struct. //! allocation_sizes: Default::default(), //! }); //! # } //! # #[cfg(not(feature = "vulkan"))] //! # fn main() {} //! ``` //! //! # Simple Vulkan allocation example //! //! ```no_run //! # #[cfg(feature = "vulkan")] //! # fn main() { //! use gpu_allocator::vulkan::*; //! use gpu_allocator::MemoryLocation; //! # use ash::vk; //! # let device = todo!(); //! # let instance = todo!(); //! # let physical_device = todo!(); //! # let mut allocator = Allocator::new(&AllocatorCreateDesc { //! # instance, //! # device, //! # physical_device, //! # debug_settings: Default::default(), //! # buffer_device_address: true, // Ideally, check the BufferDeviceAddressFeatures struct. //! # allocation_sizes: Default::default(), //! # }).unwrap(); //! //! // Setup vulkan info //! let vk_info = vk::BufferCreateInfo::builder() //! .size(512) //! .usage(vk::BufferUsageFlags::STORAGE_BUFFER); //! //! let buffer = unsafe { device.create_buffer(&vk_info, None) }.unwrap(); //! let requirements = unsafe { device.get_buffer_memory_requirements(buffer) }; //! //! let allocation = allocator //! .allocate(&AllocationCreateDesc { //! name: "Example allocation", //! requirements, //! location: MemoryLocation::CpuToGpu, //! linear: true, // Buffers are always linear //! allocation_scheme: AllocationScheme::GpuAllocatorManaged, //! }).unwrap(); //! //! // Bind memory to the buffer //! unsafe { device.bind_buffer_memory(buffer, allocation.memory(), allocation.offset()).unwrap() }; //! //! // Cleanup //! allocator.free(allocation).unwrap(); //! unsafe { device.destroy_buffer(buffer, None) }; //! # } //! # #[cfg(not(feature = "vulkan"))] //! # fn main() {} //! ``` //! //! # Setting up the D3D12 memory allocator //! //! ```no_run //! # #[cfg(feature = "d3d12")] //! # fn main() { //! use gpu_allocator::d3d12::*; //! # let device = todo!(); //! //! let mut allocator = Allocator::new(&AllocatorCreateDesc { //! device: ID3D12DeviceVersion::Device(device), //! debug_settings: Default::default(), //! allocation_sizes: Default::default(), //! }); //! # } //! # #[cfg(not(feature = "d3d12"))] //! # fn main() {} //! ``` //! //! # Simple d3d12 allocation example //! //! ```no_run //! # #[cfg(feature = "d3d12")] //! # fn main() -> windows::core::Result<()> { //! use gpu_allocator::d3d12::*; //! use gpu_allocator::MemoryLocation; //! # use windows::Win32::Graphics::{Dxgi, Direct3D12}; //! # let device = todo!(); //! //! # let mut allocator = Allocator::new(&AllocatorCreateDesc { //! # device: ID3D12DeviceVersion::Device(device), //! # debug_settings: Default::default(), //! # allocation_sizes: Default::default(), //! # }).unwrap(); //! //! let buffer_desc = Direct3D12::D3D12_RESOURCE_DESC { //! Dimension: Direct3D12::D3D12_RESOURCE_DIMENSION_BUFFER, //! Alignment: 0, //! Width: 512, //! Height: 1, //! DepthOrArraySize: 1, //! MipLevels: 1, //! Format: Dxgi::Common::DXGI_FORMAT_UNKNOWN, //! SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC { //! Count: 1, //! Quality: 0, //! }, //! Layout: Direct3D12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, //! Flags: Direct3D12::D3D12_RESOURCE_FLAG_NONE, //! }; //! let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc( //! &allocator.device(), //! &buffer_desc, //! "Example allocation", //! MemoryLocation::GpuOnly, //! ); //! let allocation = allocator.allocate(&allocation_desc).unwrap(); //! let mut resource: Option = None; //! let hr = unsafe { //! device.CreatePlacedResource( //! allocation.heap(), //! allocation.offset(), //! &buffer_desc, //! Direct3D12::D3D12_RESOURCE_STATE_COMMON, //! None, //! &mut resource, //! ) //! }?; //! //! // Cleanup //! drop(resource); //! allocator.free(allocation).unwrap(); //! # Ok(()) //! # } //! # #[cfg(not(feature = "d3d12"))] //! # fn main() {} //! ``` mod result; pub use result::*; pub(crate) mod allocator; #[cfg(feature = "visualizer")] pub mod visualizer; #[cfg(feature = "vulkan")] pub mod vulkan; #[cfg(all(windows, feature = "d3d12"))] pub mod d3d12; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum MemoryLocation { /// The allocated resource is stored at an unknown memory location; let the driver decide what's the best location Unknown, /// Store the allocation in GPU only accessible memory - typically this is the faster GPU resource and this should be /// where most of the allocations live. GpuOnly, /// Memory useful for uploading data to the GPU and potentially for constant buffers CpuToGpu, /// Memory useful for CPU readback of data GpuToCpu, } #[derive(Copy, Clone, Debug)] pub struct AllocatorDebugSettings { /// Logs out debugging information about the various heaps the current device has on startup pub log_memory_information: bool, /// Logs out all memory leaks on shutdown with log level Warn pub log_leaks_on_shutdown: bool, /// Stores a copy of the full backtrace for every allocation made, this makes it easier to debug leaks /// or other memory allocations, but storing stack traces has a RAM overhead so should be disabled /// in shipping applications. pub store_stack_traces: bool, /// Log out every allocation as it's being made with log level Debug, rather spammy so off by default pub log_allocations: bool, /// Log out every free that is being called with log level Debug, rather spammy so off by default pub log_frees: bool, /// Log out stack traces when either `log_allocations` or `log_frees` is enabled. pub log_stack_traces: bool, } impl Default for AllocatorDebugSettings { fn default() -> Self { Self { log_memory_information: false, log_leaks_on_shutdown: true, store_stack_traces: false, log_allocations: false, log_frees: false, log_stack_traces: false, } } } /// The sizes of the memory blocks that the allocator will create. /// /// Useful for tuning the allocator to your application's needs. For example most games will be fine with the default /// values, but eg. an app might want to use smaller block sizes to reduce the amount of memory used. /// /// Clamped between 4MB and 256MB, and rounds up to the nearest multiple of 4MB for alignment reasons. #[derive(Clone, Copy, Debug)] pub struct AllocationSizes { /// The size of the memory blocks that will be created for the GPU only memory type. /// /// Defaults to 256MB. device_memblock_size: u64, /// The size of the memory blocks that will be created for the CPU visible memory types. /// /// Defaults to 64MB. host_memblock_size: u64, } impl AllocationSizes { pub fn new(device_memblock_size: u64, host_memblock_size: u64) -> Self { const FOUR_MB: u64 = 4 * 1024 * 1024; const TWO_HUNDRED_AND_FIFTY_SIX_MB: u64 = 256 * 1024 * 1024; let mut device_memblock_size = device_memblock_size.clamp(FOUR_MB, TWO_HUNDRED_AND_FIFTY_SIX_MB); let mut host_memblock_size = host_memblock_size.clamp(FOUR_MB, TWO_HUNDRED_AND_FIFTY_SIX_MB); if device_memblock_size % FOUR_MB != 0 { let val = device_memblock_size / FOUR_MB + 1; device_memblock_size = val * FOUR_MB; log::warn!( "Device memory block size must be a multiple of 4MB, clamping to {}MB", device_memblock_size / 1024 / 1024 ) } if host_memblock_size % FOUR_MB != 0 { let val = host_memblock_size / FOUR_MB + 1; host_memblock_size = val * FOUR_MB; log::warn!( "Host memory block size must be a multiple of 4MB, clamping to {}MB", host_memblock_size / 1024 / 1024 ) } Self { device_memblock_size, host_memblock_size, } } } impl Default for AllocationSizes { fn default() -> Self { Self { device_memblock_size: 256 * 1024 * 1024, host_memblock_size: 64 * 1024 * 1024, } } }