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
|
use bytemuck::{Pod, Zeroable};
use std::marker::PhantomData;
use std::mem;
const DEFAULT_COUNT: wgpu::BufferAddress = 128;
/// A generic buffer struct useful for items which have no alignment requirements
/// (e.g. Vertex, Index buffers) & no dynamic offsets.
#[derive(Debug)]
pub struct Buffer<T> {
//stored sequentially per mesh iteration; refers to the offset index in the GPU buffer
offsets: Vec<wgpu::BufferAddress>,
label: &'static str,
usages: wgpu::BufferUsages,
gpu: wgpu::Buffer,
size: wgpu::BufferAddress,
_data: PhantomData<T>,
}
impl<T: Pod + Zeroable> Buffer<T> {
/// Initialize a new static buffer.
pub fn new(
device: &wgpu::Device,
label: &'static str,
usages: wgpu::BufferUsages,
) -> Self {
let size = (mem::size_of::<T>() as u64) * DEFAULT_COUNT;
Self {
offsets: Vec::new(),
label,
usages,
gpu: Self::gpu_buffer(device, label, size, usages),
size,
_data: PhantomData,
}
}
fn gpu_buffer(
device: &wgpu::Device,
label: &'static str,
size: wgpu::BufferAddress,
usage: wgpu::BufferUsages,
) -> wgpu::Buffer {
device.create_buffer(&wgpu::BufferDescriptor {
label: Some(label),
size,
usage,
mapped_at_creation: false,
})
}
/// Returns whether or not the buffer needs to be recreated. This can happen whenever mesh data
/// changes & a redraw is requested.
pub fn resize(&mut self, device: &wgpu::Device, new_count: usize) -> bool {
let size = (mem::size_of::<T>() * new_count) as u64;
if self.size < size {
self.size =
(mem::size_of::<T>() * (new_count + new_count / 2)) as u64;
self.gpu =
Self::gpu_buffer(device, self.label, self.size, self.usages);
self.offsets.clear();
true
} else {
false
}
}
/// Writes the current vertex data to the gpu buffer with a memcpy & stores its offset.
///
/// Returns the size of the written bytes.
pub fn write(
&mut self,
queue: &wgpu::Queue,
offset: u64,
content: &[T],
) -> u64 {
let bytes = bytemuck::cast_slice(content);
let bytes_size = bytes.len() as u64;
queue.write_buffer(&self.gpu, offset, bytes);
self.offsets.push(offset);
bytes_size
}
fn offset_at(&self, index: usize) -> &wgpu::BufferAddress {
self.offsets
.get(index)
.expect("Offset at index does not exist.")
}
/// Returns the slice calculated from the offset stored at the given index.
/// e.g. to calculate the slice for the 2nd mesh in the layer, this would be the offset at index
/// 1 that we stored earlier when writing.
pub fn slice_from_index(&self, index: usize) -> wgpu::BufferSlice<'_> {
self.gpu.slice(self.offset_at(index)..)
}
/// Clears any temporary data from the buffer.
pub fn clear(&mut self) {
self.offsets.clear()
}
}
|