diff --git a/README.md b/README.md index d6faf411..e3fbffce 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ let mut allocator = Allocator::new(&AllocatorCreateDesc { physical_device, debug_settings: Default::default(), buffer_device_address: true, // Ideally, check the BufferDeviceAddressFeatures struct. + allocation_sizes: Default::default(), }); ``` @@ -78,6 +79,7 @@ use gpu_allocator::d3d12::*; let mut allocator = Allocator::new(&AllocatorCreateDesc { device, debug_settings: Default::default(), + allocation_sizes: Default::default(), }); ``` diff --git a/examples/d3d12-buffer-winrs.rs b/examples/d3d12-buffer-winrs.rs index 423b38ab..deb7d94d 100644 --- a/examples/d3d12-buffer-winrs.rs +++ b/examples/d3d12-buffer-winrs.rs @@ -90,6 +90,7 @@ fn main() -> Result<()> { let mut allocator = Allocator::new(&AllocatorCreateDesc { device: device.clone(), debug_settings: Default::default(), + allocation_sizes: Default::default(), }) .unwrap(); diff --git a/examples/d3d12-buffer.rs b/examples/d3d12-buffer.rs index 26bb9b67..bd9ff2df 100644 --- a/examples/d3d12-buffer.rs +++ b/examples/d3d12-buffer.rs @@ -119,6 +119,7 @@ fn main() { let mut allocator = Allocator::new(&AllocatorCreateDesc { device: device.as_windows().clone(), debug_settings: Default::default(), + allocation_sizes: Default::default(), }) .unwrap(); diff --git a/examples/d3d12-visualization/main.rs b/examples/d3d12-visualization/main.rs index e9bb1849..a364a786 100644 --- a/examples/d3d12-visualization/main.rs +++ b/examples/d3d12-visualization/main.rs @@ -358,6 +358,7 @@ fn main() { let mut allocator = Allocator::new(&AllocatorCreateDesc { device: device.as_windows().clone(), debug_settings: Default::default(), + allocation_sizes: Default::default(), }) .unwrap(); diff --git a/examples/vulkan-buffer.rs b/examples/vulkan-buffer.rs index 3a5e3762..b2175de9 100644 --- a/examples/vulkan-buffer.rs +++ b/examples/vulkan-buffer.rs @@ -98,6 +98,7 @@ fn main() { physical_device: pdevice, debug_settings: Default::default(), buffer_device_address: false, + allocation_sizes: Default::default(), }) .unwrap(); diff --git a/examples/vulkan-visualization/main.rs b/examples/vulkan-visualization/main.rs index de3cc42e..652a11d2 100644 --- a/examples/vulkan-visualization/main.rs +++ b/examples/vulkan-visualization/main.rs @@ -231,6 +231,7 @@ fn main() -> ash::prelude::VkResult<()> { physical_device: pdevice, debug_settings: Default::default(), buffer_device_address: false, + allocation_sizes: Default::default(), }) .unwrap(), ); diff --git a/src/d3d12/mod.rs b/src/d3d12/mod.rs index b02216ba..2a77b603 100644 --- a/src/d3d12/mod.rs +++ b/src/d3d12/mod.rs @@ -85,7 +85,8 @@ use super::allocator; use super::allocator::AllocationType; use crate::{ - allocator::fmt_bytes, AllocationError, AllocatorDebugSettings, MemoryLocation, Result, + allocator::fmt_bytes, AllocationError, AllocationSizes, AllocatorDebugSettings, MemoryLocation, + Result, }; /// [`ResourceCategory`] is used for supporting [`D3D12_RESOURCE_HEAP_TIER_1`]. @@ -231,6 +232,7 @@ impl<'a> AllocationCreateDesc<'a> { pub struct AllocatorCreateDesc { pub device: ID3D12Device, pub debug_settings: AllocatorDebugSettings, + pub allocation_sizes: AllocationSizes, } pub enum ResourceType<'a> { @@ -386,21 +388,20 @@ struct MemoryType { active_general_blocks: usize, } -const DEFAULT_DEVICE_MEMBLOCK_SIZE: u64 = 256 * 1024 * 1024; -const DEFAULT_HOST_MEMBLOCK_SIZE: u64 = 64 * 1024 * 1024; impl MemoryType { fn allocate( &mut self, device: &ID3D12Device, desc: &AllocationCreateDesc<'_>, backtrace: Option, + allocation_sizes: &AllocationSizes, ) -> Result { let allocation_type = AllocationType::Linear; let memblock_size = if self.heap_properties.Type == D3D12_HEAP_TYPE_DEFAULT { - DEFAULT_DEVICE_MEMBLOCK_SIZE + allocation_sizes.device_memblock_size } else { - DEFAULT_HOST_MEMBLOCK_SIZE + allocation_sizes.host_memblock_size }; let size = desc.size; @@ -573,6 +574,7 @@ pub struct Allocator { device: ID3D12Device, debug_settings: AllocatorDebugSettings, memory_types: Vec, + allocation_sizes: AllocationSizes, } impl Allocator { @@ -679,6 +681,7 @@ impl Allocator { memory_types, device, debug_settings: desc.debug_settings, + allocation_sizes: desc.allocation_sizes, }) } @@ -722,7 +725,7 @@ impl Allocator { }) .ok_or(AllocationError::NoCompatibleMemoryTypeFound)?; - memory_type.allocate(&self.device, desc, backtrace) + memory_type.allocate(&self.device, desc, backtrace, &self.allocation_sizes) } pub fn free(&mut self, allocation: Allocation) -> Result<()> { diff --git a/src/lib.rs b/src/lib.rs index 04096d20..f23acc94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ //! physical_device, //! debug_settings: Default::default(), //! buffer_device_address: true, // Ideally, check the BufferDeviceAddressFeatures struct. +//! allocation_sizes: Default::default(), //! }); //! # } //! # #[cfg(not(feature = "vulkan"))] @@ -48,6 +49,7 @@ //! # physical_device, //! # debug_settings: Default::default(), //! # buffer_device_address: true, // Ideally, check the BufferDeviceAddressFeatures struct. +//! # allocation_sizes: Default::default(), //! # }).unwrap(); //! //! // Setup vulkan info @@ -89,6 +91,7 @@ //! let mut allocator = Allocator::new(&AllocatorCreateDesc { //! device, //! debug_settings: Default::default(), +//! allocation_sizes: Default::default(), //! }); //! # } //! # #[cfg(not(feature = "d3d12"))] @@ -108,6 +111,7 @@ //! # let mut allocator = Allocator::new(&AllocatorCreateDesc { //! # device: device, //! # debug_settings: Default::default(), +//! # allocation_sizes: Default::default(), //! # }).unwrap(); //! //! let buffer_desc = Direct3D12::D3D12_RESOURCE_DESC { @@ -210,3 +214,58 @@ impl Default for AllocatorDebugSettings { } } } + +/// 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, + } + } +} diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index 2d0760a8..be90c930 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -13,7 +13,8 @@ use log::{debug, Level}; use std::fmt; use crate::{ - allocator::fmt_bytes, AllocationError, AllocatorDebugSettings, MemoryLocation, Result, + allocator::fmt_bytes, AllocationError, AllocationSizes, AllocatorDebugSettings, MemoryLocation, + Result, }; #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -61,6 +62,7 @@ pub struct AllocatorCreateDesc { pub physical_device: ash::vk::PhysicalDevice, pub debug_settings: AllocatorDebugSettings, pub buffer_device_address: bool, + pub allocation_sizes: AllocationSizes, } /// A piece of allocated memory. @@ -441,9 +443,6 @@ pub(crate) struct MemoryType { pub(crate) buffer_device_address: bool, } -const DEFAULT_DEVICE_MEMBLOCK_SIZE: u64 = 256 * 1024 * 1024; -const DEFAULT_HOST_MEMBLOCK_SIZE: u64 = 64 * 1024 * 1024; - impl MemoryType { fn allocate( &mut self, @@ -451,6 +450,7 @@ impl MemoryType { desc: &AllocationCreateDesc<'_>, granularity: u64, backtrace: Option, + allocation_sizes: &AllocationSizes, ) -> Result { let allocation_type = if desc.linear { AllocationType::Linear @@ -462,9 +462,9 @@ impl MemoryType { .memory_properties .contains(vk::MemoryPropertyFlags::HOST_VISIBLE) { - DEFAULT_HOST_MEMBLOCK_SIZE + allocation_sizes.host_memblock_size } else { - DEFAULT_DEVICE_MEMBLOCK_SIZE + allocation_sizes.device_memblock_size }; let size = desc.requirements.size; @@ -677,6 +677,7 @@ pub struct Allocator { device: ash::Device, pub(crate) buffer_image_granularity: u64, pub(crate) debug_settings: AllocatorDebugSettings, + allocation_sizes: AllocationSizes, } impl fmt::Debug for Allocator { @@ -793,6 +794,7 @@ impl Allocator { device: desc.device.clone(), buffer_image_granularity: granularity, debug_settings: desc.debug_settings, + allocation_sizes: AllocationSizes::default(), }) } @@ -866,6 +868,7 @@ impl Allocator { desc, self.buffer_image_granularity, backtrace.clone(), + &self.allocation_sizes, ) }; @@ -887,6 +890,7 @@ impl Allocator { desc, self.buffer_image_granularity, backtrace, + &self.allocation_sizes, ) } else { allocation