bevy_render/render_resource/
storage_buffer.rs1use core::marker::PhantomData;
2
3use super::Buffer;
4use crate::renderer::{RenderDevice, RenderQueue};
5use encase::{
6 internal::WriteInto, DynamicStorageBuffer as DynamicStorageBufferWrapper, ShaderType,
7 StorageBuffer as StorageBufferWrapper,
8};
9use wgpu::{util::BufferInitDescriptor, BindingResource, BufferBinding, BufferSize, BufferUsages};
10
11use super::IntoBinding;
12
13pub struct StorageBuffer<T: ShaderType> {
36 value: T,
37 scratch: StorageBufferWrapper<Vec<u8>>,
38 buffer: Option<Buffer>,
39 label: Option<String>,
40 changed: bool,
41 buffer_usage: BufferUsages,
42 last_written_size: Option<BufferSize>,
43}
44
45impl<T: ShaderType> From<T> for StorageBuffer<T> {
46 fn from(value: T) -> Self {
47 Self {
48 value,
49 scratch: StorageBufferWrapper::new(Vec::new()),
50 buffer: None,
51 label: None,
52 changed: false,
53 buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
54 last_written_size: None,
55 }
56 }
57}
58
59impl<T: ShaderType + Default> Default for StorageBuffer<T> {
60 fn default() -> Self {
61 Self {
62 value: T::default(),
63 scratch: StorageBufferWrapper::new(Vec::new()),
64 buffer: None,
65 label: None,
66 changed: false,
67 buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
68 last_written_size: None,
69 }
70 }
71}
72
73impl<T: ShaderType + WriteInto> StorageBuffer<T> {
74 #[inline]
75 pub fn buffer(&self) -> Option<&Buffer> {
76 self.buffer.as_ref()
77 }
78
79 #[inline]
80 pub fn binding(&self) -> Option<BindingResource> {
81 Some(BindingResource::Buffer(BufferBinding {
82 buffer: self.buffer()?,
83 offset: 0,
84 size: self.last_written_size,
85 }))
86 }
87
88 pub fn set(&mut self, value: T) {
89 self.value = value;
90 }
91
92 pub fn get(&self) -> &T {
93 &self.value
94 }
95
96 pub fn get_mut(&mut self) -> &mut T {
97 &mut self.value
98 }
99
100 pub fn set_label(&mut self, label: Option<&str>) {
101 let label = label.map(str::to_string);
102
103 if label != self.label {
104 self.changed = true;
105 }
106
107 self.label = label;
108 }
109
110 pub fn get_label(&self) -> Option<&str> {
111 self.label.as_deref()
112 }
113
114 pub fn add_usages(&mut self, usage: BufferUsages) {
120 self.buffer_usage |= usage;
121 self.changed = true;
122 }
123
124 pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
130 self.scratch.write(&self.value).unwrap();
131
132 let capacity = self.buffer.as_deref().map(wgpu::Buffer::size).unwrap_or(0);
133 let size = self.scratch.as_ref().len() as u64;
134
135 if capacity < size || self.changed {
136 self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
137 label: self.label.as_deref(),
138 usage: self.buffer_usage,
139 contents: self.scratch.as_ref(),
140 }));
141 self.changed = false;
142 } else if let Some(buffer) = &self.buffer {
143 queue.write_buffer(buffer, 0, self.scratch.as_ref());
144 }
145
146 self.last_written_size = BufferSize::new(size);
147 }
148}
149
150impl<'a, T: ShaderType + WriteInto> IntoBinding<'a> for &'a StorageBuffer<T> {
151 #[inline]
152 fn into_binding(self) -> BindingResource<'a> {
153 self.binding().expect("Failed to get buffer")
154 }
155}
156
157pub struct DynamicStorageBuffer<T: ShaderType> {
182 scratch: DynamicStorageBufferWrapper<Vec<u8>>,
183 buffer: Option<Buffer>,
184 label: Option<String>,
185 changed: bool,
186 buffer_usage: BufferUsages,
187 last_written_size: Option<BufferSize>,
188 _marker: PhantomData<fn() -> T>,
189}
190
191impl<T: ShaderType> Default for DynamicStorageBuffer<T> {
192 fn default() -> Self {
193 Self {
194 scratch: DynamicStorageBufferWrapper::new(Vec::new()),
195 buffer: None,
196 label: None,
197 changed: false,
198 buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
199 last_written_size: None,
200 _marker: PhantomData,
201 }
202 }
203}
204
205impl<T: ShaderType + WriteInto> DynamicStorageBuffer<T> {
206 #[inline]
207 pub fn buffer(&self) -> Option<&Buffer> {
208 self.buffer.as_ref()
209 }
210
211 #[inline]
212 pub fn binding(&self) -> Option<BindingResource> {
213 Some(BindingResource::Buffer(BufferBinding {
214 buffer: self.buffer()?,
215 offset: 0,
216 size: self.last_written_size,
217 }))
218 }
219
220 #[inline]
221 pub fn is_empty(&self) -> bool {
222 self.scratch.as_ref().is_empty()
223 }
224
225 #[inline]
226 pub fn push(&mut self, value: T) -> u32 {
227 self.scratch.write(&value).unwrap() as u32
228 }
229
230 pub fn set_label(&mut self, label: Option<&str>) {
231 let label = label.map(str::to_string);
232
233 if label != self.label {
234 self.changed = true;
235 }
236
237 self.label = label;
238 }
239
240 pub fn get_label(&self) -> Option<&str> {
241 self.label.as_deref()
242 }
243
244 pub fn add_usages(&mut self, usage: BufferUsages) {
250 self.buffer_usage |= usage;
251 self.changed = true;
252 }
253
254 #[inline]
255 pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
256 let capacity = self.buffer.as_deref().map(wgpu::Buffer::size).unwrap_or(0);
257 let size = self.scratch.as_ref().len() as u64;
258
259 if capacity < size || (self.changed && size > 0) {
260 self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
261 label: self.label.as_deref(),
262 usage: self.buffer_usage,
263 contents: self.scratch.as_ref(),
264 }));
265 self.changed = false;
266 } else if let Some(buffer) = &self.buffer {
267 queue.write_buffer(buffer, 0, self.scratch.as_ref());
268 }
269
270 self.last_written_size = BufferSize::new(size);
271 }
272
273 #[inline]
274 pub fn clear(&mut self) {
275 self.scratch.as_mut().clear();
276 self.scratch.set_offset(0);
277 }
278}
279
280impl<'a, T: ShaderType + WriteInto> IntoBinding<'a> for &'a DynamicStorageBuffer<T> {
281 #[inline]
282 fn into_binding(self) -> BindingResource<'a> {
283 self.binding().expect("Failed to get buffer")
284 }
285}