gfx_memory/allocator/
dedicated.rs

1use crate::{
2    allocator::{Allocator, Kind},
3    block::Block,
4    mapping::MappedRange,
5    memory::Memory,
6    AtomSize, Size,
7};
8use hal::{device::Device as _, Backend};
9use std::ptr::NonNull;
10
11/// Memory block allocated from `DedicatedAllocator`.
12#[derive(Debug)]
13pub struct DedicatedBlock<B: Backend> {
14    memory: Memory<B>,
15    ptr: Option<NonNull<u8>>,
16}
17
18unsafe impl<B: Backend> Send for DedicatedBlock<B> {}
19unsafe impl<B: Backend> Sync for DedicatedBlock<B> {}
20
21impl<B: Backend> DedicatedBlock<B> {
22    /// Get inner memory.
23    /// Panics if mapped.
24    pub fn unwrap_memory(self) -> Memory<B> {
25        assert_eq!(self.ptr, None);
26        self.memory
27    }
28
29    /// Make a non-mappable block.
30    pub fn from_memory(memory: Memory<B>) -> Self {
31        DedicatedBlock { memory, ptr: None }
32    }
33
34    /// Get the size of the block.
35    pub fn size(&self) -> Size {
36        self.memory.size()
37    }
38}
39
40impl<B: Backend> Block<B> for DedicatedBlock<B> {
41    fn properties(&self) -> hal::memory::Properties {
42        self.memory.properties()
43    }
44
45    fn memory(&self) -> &B::Memory {
46        self.memory.raw()
47    }
48
49    fn segment(&self) -> hal::memory::Segment {
50        hal::memory::Segment {
51            offset: 0,
52            size: Some(self.memory.size()),
53        }
54    }
55
56    fn map<'a>(
57        &'a mut self,
58        _device: &B::Device,
59        segment: hal::memory::Segment,
60    ) -> Result<MappedRange<'a, B>, hal::device::MapError> {
61        let requested_range = segment.offset..match segment.size {
62            Some(s) => segment.offset + s,
63            None => self.memory.size(),
64        };
65        let mapping_range = match self.memory.non_coherent_atom_size {
66            Some(atom) => crate::align_range(&requested_range, atom),
67            None => requested_range.clone(),
68        };
69
70        Ok(unsafe {
71            MappedRange::from_raw(
72                &self.memory,
73                self.ptr
74                    //TODO: https://github.com/gfx-rs/gfx/issues/3182
75                    .ok_or(hal::device::MapError::MappingFailed)?
76                    .as_ptr()
77                    .offset(mapping_range.start as isize),
78                mapping_range,
79                requested_range,
80            )
81        })
82    }
83}
84
85/// Dedicated memory allocator that uses memory object per allocation requested.
86///
87/// This allocator suites best huge allocations.
88/// From 32 MiB when GPU has 4-8 GiB memory total.
89///
90/// `Heaps` use this allocator when none of sub-allocators bound to the memory type
91/// can handle size required.
92/// TODO: Check if resource prefers dedicated memory.
93#[derive(Debug)]
94pub struct DedicatedAllocator {
95    memory_type: hal::MemoryTypeId,
96    memory_properties: hal::memory::Properties,
97    non_coherent_atom_size: Option<AtomSize>,
98    used: Size,
99}
100
101impl DedicatedAllocator {
102    /// Create new `DedicatedAllocator`
103    /// for `memory_type` with `memory_properties` specified
104    pub fn new(
105        memory_type: hal::MemoryTypeId,
106        memory_properties: hal::memory::Properties,
107        non_coherent_atom_size: Size,
108    ) -> Self {
109        DedicatedAllocator {
110            memory_type,
111            memory_properties,
112            non_coherent_atom_size: if crate::is_non_coherent_visible(memory_properties) {
113                AtomSize::new(non_coherent_atom_size)
114            } else {
115                None
116            },
117            used: 0,
118        }
119    }
120}
121
122impl<B: Backend> Allocator<B> for DedicatedAllocator {
123    type Block = DedicatedBlock<B>;
124
125    const KIND: Kind = Kind::Dedicated;
126
127    fn alloc(
128        &mut self,
129        device: &B::Device,
130        size: Size,
131        _align: Size,
132    ) -> Result<(DedicatedBlock<B>, Size), hal::device::AllocationError> {
133        let size = match self.non_coherent_atom_size {
134            Some(atom) => crate::align_size(size, atom),
135            None => size,
136        };
137        log::trace!("Allocate block of size: {}", size);
138
139        let (memory, ptr) = unsafe {
140            super::allocate_memory_helper(
141                device,
142                self.memory_type,
143                size,
144                self.memory_properties,
145                self.non_coherent_atom_size,
146            )?
147        };
148
149        self.used += size;
150        Ok((DedicatedBlock { memory, ptr }, size))
151    }
152
153    fn free(&mut self, device: &B::Device, block: DedicatedBlock<B>) -> Size {
154        let size = block.memory.size();
155        log::trace!("Free block of size: {}", size);
156        self.used -= size;
157        unsafe {
158            device.unmap_memory(block.memory.raw());
159            device.free_memory(block.memory.into_raw());
160        }
161        size
162    }
163}
164
165impl Drop for DedicatedAllocator {
166    fn drop(&mut self) {
167        if self.used != 0 {
168            log::error!("Not all allocation from DedicatedAllocator was freed");
169        }
170    }
171}