1 mod heap; 2 mod memory_type; 3 4 use self::{ 5 heap::MemoryHeap, 6 memory_type::{BlockFlavor, MemoryType}, 7 }; 8 use crate::{ 9 allocator::*, block::Block, mapping::MappedRange, stats::TotalMemoryUtilization, 10 usage::MemoryUsage, Size, 11 }; 12 13 /// Possible errors returned by `Heaps`. 14 #[derive(Clone, Debug, PartialEq)] 15 pub enum HeapsError { 16 /// Memory allocation failure. 17 AllocationError(hal::device::AllocationError), 18 /// No memory types among required for resource with requested properties was found. 19 NoSuitableMemory(u32, hal::memory::Properties), 20 } 21 22 impl std::fmt::Display for HeapsError { fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 24 match self { 25 HeapsError::AllocationError(e) => write!(f, "{:?}", e), 26 HeapsError::NoSuitableMemory(e, e2) => write!( 27 f, 28 "Memory type among ({}) with properties ({:?}) not found", 29 e, e2 30 ), 31 } 32 } 33 } 34 impl std::error::Error for HeapsError { source(&self) -> Option<&(dyn std::error::Error + 'static)>35 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 36 match *self { 37 HeapsError::AllocationError(ref err) => Some(err), 38 HeapsError::NoSuitableMemory(..) => None, 39 } 40 } 41 } 42 43 impl From<hal::device::AllocationError> for HeapsError { from(error: hal::device::AllocationError) -> Self44 fn from(error: hal::device::AllocationError) -> Self { 45 HeapsError::AllocationError(error) 46 } 47 } 48 49 impl From<hal::device::OutOfMemory> for HeapsError { from(error: hal::device::OutOfMemory) -> Self50 fn from(error: hal::device::OutOfMemory) -> Self { 51 HeapsError::AllocationError(error.into()) 52 } 53 } 54 55 /// Heaps available on particular physical device. 56 #[derive(Debug)] 57 pub struct Heaps<B: hal::Backend> { 58 types: Vec<MemoryType<B>>, 59 heaps: Vec<MemoryHeap>, 60 } 61 62 impl<B: hal::Backend> Heaps<B> { 63 /// Initialize the new `Heaps` object. new( hal_memory_properties: &hal::adapter::MemoryProperties, config_general: GeneralConfig, config_linear: LinearConfig, non_coherent_atom_size: Size, ) -> Self64 pub unsafe fn new( 65 hal_memory_properties: &hal::adapter::MemoryProperties, 66 config_general: GeneralConfig, 67 config_linear: LinearConfig, 68 non_coherent_atom_size: Size, 69 ) -> Self { 70 Heaps { 71 types: hal_memory_properties.memory_types 72 .iter() 73 .enumerate() 74 .map(|(index, mt)| { 75 assert!(mt.heap_index < hal_memory_properties.memory_heaps.len()); 76 MemoryType::new( 77 hal::MemoryTypeId(index), 78 mt, 79 &config_general, 80 &config_linear, 81 non_coherent_atom_size, 82 ) 83 }) 84 .collect(), 85 heaps: hal_memory_properties.memory_heaps 86 .iter() 87 .map(|&size| MemoryHeap::new(size)) 88 .collect(), 89 } 90 } 91 92 /// Allocate memory block 93 /// from one of memory types specified by `mask`, 94 /// for intended `usage`, 95 /// with `size` 96 /// and `align` requirements. allocate( &mut self, device: &B::Device, mask: u32, usage: MemoryUsage, kind: Kind, size: Size, align: Size, ) -> Result<MemoryBlock<B>, HeapsError>97 pub fn allocate( 98 &mut self, 99 device: &B::Device, 100 mask: u32, 101 usage: MemoryUsage, 102 kind: Kind, 103 size: Size, 104 align: Size, 105 ) -> Result<MemoryBlock<B>, HeapsError> { 106 let (memory_index, _, _) = { 107 let suitable_types = self 108 .types 109 .iter() 110 .enumerate() 111 .filter(|(index, _)| (mask & (1u32 << index)) != 0) 112 .filter_map(|(index, mt)| { 113 if mt.properties().contains(usage.properties_required()) { 114 let fitness = usage.memory_fitness(mt.properties()); 115 Some((index, mt, fitness)) 116 } else { 117 None 118 } 119 }); 120 121 if suitable_types.clone().next().is_none() { 122 return Err(HeapsError::NoSuitableMemory( 123 mask, 124 usage.properties_required(), 125 )); 126 } 127 128 suitable_types 129 .filter(|(_, mt, _)| self.heaps[mt.heap_index()].available() > size + align) 130 .max_by_key(|&(_, _, fitness)| fitness) 131 .ok_or_else(|| { 132 log::error!("All suitable heaps are exhausted. {:#?}", self); 133 hal::device::OutOfMemory::Device 134 })? 135 }; 136 137 self.allocate_from(device, memory_index as u32, kind, size, align) 138 } 139 140 /// Allocate memory block 141 /// from `memory_index` specified, 142 /// for intended `usage`, 143 /// with `size` 144 /// and `align` requirements. allocate_from( &mut self, device: &B::Device, memory_index: u32, kind: Kind, size: Size, align: Size, ) -> Result<MemoryBlock<B>, HeapsError>145 fn allocate_from( 146 &mut self, 147 device: &B::Device, 148 memory_index: u32, 149 kind: Kind, 150 size: Size, 151 align: Size, 152 ) -> Result<MemoryBlock<B>, HeapsError> { 153 log::trace!( 154 "Allocate memory block: type '{}', kind '{:?}', size: '{}', align: '{}'", 155 memory_index, 156 kind, 157 size, 158 align 159 ); 160 161 let ref mut memory_type = self.types[memory_index as usize]; 162 let ref mut memory_heap = self.heaps[memory_type.heap_index()]; 163 164 if memory_heap.available() < size { 165 return Err(hal::device::OutOfMemory::Device.into()); 166 } 167 168 let (flavor, allocated) = match memory_type.alloc(device, kind, size, align) { 169 Ok(mapping) => mapping, 170 Err(e) if kind == Kind::Linear => { 171 log::warn!("Unable to allocate {:?} with {:?}: {:?}", size, kind, e); 172 memory_type.alloc(device, Kind::Dedicated, size, align)? 173 } 174 Err(e) => return Err(e.into()), 175 }; 176 memory_heap.allocated(allocated, flavor.size()); 177 178 Ok(MemoryBlock { 179 flavor, 180 memory_index, 181 }) 182 } 183 184 /// Free memory block. 185 /// 186 /// Memory block must be allocated from this heap. free(&mut self, device: &B::Device, block: MemoryBlock<B>)187 pub fn free(&mut self, device: &B::Device, block: MemoryBlock<B>) { 188 let memory_index = block.memory_index; 189 let size = block.flavor.size(); 190 log::trace!( 191 "Free memory block: type '{}', size: '{}'", 192 memory_index, 193 size, 194 ); 195 196 let ref mut memory_type = self.types[memory_index as usize]; 197 let ref mut memory_heap = self.heaps[memory_type.heap_index()]; 198 let freed = memory_type.free(device, block.flavor); 199 memory_heap.freed(freed, size); 200 } 201 202 /// Clear allocators before dropping. 203 /// Will panic if memory instances are left allocated. clear(&mut self, device: &B::Device)204 pub fn clear(&mut self, device: &B::Device) { 205 for mut mt in self.types.drain(..) { 206 mt.clear(device) 207 } 208 } 209 210 /// Get memory utilization. utilization(&self) -> TotalMemoryUtilization211 pub fn utilization(&self) -> TotalMemoryUtilization { 212 TotalMemoryUtilization { 213 heaps: self.heaps.iter().map(MemoryHeap::utilization).collect(), 214 types: self.types.iter().map(MemoryType::utilization).collect(), 215 } 216 } 217 } 218 219 impl<B: hal::Backend> Drop for Heaps<B> { drop(&mut self)220 fn drop(&mut self) { 221 if !self.types.is_empty() { 222 log::error!("Heaps still have {:?} types live on drop", self.types.len()); 223 } 224 } 225 } 226 227 /// Memory block allocated from `Heaps`. 228 #[derive(Debug)] 229 pub struct MemoryBlock<B: hal::Backend> { 230 flavor: BlockFlavor<B>, 231 memory_index: u32, 232 } 233 234 impl<B: hal::Backend> MemoryBlock<B> { 235 /// Get memory type id. memory_type(&self) -> u32236 pub fn memory_type(&self) -> u32 { 237 self.memory_index 238 } 239 } 240 241 impl<B: hal::Backend> Block<B> for MemoryBlock<B> { properties(&self) -> hal::memory::Properties242 fn properties(&self) -> hal::memory::Properties { 243 match self.flavor { 244 BlockFlavor::Dedicated(ref block) => block.properties(), 245 BlockFlavor::General(ref block) => block.properties(), 246 BlockFlavor::Linear(ref block) => block.properties(), 247 } 248 } 249 memory(&self) -> &B::Memory250 fn memory(&self) -> &B::Memory { 251 match self.flavor { 252 BlockFlavor::Dedicated(ref block) => block.memory(), 253 BlockFlavor::General(ref block) => block.memory(), 254 BlockFlavor::Linear(ref block) => block.memory(), 255 } 256 } 257 segment(&self) -> hal::memory::Segment258 fn segment(&self) -> hal::memory::Segment { 259 match self.flavor { 260 BlockFlavor::Dedicated(ref block) => block.segment(), 261 BlockFlavor::General(ref block) => block.segment(), 262 BlockFlavor::Linear(ref block) => block.segment(), 263 } 264 } 265 map<'a>( &'a mut self, device: &B::Device, segment: hal::memory::Segment, ) -> Result<MappedRange<'a, B>, hal::device::MapError>266 fn map<'a>( 267 &'a mut self, 268 device: &B::Device, 269 segment: hal::memory::Segment, 270 ) -> Result<MappedRange<'a, B>, hal::device::MapError> { 271 match self.flavor { 272 BlockFlavor::Dedicated(ref mut block) => block.map(device, segment), 273 BlockFlavor::General(ref mut block) => block.map(device, segment), 274 BlockFlavor::Linear(ref mut block) => block.map(device, segment), 275 } 276 } 277 } 278