1mod heap;
2mod memory_type;
3
4use {
5 self::{heap::MemoryHeap, memory_type::MemoryType},
6 crate::{allocator::*, block::Block, mapping::*, usage::MemoryUsage, util::*, utilization::*},
7 std::ops::Range,
8};
9
10#[allow(missing_copy_implementations)]
12#[derive(Clone, Debug, PartialEq)]
13pub enum HeapsError {
14 AllocationError(gfx_hal::device::AllocationError),
16 NoSuitableMemory(u32, gfx_hal::memory::Properties),
18}
19
20impl std::fmt::Display for HeapsError {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 match self {
23 HeapsError::AllocationError(e) => write!(f, "{:?}", e),
24 HeapsError::NoSuitableMemory(e, e2) => write!(
25 f,
26 "Memory type among ({}) with properties ({:?}) not found",
27 e, e2
28 ),
29 }
30 }
31}
32impl std::error::Error for HeapsError {}
33
34impl From<gfx_hal::device::AllocationError> for HeapsError {
35 fn from(error: gfx_hal::device::AllocationError) -> Self {
36 HeapsError::AllocationError(error)
37 }
38}
39
40impl From<gfx_hal::device::OutOfMemory> for HeapsError {
41 fn from(error: gfx_hal::device::OutOfMemory) -> Self {
42 HeapsError::AllocationError(error.into())
43 }
44}
45
46#[derive(Clone, Copy, Debug)]
48#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
49pub struct HeapsConfig {
50 pub linear: Option<LinearConfig>,
52
53 pub dynamic: Option<DynamicConfig>,
55}
56
57#[derive(Debug)]
59pub struct Heaps<B: gfx_hal::Backend> {
60 types: Vec<MemoryType<B>>,
61 heaps: Vec<MemoryHeap>,
62}
63
64impl<B> Heaps<B>
65where
66 B: gfx_hal::Backend,
67{
68 pub unsafe fn new<P, H>(types: P, heaps: H) -> Self
70 where
71 P: IntoIterator<Item = (gfx_hal::memory::Properties, u32, HeapsConfig)>,
72 H: IntoIterator<Item = u64>,
73 {
74 let heaps = heaps
75 .into_iter()
76 .map(|size| MemoryHeap::new(size))
77 .collect::<Vec<_>>();
78 Heaps {
79 types: types
80 .into_iter()
81 .enumerate()
82 .map(|(index, (properties, heap_index, config))| {
83 assert!(
84 fits_u32(index),
85 "Number of memory types must fit in u32 limit"
86 );
87 assert!(
88 fits_usize(heap_index),
89 "Number of memory types must fit in u32 limit"
90 );
91 let memory_type = gfx_hal::MemoryTypeId(index);
92 let heap_index = heap_index as usize;
93 assert!(heap_index < heaps.len());
94 MemoryType::new(memory_type, heap_index, properties, config)
95 })
96 .collect(),
97 heaps,
98 }
99 }
100
101 pub fn allocate(
107 &mut self,
108 device: &B::Device,
109 mask: u32,
110 usage: impl MemoryUsage,
111 size: u64,
112 align: u64,
113 ) -> Result<MemoryBlock<B>, HeapsError> {
114 debug_assert!(fits_u32(self.types.len()));
115
116 let (memory_index, _, _) = {
117 let suitable_types = self
118 .types
119 .iter()
120 .enumerate()
121 .filter(|(index, _)| (mask & (1u32 << index)) != 0)
122 .filter_map(|(index, mt)| {
123 if mt.properties().contains(usage.properties_required()) {
124 let fitness = usage.memory_fitness(mt.properties());
125 Some((index, mt, fitness))
126 } else {
127 None
128 }
129 })
130 .collect::<smallvec::SmallVec<[_; 64]>>();
131
132 if suitable_types.is_empty() {
133 return Err(HeapsError::NoSuitableMemory(
134 mask,
135 usage.properties_required(),
136 ));
137 }
138
139 suitable_types
140 .into_iter()
141 .filter(|(_, mt, _)| self.heaps[mt.heap_index()].available() > size + align)
142 .max_by_key(|&(_, _, fitness)| fitness)
143 .ok_or_else(|| {
144 log::error!("All suitable heaps are exhausted. {:#?}", self);
145 gfx_hal::device::OutOfMemory::Device
146 })?
147 };
148
149 self.allocate_from(device, memory_index as u32, usage, size, align)
150 }
151
152 fn allocate_from(
158 &mut self,
159 device: &B::Device,
160 memory_index: u32,
161 usage: impl MemoryUsage,
162 size: u64,
163 align: u64,
164 ) -> Result<MemoryBlock<B>, HeapsError> {
165 log::trace!(
166 "Allocate memory block: type '{}', usage '{:#?}', size: '{}', align: '{}'",
167 memory_index,
168 usage,
169 size,
170 align
171 );
172 assert!(fits_usize(memory_index));
173
174 let ref mut memory_type = self.types[memory_index as usize];
175 let ref mut memory_heap = self.heaps[memory_type.heap_index()];
176
177 if memory_heap.available() < size {
178 return Err(gfx_hal::device::OutOfMemory::Device.into());
179 }
180
181 let (block, allocated) = memory_type.alloc(device, usage, size, align)?;
182 memory_heap.allocated(allocated, block.size());
183
184 Ok(MemoryBlock {
185 block,
186 memory_index,
187 })
188 }
189
190 pub fn free(&mut self, device: &B::Device, block: MemoryBlock<B>) {
194 let memory_index = block.memory_index;
196 debug_assert!(fits_usize(memory_index));
197 let size = block.size();
198
199 let ref mut memory_type = self.types[memory_index as usize];
200 let ref mut memory_heap = self.heaps[memory_type.heap_index()];
201 let freed = memory_type.free(device, block.block);
202 memory_heap.freed(freed, size);
203 }
204
205 pub fn dispose(self, device: &B::Device) {
209 for mt in self.types {
210 mt.dispose(device)
211 }
212 }
213
214 pub fn utilization(&self) -> TotalMemoryUtilization {
216 TotalMemoryUtilization {
217 heaps: self.heaps.iter().map(MemoryHeap::utilization).collect(),
218 types: self.types.iter().map(MemoryType::utilization).collect(),
219 }
220 }
221}
222
223#[derive(Debug)]
225pub struct MemoryBlock<B: gfx_hal::Backend> {
226 block: BlockFlavor<B>,
227 memory_index: u32,
228}
229
230impl<B> MemoryBlock<B>
231where
232 B: gfx_hal::Backend,
233{
234 pub fn memory_type(&self) -> u32 {
236 self.memory_index
237 }
238}
239
240#[derive(Debug)]
241enum BlockFlavor<B: gfx_hal::Backend> {
242 Dedicated(DedicatedBlock<B>),
243 Linear(LinearBlock<B>),
244 Dynamic(DynamicBlock<B>),
245 }
247
248macro_rules! any_block {
249 ($self:ident. $block:ident => $expr:expr) => {{
250 use self::BlockFlavor::*;
251 match $self.$block {
252 Dedicated($block) => $expr,
253 Linear($block) => $expr,
254 Dynamic($block) => $expr,
255 }
257 }};
258 (& $self:ident. $block:ident => $expr:expr) => {{
259 use self::BlockFlavor::*;
260 match &$self.$block {
261 Dedicated($block) => $expr,
262 Linear($block) => $expr,
263 Dynamic($block) => $expr,
264 }
266 }};
267 (&mut $self:ident. $block:ident => $expr:expr) => {{
268 use self::BlockFlavor::*;
269 match &mut $self.$block {
270 Dedicated($block) => $expr,
271 Linear($block) => $expr,
272 Dynamic($block) => $expr,
273 }
275 }};
276}
277
278impl<B> BlockFlavor<B>
279where
280 B: gfx_hal::Backend,
281{
282 #[inline]
283 fn size(&self) -> u64 {
284 use self::BlockFlavor::*;
285 match self {
286 Dedicated(block) => block.size(),
287 Linear(block) => block.size(),
288 Dynamic(block) => block.size(),
289 }
291 }
292}
293
294impl<B> Block<B> for MemoryBlock<B>
295where
296 B: gfx_hal::Backend,
297{
298 #[inline]
299 fn properties(&self) -> gfx_hal::memory::Properties {
300 any_block!(&self.block => block.properties())
301 }
302
303 #[inline]
304 fn memory(&self) -> &B::Memory {
305 any_block!(&self.block => block.memory())
306 }
307
308 #[inline]
309 fn range(&self) -> Range<u64> {
310 any_block!(&self.block => block.range())
311 }
312
313 fn map<'a>(
314 &'a mut self,
315 device: &B::Device,
316 range: Range<u64>,
317 ) -> Result<MappedRange<'a, B>, gfx_hal::device::MapError> {
318 any_block!(&mut self.block => block.map(device, range))
319 }
320
321 fn unmap(&mut self, device: &B::Device) {
322 any_block!(&mut self.block => block.unmap(device))
323 }
324}