Skip to main content

ursus_core/vulkan/resources/
mapped_buffer.rs

1use crate::vulkan::core::memory::find_memory_type;
2use ash::vk;
3use std::marker::PhantomData;
4use std::ptr::{copy_nonoverlapping, write};
5
6pub struct MappedGpuBuffer<T> {
7    pub(crate) buffer: vk::Buffer,
8    memory: vk::DeviceMemory,
9    mapped: *mut T,
10    pub capacity: usize,
11    device: ash::Device,
12    _marker: PhantomData<T>,
13}
14
15unsafe impl<T> Send for MappedGpuBuffer<T> {}
16unsafe impl<T> Sync for MappedGpuBuffer<T> {}
17
18impl<T: Copy> MappedGpuBuffer<T> {
19    pub fn new(
20        device: &ash::Device,
21        physical_device: vk::PhysicalDevice,
22        instance: &ash::Instance,
23        usage: vk::BufferUsageFlags,
24        capacity: usize,
25    ) -> anyhow::Result<Self> {
26        let size = (capacity * size_of::<T>()) as vk::DeviceSize;
27
28        let buf_info = vk::BufferCreateInfo::default().size(size).usage(usage).sharing_mode(vk::SharingMode::EXCLUSIVE);
29        let buffer = unsafe { device.create_buffer(&buf_info, None)? };
30
31        let req = unsafe { device.get_buffer_memory_requirements(buffer) };
32        let mem_type = find_memory_type(
33            instance,
34            physical_device,
35            req.memory_type_bits,
36            vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
37        )?;
38
39        let memory = unsafe {
40            device.allocate_memory(
41                &vk::MemoryAllocateInfo::default().allocation_size(req.size).memory_type_index(mem_type),
42                None,
43            )?
44        };
45        unsafe { device.bind_buffer_memory(buffer, memory, 0)? };
46
47        let mapped = unsafe { device.map_memory(memory, 0, size, vk::MemoryMapFlags::empty())? as *mut T };
48
49        Ok(Self { buffer, memory, mapped, capacity, device: device.clone(), _marker: PhantomData })
50    }
51
52    pub fn new_single(
53        device: &ash::Device,
54        physical_device: vk::PhysicalDevice,
55        instance: &ash::Instance,
56        initial: T,
57    ) -> anyhow::Result<Self> {
58        let this = Self::new(device, physical_device, instance, vk::BufferUsageFlags::UNIFORM_BUFFER, 1)?;
59        this.upload_one(&initial);
60        Ok(this)
61    }
62
63    pub fn upload_one(&self, data: &T) {
64        debug_assert_eq!(self.capacity, 1, "upload_one вызван для буфера с capacity != 1");
65        unsafe { write(self.mapped, *data) };
66    }
67
68    pub fn upload_slice(&self, data: &[T]) {
69        assert!(data.len() <= self.capacity, "MappedGpuBuffer::upload_slice: превышена capacity");
70        unsafe { copy_nonoverlapping(data.as_ptr(), self.mapped, data.len()) };
71    }
72
73    pub fn size(&self) -> vk::DeviceSize {
74        (self.capacity * size_of::<T>()) as vk::DeviceSize
75    }
76}
77
78impl<T> Drop for MappedGpuBuffer<T> {
79    fn drop(&mut self) {
80        unsafe {
81            self.device.unmap_memory(self.memory);
82            self.device.destroy_buffer(self.buffer, None);
83            self.device.free_memory(self.memory, None);
84        }
85    }
86}