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> {
35 value: T,
36 scratch: StorageBufferWrapper<Vec<u8>>,
37 buffer: Option<Buffer>,
38 label: Option<String>,
39 changed: bool,
40 buffer_usage: BufferUsages,
41 last_written_size: Option<BufferSize>,
42}
43
44impl<T: ShaderType> From<T> for StorageBuffer<T> {
45 fn from(value: T) -> Self {
46 Self {
47 value,
48 scratch: StorageBufferWrapper::new(Vec::new()),
49 buffer: None,
50 label: None,
51 changed: false,
52 buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
53 last_written_size: None,
54 }
55 }
56}
57
58impl<T: ShaderType + Default> Default for StorageBuffer<T> {
59 fn default() -> Self {
60 Self {
61 value: T::default(),
62 scratch: StorageBufferWrapper::new(Vec::new()),
63 buffer: None,
64 label: None,
65 changed: false,
66 buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
67 last_written_size: None,
68 }
69 }
70}
71
72impl<T: ShaderType + WriteInto> StorageBuffer<T> {
73 #[inline]
74 pub fn buffer(&self) -> Option<&Buffer> {
75 self.buffer.as_ref()
76 }
77
78 #[inline]
79 pub fn binding(&self) -> Option<BindingResource> {
80 Some(BindingResource::Buffer(BufferBinding {
81 buffer: self.buffer()?,
82 offset: 0,
83 size: self.last_written_size,
84 }))
85 }
86
87 pub fn set(&mut self, value: T) {
88 self.value = value;
89 }
90
91 pub fn get(&self) -> &T {
92 &self.value
93 }
94
95 pub fn get_mut(&mut self) -> &mut T {
96 &mut self.value
97 }
98
99 pub fn set_label(&mut self, label: Option<&str>) {
100 let label = label.map(str::to_string);
101
102 if label != self.label {
103 self.changed = true;
104 }
105
106 self.label = label;
107 }
108
109 pub fn get_label(&self) -> Option<&str> {
110 self.label.as_deref()
111 }
112
113 pub fn add_usages(&mut self, usage: BufferUsages) {
119 self.buffer_usage |= usage;
120 self.changed = true;
121 }
122
123 pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
129 self.scratch.write(&self.value).unwrap();
130
131 let capacity = self.buffer.as_deref().map(wgpu::Buffer::size).unwrap_or(0);
132 let size = self.scratch.as_ref().len() as u64;
133
134 if capacity < size || self.changed {
135 self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
136 label: self.label.as_deref(),
137 usage: self.buffer_usage,
138 contents: self.scratch.as_ref(),
139 }));
140 self.changed = false;
141 } else if let Some(buffer) = &self.buffer {
142 queue.write_buffer(buffer, 0, self.scratch.as_ref());
143 }
144
145 self.last_written_size = BufferSize::new(size);
146 }
147}
148
149impl<'a, T: ShaderType + WriteInto> IntoBinding<'a> for &'a StorageBuffer<T> {
150 #[inline]
151 fn into_binding(self) -> BindingResource<'a> {
152 self.binding().expect("Failed to get buffer")
153 }
154}
155
156pub 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}