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