rendy_memory/allocator/
dedicated.rs

1use std::{ops::Range, ptr::NonNull};
2
3use {
4    crate::{
5        allocator::{Allocator, Kind},
6        block::Block,
7        mapping::{mapped_fitting_range, MappedRange},
8        memory::*,
9    },
10    gfx_hal::{device::Device as _, Backend},
11};
12
13/// Memory block allocated from `DedicatedAllocator`
14#[derive(Debug)]
15pub struct DedicatedBlock<B: Backend> {
16    memory: Memory<B>,
17    mapping: Option<(NonNull<u8>, Range<u64>)>,
18}
19
20unsafe impl<B> Send for DedicatedBlock<B> where B: Backend {}
21unsafe impl<B> Sync for DedicatedBlock<B> where B: Backend {}
22
23impl<B> DedicatedBlock<B>
24where
25    B: Backend,
26{
27    /// Get inner memory.
28    /// Panics if mapped.
29    pub fn unwrap_memory(self) -> Memory<B> {
30        assert!(self.mapping.is_none());
31        self.memory
32    }
33
34    /// Make unmapped block.
35    pub fn from_memory(memory: Memory<B>) -> Self {
36        DedicatedBlock {
37            memory,
38            mapping: None,
39        }
40    }
41}
42
43impl<B> Block<B> for DedicatedBlock<B>
44where
45    B: Backend,
46{
47    #[inline]
48    fn properties(&self) -> gfx_hal::memory::Properties {
49        self.memory.properties()
50    }
51
52    #[inline]
53    fn memory(&self) -> &B::Memory {
54        self.memory.raw()
55    }
56
57    #[inline]
58    fn range(&self) -> Range<u64> {
59        0..self.memory.size()
60    }
61
62    fn map<'a>(
63        &'a mut self,
64        device: &B::Device,
65        range: Range<u64>,
66    ) -> Result<MappedRange<'a, B>, gfx_hal::device::MapError> {
67        assert!(
68            range.start < range.end,
69            "Memory mapping region must have valid size"
70        );
71
72        if !self.memory.host_visible() {
73            //TODO: invalid access error
74            return Err(gfx_hal::device::MapError::MappingFailed);
75        }
76
77        unsafe {
78            if let Some(ptr) = self
79                .mapping
80                .clone()
81                .and_then(|mapping| mapped_fitting_range(mapping.0, mapping.1, range.clone()))
82            {
83                Ok(MappedRange::from_raw(&self.memory, ptr, range))
84            } else {
85                self.unmap(device);
86                let ptr = device.map_memory(self.memory.raw(), range.clone())?;
87                let ptr = NonNull::new(ptr).expect("Memory mapping shouldn't return nullptr");
88                let mapping = MappedRange::from_raw(&self.memory, ptr, range);
89                self.mapping = Some((mapping.ptr(), mapping.range()));
90                Ok(mapping)
91            }
92        }
93    }
94
95    fn unmap(&mut self, device: &B::Device) {
96        if self.mapping.take().is_some() {
97            unsafe {
98                // trace!("Unmap memory: {:#?}", self.memory);
99                device.unmap_memory(self.memory.raw());
100            }
101        }
102    }
103}
104
105/// Dedicated memory allocator that uses memory object per allocation requested.
106///
107/// This allocator suites best huge allocations.
108/// From 32 MiB when GPU has 4-8 GiB memory total.
109///
110/// `Heaps` use this allocator when none of sub-allocators bound to the memory type
111/// can handle size required.
112/// TODO: Check if resource prefers dedicated memory.
113#[derive(Debug)]
114pub struct DedicatedAllocator {
115    memory_type: gfx_hal::MemoryTypeId,
116    memory_properties: gfx_hal::memory::Properties,
117    used: u64,
118}
119
120impl DedicatedAllocator {
121    /// Get properties required by the allocator.
122    pub fn properties_required() -> gfx_hal::memory::Properties {
123        gfx_hal::memory::Properties::empty()
124    }
125
126    /// Create new `LinearAllocator`
127    /// for `memory_type` with `memory_properties` specified
128    pub fn new(
129        memory_type: gfx_hal::MemoryTypeId,
130        memory_properties: gfx_hal::memory::Properties,
131    ) -> Self {
132        DedicatedAllocator {
133            memory_type,
134            memory_properties,
135            used: 0,
136        }
137    }
138}
139
140impl<B> Allocator<B> for DedicatedAllocator
141where
142    B: Backend,
143{
144    type Block = DedicatedBlock<B>;
145
146    fn kind() -> Kind {
147        Kind::Dedicated
148    }
149
150    #[inline]
151    fn alloc(
152        &mut self,
153        device: &B::Device,
154        size: u64,
155        _align: u64,
156    ) -> Result<(DedicatedBlock<B>, u64), gfx_hal::device::AllocationError> {
157        let memory = unsafe {
158            Memory::from_raw(
159                device.allocate_memory(self.memory_type, size)?,
160                size,
161                self.memory_properties,
162            )
163        };
164
165        self.used += size;
166
167        Ok((DedicatedBlock::from_memory(memory), size))
168    }
169
170    #[inline]
171    fn free(&mut self, device: &B::Device, mut block: DedicatedBlock<B>) -> u64 {
172        block.unmap(device);
173        let size = block.memory.size();
174        self.used -= size;
175        unsafe {
176            device.free_memory(block.memory.into_raw());
177        }
178        size
179    }
180}
181
182impl Drop for DedicatedAllocator {
183    fn drop(&mut self) {
184        if self.used > 0 {
185            log::error!("Not all allocation from DedicatedAllocator was freed");
186        }
187    }
188}