1#![allow(clippy::cast_possible_truncation)]
4
5use bytemuck::Pod;
6use wgpu::{Device, util::DeviceExt};
7
8use crate::vertex::Vertex;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum BufferUsage {
13 Vertex,
15 Index,
17 Uniform,
19 Storage,
21 Indirect,
23}
24
25impl From<BufferUsage> for wgpu::BufferUsages {
26 fn from(usage: BufferUsage) -> Self {
27 match usage {
28 BufferUsage::Vertex => wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
29 BufferUsage::Index => wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
30 BufferUsage::Uniform => wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
31 BufferUsage::Storage => {
32 wgpu::BufferUsages::STORAGE
33 | wgpu::BufferUsages::COPY_DST
34 | wgpu::BufferUsages::COPY_SRC
35 }
36 BufferUsage::Indirect => wgpu::BufferUsages::INDIRECT | wgpu::BufferUsages::COPY_DST,
37 }
38 }
39}
40
41#[derive(Debug)]
43pub struct Buffer {
44 inner: wgpu::Buffer,
45 usage: BufferUsage,
46 size: u64,
47}
48
49impl Buffer {
50 #[must_use]
52 pub fn new<T: Pod>(
53 device: &Device,
54 usage: BufferUsage,
55 data: &[T],
56 label: Option<&str>,
57 ) -> Self {
58 let inner = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
59 label,
60 contents: bytemuck::cast_slice(data),
61 usage: usage.into(),
62 });
63
64 Self {
65 inner,
66 usage,
67 size: std::mem::size_of_val(data) as u64,
68 }
69 }
70
71 #[must_use]
73 pub fn empty(device: &Device, usage: BufferUsage, size: u64, label: Option<&str>) -> Self {
74 let inner = device.create_buffer(&wgpu::BufferDescriptor {
75 label,
76 size,
77 usage: usage.into(),
78 mapped_at_creation: false,
79 });
80
81 Self { inner, usage, size }
82 }
83
84 #[must_use]
86 pub fn inner(&self) -> &wgpu::Buffer {
87 &self.inner
88 }
89
90 #[must_use]
92 pub fn usage(&self) -> BufferUsage {
93 self.usage
94 }
95
96 #[must_use]
98 pub fn size(&self) -> u64 {
99 self.size
100 }
101
102 #[must_use]
104 pub fn slice(&self) -> wgpu::BufferSlice<'_> {
105 self.inner.slice(..)
106 }
107}
108
109#[derive(Debug)]
111pub struct VertexBuffer<V: Vertex> {
112 buffer: Buffer,
113 vertex_count: u32,
114 _marker: std::marker::PhantomData<V>,
115}
116
117impl<V: Vertex> VertexBuffer<V> {
118 #[must_use]
120 pub fn new(device: &Device, vertices: &[V]) -> Self {
121 let buffer = Buffer::new(device, BufferUsage::Vertex, vertices, Some("Vertex Buffer"));
122
123 Self {
124 buffer,
125 vertex_count: vertices.len() as u32,
126 _marker: std::marker::PhantomData,
127 }
128 }
129
130 #[must_use]
132 pub fn with_label(device: &Device, vertices: &[V], label: &str) -> Self {
133 let buffer = Buffer::new(device, BufferUsage::Vertex, vertices, Some(label));
134
135 Self {
136 buffer,
137 vertex_count: vertices.len() as u32,
138 _marker: std::marker::PhantomData,
139 }
140 }
141
142 #[must_use]
144 pub fn vertex_count(&self) -> u32 {
145 self.vertex_count
146 }
147
148 #[must_use]
150 pub fn buffer(&self) -> &Buffer {
151 &self.buffer
152 }
153
154 #[must_use]
156 pub fn slice(&self) -> wgpu::BufferSlice<'_> {
157 self.buffer.slice()
158 }
159}
160
161#[derive(Debug)]
163pub struct IndexBuffer {
164 buffer: Buffer,
165 index_count: u32,
166 format: wgpu::IndexFormat,
167}
168
169impl IndexBuffer {
170 #[must_use]
172 pub fn new_u16(device: &Device, indices: &[u16]) -> Self {
173 let buffer = Buffer::new(device, BufferUsage::Index, indices, Some("Index Buffer"));
174
175 Self {
176 buffer,
177 index_count: indices.len() as u32,
178 format: wgpu::IndexFormat::Uint16,
179 }
180 }
181
182 #[must_use]
184 pub fn new_u32(device: &Device, indices: &[u32]) -> Self {
185 let buffer = Buffer::new(device, BufferUsage::Index, indices, Some("Index Buffer"));
186
187 Self {
188 buffer,
189 index_count: indices.len() as u32,
190 format: wgpu::IndexFormat::Uint32,
191 }
192 }
193
194 #[must_use]
196 pub fn index_count(&self) -> u32 {
197 self.index_count
198 }
199
200 #[must_use]
202 pub fn format(&self) -> wgpu::IndexFormat {
203 self.format
204 }
205
206 #[must_use]
208 pub fn buffer(&self) -> &Buffer {
209 &self.buffer
210 }
211
212 #[must_use]
214 pub fn slice(&self) -> wgpu::BufferSlice<'_> {
215 self.buffer.slice()
216 }
217}