Skip to main content

maia/
memory.rs

1// Copyright 2022 Google LLC
2
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::marker::PhantomData;
10use std::ptr::NonNull;
11
12use crate::error::{Error, ErrorAndSelf, Result, ResultAndSelf};
13use crate::subobject::{Owner, Subobject};
14use crate::types::*;
15use crate::vk::Device;
16
17#[derive(Debug)]
18pub struct MemoryLifetime {
19    handle: Handle<VkDeviceMemory>,
20    device: Arc<Device>,
21}
22
23/// A piece of
24#[doc = crate::spec_link!("device memory", "11", "memory-device")]
25#[derive(Debug)]
26pub struct DeviceMemory {
27    inner: Owner<MemoryLifetime>,
28    allocation_size: u64,
29    memory_type_index: u32,
30}
31
32impl DeviceMemory {
33    /// Returns [`Error::OutOfBounds`] if no memory type exists with the given
34    /// index.
35    #[doc = crate::man_link!(vkAllocateMemory)]
36    pub fn new(
37        device: &Arc<Device>, allocation_size: u64, memory_type_index: u32,
38    ) -> Result<Self> {
39        let mem_types = device.physical_device().memory_properties();
40        if memory_type_index >= mem_types.memory_types.len() {
41            return Err(Error::OutOfBounds);
42        }
43        device.increment_memory_alloc_count()?;
44        let mut handle = None;
45        let result = unsafe {
46            (device.fun.allocate_memory)(
47                device.handle(),
48                &MemoryAllocateInfo {
49                    stype: Default::default(),
50                    next: Default::default(),
51                    allocation_size,
52                    memory_type_index,
53                },
54                None,
55                &mut handle,
56            )
57        };
58        if result.is_err() {
59            device.decrement_memory_alloc_count();
60            result?;
61        }
62        Ok(Self {
63            allocation_size,
64            memory_type_index,
65            inner: Owner::new(MemoryLifetime {
66                handle: handle.unwrap(),
67                device: device.clone(),
68            }),
69        })
70    }
71
72    /// Borrows the inner Vulkan handle.
73    pub fn handle(&self) -> Ref<VkDeviceMemory> {
74        self.inner.handle.borrow()
75    }
76    /// Borrows the inner Vulkan handle.
77    pub fn mut_handle(&mut self) -> Mut<VkDeviceMemory> {
78        self.inner.handle.borrow_mut()
79    }
80    /// Returns the associated device.
81    pub fn device(&self) -> &Arc<Device> {
82        &self.inner.device
83    }
84    /// Extend the lifetime of the memory until the returned object is dropped.
85    pub(crate) fn resource(&self) -> Subobject<MemoryLifetime> {
86        Subobject::new(&self.inner)
87    }
88    /// Check if the memory meets `requirements` at the given offset.
89    pub fn check(&self, offset: u64, requirements: MemoryRequirements) -> bool {
90        let (end, overflow) = offset.overflowing_add(requirements.size);
91        (1 << self.memory_type_index) & requirements.memory_type_bits != 0
92            && offset & (requirements.alignment - 1) == 0
93            && !overflow
94            && end <= self.allocation_size
95    }
96}
97
98impl Drop for MemoryLifetime {
99    fn drop(&mut self) {
100        unsafe {
101            (self.device.fun.free_memory)(
102                self.device.handle(),
103                self.handle.borrow_mut(),
104                None,
105            )
106        }
107        self.device.decrement_memory_alloc_count();
108    }
109}
110
111/// A [`DeviceMemory`] which has been mapped and can be written to
112pub struct MappedMemory {
113    memory: DeviceMemory,
114    size: usize,
115    ptr: NonNull<u8>,
116}
117
118/// A structure for copying data out of mapped memory. Implements
119/// [`std::io::Read`].
120pub struct MemoryRead<'a> {
121    ptr: NonNull<u8>,
122    end: *const u8,
123    _lt: PhantomData<&'a ()>,
124}
125/// A structure for copying data into mapped memory. Implements
126/// [`std::io::Write`].
127pub struct MemoryWrite<'a> {
128    ptr: NonNull<u8>,
129    end: *const u8,
130    _lt: PhantomData<&'a ()>,
131}
132
133#[allow(clippy::len_without_is_empty)]
134impl DeviceMemory {
135    /// Map the memory so it can be written to. Returns [`Error::OutOfBounds`] if
136    /// `offset` and `size` are out of bounds.
137    pub fn map(
138        mut self, offset: u64, size: usize,
139    ) -> ResultAndSelf<MappedMemory, Self> {
140        let (end, overflow) = offset.overflowing_add(size as u64);
141        if overflow || end > self.allocation_size || size > isize::MAX as usize
142        {
143            return Err(ErrorAndSelf(Error::OutOfBounds, self));
144        }
145        let inner = &mut *self.inner;
146        let mut ptr = std::ptr::null_mut();
147        unsafe {
148            if let Err(err) = (inner.device.fun.map_memory)(
149                inner.device.handle(),
150                inner.handle.borrow_mut(),
151                offset,
152                size as u64,
153                Default::default(),
154                &mut ptr,
155            ) {
156                return Err(ErrorAndSelf(err.into(), self));
157            }
158        }
159        Ok(MappedMemory { memory: self, size, ptr: NonNull::new(ptr).unwrap() })
160    }
161    /// Returns the size of the memory in bytes.
162    pub fn len(&self) -> u64 {
163        self.allocation_size
164    }
165}
166
167impl Drop for MappedMemory {
168    fn drop(&mut self) {
169        self.unmap_impl()
170    }
171}
172
173impl MappedMemory {
174    fn unmap_impl(&mut self) {
175        let inner = &mut *self.memory.inner;
176        unsafe {
177            (inner.device.fun.unmap_memory)(
178                inner.device.handle(),
179                inner.handle.borrow_mut(),
180            )
181        }
182    }
183
184    /// Unmaps the memory
185    pub fn unmap(mut self) -> DeviceMemory {
186        self.unmap_impl();
187        let no_drop = std::mem::ManuallyDrop::new(self);
188        unsafe { std::ptr::addr_of!(no_drop.memory).read() }
189    }
190
191    /// Gets the associated memory object
192    pub fn memory(&self) -> &DeviceMemory {
193        &self.memory
194    }
195
196    /// Read the memory's contents. It may be garbage (although it won't be
197    /// uninitialized). If `offset` is out of bounds, the result will be empty.
198    #[inline]
199    pub fn read_at(&self, offset: usize) -> MemoryRead {
200        unsafe {
201            let ptr = self.ptr.as_ptr().add(offset.min(self.size));
202            MemoryRead {
203                ptr: NonNull::new_unchecked(ptr),
204                end: self.ptr.as_ptr().add(self.size),
205                _lt: PhantomData,
206            }
207        }
208    }
209
210    /// Write to the memory. If `offset` is out of bounds, the result will be
211    /// empty.
212    #[inline]
213    pub fn write_at(&mut self, offset: usize) -> MemoryWrite {
214        unsafe {
215            let ptr = self.ptr.as_ptr().add(offset.min(self.size));
216            MemoryWrite {
217                ptr: NonNull::new_unchecked(ptr),
218                end: self.ptr.as_ptr().add(self.size),
219                _lt: PhantomData,
220            }
221        }
222    }
223}
224
225impl<'a> std::io::Read for MemoryRead<'a> {
226    #[inline]
227    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
228        unsafe {
229            let size = self.end.offset_from(self.ptr.as_ptr()) as usize;
230            let count = size.min(buf.len());
231            std::ptr::copy_nonoverlapping(
232                self.ptr.as_ptr(),
233                buf.as_mut_ptr(),
234                count,
235            );
236            self.ptr = NonNull::new_unchecked(self.ptr.as_ptr().add(count));
237            Ok(count)
238        }
239    }
240    #[inline]
241    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
242        unsafe {
243            let size = self.end.offset_from(self.ptr.as_ptr()) as usize;
244            buf.reserve_exact(size);
245            std::ptr::copy_nonoverlapping(
246                self.ptr.as_ptr(),
247                buf.spare_capacity_mut().as_mut_ptr() as *mut u8,
248                size,
249            );
250            buf.set_len(buf.len() + size);
251            Ok(size)
252        }
253    }
254}
255
256impl<'a> std::io::Write for MemoryWrite<'a> {
257    #[inline]
258    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
259        unsafe {
260            let size = self.end.offset_from(self.ptr.as_ptr()) as usize;
261            let count = size.min(buf.len());
262            std::ptr::copy_nonoverlapping(
263                buf.as_ptr(),
264                self.ptr.as_ptr(),
265                count,
266            );
267            self.ptr = NonNull::new_unchecked(self.ptr.as_ptr().add(count));
268            Ok(count)
269        }
270    }
271    /// Returns an error of kind [`std::io::ErrorKind::WriteZero`] if not all
272    /// the bytes could be written.
273    fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
274        if self.write(buf)? == buf.len() {
275            Ok(())
276        } else {
277            Err(std::io::ErrorKind::WriteZero.into())
278        }
279    }
280
281    /// Does nothing.
282    #[inline]
283    fn flush(&mut self) -> std::io::Result<()> {
284        Ok(())
285    }
286}
287
288// Access to ptr is properly controlled with borrows
289unsafe impl Send for MappedMemory {}
290unsafe impl Sync for MappedMemory {}
291impl std::panic::UnwindSafe for MappedMemory {}
292impl std::panic::RefUnwindSafe for MappedMemory {}
293unsafe impl<'a> Send for MemoryRead<'a> {}
294unsafe impl<'a> Sync for MemoryRead<'a> {}
295impl<'a> std::panic::UnwindSafe for MemoryRead<'a> {}
296impl<'a> std::panic::RefUnwindSafe for MemoryRead<'a> {}
297unsafe impl<'a> Send for MemoryWrite<'a> {}
298unsafe impl<'a> Sync for MemoryWrite<'a> {}
299impl<'a> std::panic::UnwindSafe for MemoryWrite<'a> {}
300impl<'a> std::panic::RefUnwindSafe for MemoryWrite<'a> {}