1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use super::{Buffer, StaticBuffer};
use crate::graphics::vulkan::{device_allocator::Allocation, Device};
use anyhow::Result;
use ash::{version::DeviceV1_0, vk};
use std::sync::Arc;
pub struct CpuBuffer {
buffer: StaticBuffer,
written_size: u64,
}
impl CpuBuffer {
pub fn new(
device: Arc<Device>,
usage: vk::BufferUsageFlags,
) -> Result<Self> {
Ok(Self {
buffer: StaticBuffer::empty(
device.clone(),
usage,
vk::MemoryPropertyFlags::HOST_VISIBLE
| vk::MemoryPropertyFlags::HOST_COHERENT,
)?,
written_size: 0,
})
}
pub unsafe fn write_data<T>(&mut self, data: &[T]) -> Result<()>
where
T: Sized + Copy + std::fmt::Debug,
{
self.write_data_arrays(&[data])?;
Ok(())
}
pub unsafe fn write_data_arrays<T>(
&mut self,
data_arrays: &[&[T]],
) -> Result<()>
where
T: Sized + Copy + std::fmt::Debug,
{
let entry_size = std::mem::size_of::<T>();
let total_count: usize =
data_arrays.iter().map(|entry| entry.len()).sum();
let total_size = total_count * entry_size;
self.resize(total_size as u64)?;
let allocation = self.buffer.allocation();
let mut ptr = self.buffer.device.logical_device.map_memory(
allocation.memory,
allocation.offset,
self.written_size,
vk::MemoryMapFlags::empty(),
)? as *mut T;
for entry in data_arrays {
let mapped_slice = std::slice::from_raw_parts_mut(ptr, entry.len());
mapped_slice.copy_from_slice(entry);
ptr = ptr.offset(entry.len() as isize);
}
self.buffer
.device
.logical_device
.unmap_memory(self.buffer.allocation().memory);
Ok(())
}
fn resize(&mut self, byte_size: u64) -> Result<()> {
if byte_size > self.buffer.size_in_bytes() {
self.buffer = self.buffer.allocate(byte_size)?;
}
self.written_size = byte_size;
Ok(())
}
}
impl Buffer for CpuBuffer {
unsafe fn raw(&self) -> ash::vk::Buffer {
self.buffer.raw()
}
unsafe fn allocation(&self) -> &Allocation {
self.buffer.allocation()
}
fn size_in_bytes(&self) -> u64 {
self.written_size
}
}