ursus_core/vulkan/resources/
mapped_buffer.rs1use 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}