1pub type OwnedLabel = Option<String>;
5
6#[derive(Clone, Debug, PartialEq, Eq, Hash)]
8pub struct BufferInitDescriptor<'a> {
9 pub label: wgpu::Label<'a>,
11 pub contents: &'a [u8],
13 pub size: Option<wgpu::BufferAddress>,
15 pub usage: wgpu::BufferUsages,
18}
19
20pub trait DeviceExt {
22 fn create_buffer_init(&self, desc: &BufferInitDescriptor<'_>) -> wgpu::Buffer;
25}
26
27impl DeviceExt for wgpu::Device {
28 fn create_buffer_init(&self, descriptor: &BufferInitDescriptor<'_>) -> wgpu::Buffer {
29 let unpadded_size = {
30 let contents_size = descriptor.contents.len() as wgpu::BufferAddress;
31 match descriptor.size {
32 None => contents_size,
33 Some(specified_size) => {
34 assert!(
35 specified_size >= contents_size,
36 "specified size must at least be size of contents"
37 );
38 specified_size
39 }
40 }
41 };
42
43 let align_mask = wgpu::COPY_BUFFER_ALIGNMENT - 1;
48 let padded_size =
49 ((unpadded_size + align_mask) & !align_mask).max(wgpu::COPY_BUFFER_ALIGNMENT);
50
51 let normal_descriptor = wgpu::BufferDescriptor {
52 label: descriptor.label,
53 size: padded_size,
54 usage: descriptor.usage,
55 mapped_at_creation: true,
56 };
57
58 let buffer = self.create_buffer(&normal_descriptor);
59 {
60 let mut slice = buffer.slice(..).get_mapped_range_mut();
61 slice[0..unpadded_size as usize].copy_from_slice(descriptor.contents);
62
63 for i in unpadded_size..padded_size {
64 slice[i as usize] = 0;
65 }
66 }
67 buffer.unmap();
68 buffer
69 }
70}
71
72#[derive(Debug)]
74pub struct SizedBuffer {
75 pub size: wgpu::BufferAddress,
76 pub buffer: wgpu::Buffer,
77}
78
79impl SizedBuffer {
80 pub fn new(size: wgpu::BufferAddress, buffer: wgpu::Buffer) -> Self {
81 Self { size, buffer }
82 }
83}
84
85pub struct BufferResizeWriteDescriptor<'a> {
86 pub label: wgpu::Label<'a>,
87 pub contents: &'a [u8],
88 pub usage: wgpu::BufferUsages,
89}
90
91pub fn resize_write_buffer(
95 device: &wgpu::Device,
96 queue: &wgpu::Queue,
97 buffer: SizedBuffer,
98 descriptor: &BufferResizeWriteDescriptor,
99) -> SizedBuffer {
100 let contents_size = descriptor.contents.len() as wgpu::BufferAddress;
101 let enough_space = contents_size <= buffer.size;
102 if enough_space {
103 queue.write_buffer(&buffer.buffer, 0, descriptor.contents);
104 buffer
105 } else {
106 let new = device.create_buffer_init(&BufferInitDescriptor {
107 label: descriptor.label,
108 contents: descriptor.contents,
109 size: None,
110 usage: descriptor.usage,
111 });
112 SizedBuffer::new(contents_size, new)
113 }
114}
115
116#[derive(Debug)]
118pub struct DynamicBuffer {
119 raw: wgpu::Buffer,
120
121 label: crate::OwnedLabel,
122 size: wgpu::BufferAddress,
123 usage: wgpu::BufferUsages,
124}
125
126impl DynamicBuffer {
127 const RESERVE: bool = true;
128
129 pub fn new(device: &wgpu::Device, descriptor: &wgpu::BufferDescriptor) -> Self {
131 let raw = device.create_buffer(descriptor);
132
133 Self {
134 raw,
135 label: descriptor.label.map(|l| l.to_owned()),
136 size: descriptor.size,
137 usage: descriptor.usage,
138 }
139 }
140
141 pub fn new_init(device: &wgpu::Device, descriptor: &crate::BufferInitDescriptor) -> Self {
143 let raw = device.create_buffer_init(descriptor);
144
145 let descriptor = wgpu::BufferDescriptor {
146 label: descriptor.label,
147 size: descriptor.contents.len() as wgpu::BufferAddress,
148 usage: descriptor.usage,
149 mapped_at_creation: false,
150 };
151
152 Self {
153 raw,
154 label: descriptor.label.map(|l| l.to_owned()),
155 size: descriptor.size,
156 usage: descriptor.usage,
157 }
158 }
159
160 pub fn upload(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, contents: &[u8]) {
165 if self.try_upload(queue, contents).is_err() {
166 self.upload_by_init(device, contents)
167 }
168 }
169
170 pub fn try_upload(
173 &mut self,
174 queue: &wgpu::Queue,
175 contents: &[u8],
176 ) -> Result<(), wgpu::BufferAddress> {
177 let contents_size = contents.len() as wgpu::BufferAddress;
178 if contents_size < self.size {
179 queue.write_buffer(&self.raw, 0, contents);
180 self.size = contents_size;
181 Ok(())
182 } else {
183 Err(contents_size - self.size)
184 }
185 }
186
187 pub fn upload_by_init(&mut self, device: &wgpu::Device, contents: &[u8]) {
190 device.create_buffer_init(&crate::BufferInitDescriptor {
191 label: self.label.as_deref(),
192 contents,
193 usage: self.usage,
194 size: match Self::RESERVE {
195 true => Some(reserve_function(self.size)),
196 false => None,
197 },
198 });
199 }
200
201 pub fn raw(&self) -> &wgpu::Buffer {
203 &self.raw
204 }
205
206 pub fn into_raw(self) -> wgpu::Buffer {
208 self.raw
209 }
210}
211
212fn reserve_function(last_size: wgpu::BufferAddress) -> wgpu::BufferAddress {
213 last_size.pow(2)
214}
215
216#[derive(Debug)]
218pub struct BufferPool {
219 buffers: Vec<SizedBuffer>,
220 occupied: usize,
221
222 label: crate::OwnedLabel,
223 usage: wgpu::BufferUsages,
224}
225
226impl BufferPool {
227 pub fn new(descriptor: &BufferPoolDescriptor) -> Self {
229 Self {
230 buffers: Vec::new(),
231 occupied: 0,
232
233 label: descriptor.label.map(|l| l.to_owned()),
234 usage: descriptor.usage,
235 }
236 }
237
238 pub fn upload(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, contents: &[u8]) -> usize {
243 if self.occupied < self.buffers.len() {
244 let buffer = &mut self.buffers[self.occupied];
245
246 let label = self.label.as_deref();
248 let usage = self.usage;
249 replace_with::replace_with_or_abort(buffer, |buffer| {
250 resize_write_buffer(
251 device,
252 queue,
253 buffer,
254 &BufferResizeWriteDescriptor {
255 label,
256 contents,
257 usage,
258 },
259 )
260 });
261 } else {
262 self.buffers.push(self.create_buffer(device, contents));
263 }
264 self.occupied += 1;
265 self.occupied
266 }
267
268 pub fn clear(&mut self) {
270 self.occupied = 0;
271 }
272
273 pub fn get(&self, i: usize) -> Option<&wgpu::Buffer> {
275 if i < self.occupied {
276 Some(&self.buffers[i].buffer)
277 } else {
278 None
279 }
280 }
281
282 pub fn get_any(&self, i: usize) -> Option<&wgpu::Buffer> {
284 self.buffers.get(i).map(|b| &b.buffer)
285 }
286
287 pub fn size(&self) -> usize {
289 self.buffers.len()
290 }
291
292 pub fn occupied(&self) -> usize {
294 self.occupied
295 }
296}
297
298impl BufferPool {
299 fn create_buffer(&self, device: &wgpu::Device, contents: &[u8]) -> SizedBuffer {
300 let buffer = device.create_buffer_init(&BufferInitDescriptor {
301 label: self.label.as_deref(),
302 contents,
303 usage: self.usage,
304 size: None,
305 });
306 SizedBuffer::new(contents.len() as wgpu::BufferAddress, buffer)
307 }
308}
309
310pub struct BufferPoolDescriptor<'a> {
312 pub label: wgpu::Label<'a>,
314 pub usage: wgpu::BufferUsages,
316}