encase/core/
buffers.rs

1use super::{
2    AlignmentValue, BufferMut, BufferRef, CreateFrom, ReadFrom, Reader, Result, ShaderType,
3    WriteInto, Writer,
4};
5
6/// Storage buffer wrapper facilitating RW operations
7pub struct StorageBuffer<B> {
8    inner: B,
9}
10
11impl<B> StorageBuffer<B> {
12    pub const fn new(buffer: B) -> Self {
13        Self { inner: buffer }
14    }
15
16    pub fn into_inner(self) -> B {
17        self.inner
18    }
19
20    pub fn content_of<T, U>(item: &T) -> Result<U>
21    where
22        T: ShaderType + WriteInto,
23        U: BufferMut + Default,
24    {
25        let mut buffer = StorageBuffer::new(U::default());
26        buffer.write(item)?;
27        Ok(buffer.into_inner())
28    }
29}
30
31impl<B> From<B> for StorageBuffer<B> {
32    fn from(buffer: B) -> Self {
33        Self::new(buffer)
34    }
35}
36
37impl<B> AsRef<B> for StorageBuffer<B> {
38    fn as_ref(&self) -> &B {
39        &self.inner
40    }
41}
42
43impl<B> AsMut<B> for StorageBuffer<B> {
44    fn as_mut(&mut self) -> &mut B {
45        &mut self.inner
46    }
47}
48
49impl<B: BufferMut> StorageBuffer<B> {
50    pub fn write<T>(&mut self, value: &T) -> Result<()>
51    where
52        T: ?Sized + ShaderType + WriteInto,
53    {
54        let mut writer = Writer::new(value, &mut self.inner, 0)?;
55        value.write_into(&mut writer);
56        Ok(())
57    }
58}
59
60impl<B: BufferRef> StorageBuffer<B> {
61    pub fn read<T>(&self, value: &mut T) -> Result<()>
62    where
63        T: ?Sized + ShaderType + ReadFrom,
64    {
65        let mut writer = Reader::new::<T>(&self.inner, 0)?;
66        value.read_from(&mut writer);
67        Ok(())
68    }
69
70    pub fn create<T>(&self) -> Result<T>
71    where
72        T: ShaderType + CreateFrom,
73    {
74        let mut writer = Reader::new::<T>(&self.inner, 0)?;
75        Ok(T::create_from(&mut writer))
76    }
77}
78
79/// Uniform buffer wrapper facilitating RW operations
80pub struct UniformBuffer<B> {
81    inner: StorageBuffer<B>,
82}
83
84impl<B> UniformBuffer<B> {
85    pub const fn new(buffer: B) -> Self {
86        Self {
87            inner: StorageBuffer::new(buffer),
88        }
89    }
90
91    pub fn into_inner(self) -> B {
92        self.inner.inner
93    }
94
95    pub fn content_of<T, U>(item: &T) -> Result<U>
96    where
97        T: ShaderType + WriteInto,
98        U: BufferMut + Default,
99    {
100        let mut buffer = UniformBuffer::new(U::default());
101        buffer.write(item)?;
102        Ok(buffer.into_inner())
103    }
104}
105
106impl<B> From<B> for UniformBuffer<B> {
107    fn from(buffer: B) -> Self {
108        Self::new(buffer)
109    }
110}
111
112impl<B> AsRef<B> for UniformBuffer<B> {
113    fn as_ref(&self) -> &B {
114        &self.inner.inner
115    }
116}
117
118impl<B> AsMut<B> for UniformBuffer<B> {
119    fn as_mut(&mut self) -> &mut B {
120        &mut self.inner.inner
121    }
122}
123
124impl<B: BufferMut> UniformBuffer<B> {
125    pub fn write<T>(&mut self, value: &T) -> Result<()>
126    where
127        T: ?Sized + ShaderType + WriteInto,
128    {
129        T::assert_uniform_compat();
130        self.inner.write(value)
131    }
132}
133
134impl<B: BufferRef> UniformBuffer<B> {
135    pub fn read<T>(&self, value: &mut T) -> Result<()>
136    where
137        T: ?Sized + ShaderType + ReadFrom,
138    {
139        T::assert_uniform_compat();
140        self.inner.read(value)
141    }
142
143    pub fn create<T>(&self) -> Result<T>
144    where
145        T: ShaderType + CreateFrom,
146    {
147        T::assert_uniform_compat();
148        self.inner.create()
149    }
150}
151
152/// Dynamic storage buffer wrapper facilitating RW operations
153pub struct DynamicStorageBuffer<B> {
154    inner: B,
155    alignment: AlignmentValue,
156    offset: usize,
157}
158
159impl<B> DynamicStorageBuffer<B> {
160    /// Creates a new dynamic storage buffer wrapper with an alignment of 256
161    /// (default alignment in the WebGPU spec).
162    pub const fn new(buffer: B) -> Self {
163        Self::new_with_alignment(buffer, 256)
164    }
165
166    /// Creates a new dynamic storage buffer wrapper with a given alignment.
167    /// # Panics
168    ///
169    /// - if `alignment` is not a power of two.
170    /// - if `alignment` is less than 32 (min alignment imposed by the WebGPU spec).
171    pub const fn new_with_alignment(buffer: B, alignment: u64) -> Self {
172        if alignment < 32 {
173            panic!("Alignment must be at least 32!");
174        }
175        Self {
176            inner: buffer,
177            alignment: AlignmentValue::new(alignment),
178            offset: 0,
179        }
180    }
181
182    pub fn set_offset(&mut self, offset: u64) {
183        if !self.alignment.is_aligned(offset) {
184            panic!(
185                "offset of {} bytes is not aligned to alignment of {} bytes",
186                offset,
187                self.alignment.get()
188            );
189        }
190
191        self.offset = offset as usize;
192    }
193
194    pub fn into_inner(self) -> B {
195        self.inner
196    }
197}
198
199impl<B> From<B> for DynamicStorageBuffer<B> {
200    fn from(buffer: B) -> Self {
201        Self::new(buffer)
202    }
203}
204
205impl<B> AsRef<B> for DynamicStorageBuffer<B> {
206    fn as_ref(&self) -> &B {
207        &self.inner
208    }
209}
210
211impl<B> AsMut<B> for DynamicStorageBuffer<B> {
212    fn as_mut(&mut self) -> &mut B {
213        &mut self.inner
214    }
215}
216
217impl<B: BufferMut> DynamicStorageBuffer<B> {
218    pub fn write<T>(&mut self, value: &T) -> Result<u64>
219    where
220        T: ?Sized + ShaderType + WriteInto,
221    {
222        let offset = self.offset;
223
224        let mut writer = Writer::new(value, &mut self.inner, offset)?;
225        value.write_into(&mut writer);
226
227        self.offset += self.alignment.round_up(value.size().get()) as usize;
228
229        Ok(offset as u64)
230    }
231}
232
233impl<B: BufferRef> DynamicStorageBuffer<B> {
234    pub fn read<T>(&mut self, value: &mut T) -> Result<()>
235    where
236        T: ?Sized + ShaderType + ReadFrom,
237    {
238        let mut writer = Reader::new::<T>(&self.inner, self.offset)?;
239        value.read_from(&mut writer);
240
241        self.offset += self.alignment.round_up(value.size().get()) as usize;
242
243        Ok(())
244    }
245
246    pub fn create<T>(&mut self) -> Result<T>
247    where
248        T: ShaderType + CreateFrom,
249    {
250        let mut writer = Reader::new::<T>(&self.inner, self.offset)?;
251        let value = T::create_from(&mut writer);
252
253        self.offset += self.alignment.round_up(value.size().get()) as usize;
254
255        Ok(value)
256    }
257}
258
259/// Dynamic uniform buffer wrapper facilitating RW operations
260pub struct DynamicUniformBuffer<B> {
261    inner: DynamicStorageBuffer<B>,
262}
263
264impl<B> DynamicUniformBuffer<B> {
265    /// Creates a new dynamic uniform buffer wrapper with an alignment of 256
266    /// (default alignment in the WebGPU spec).
267    pub const fn new(buffer: B) -> Self {
268        Self {
269            inner: DynamicStorageBuffer::new(buffer),
270        }
271    }
272
273    /// Creates a new dynamic uniform buffer wrapper with a given alignment.
274    /// # Panics
275    ///
276    /// - if `alignment` is not a power of two.
277    /// - if `alignment` is less than 32 (min alignment imposed by the WebGPU spec).
278    pub const fn new_with_alignment(buffer: B, alignment: u64) -> Self {
279        Self {
280            inner: DynamicStorageBuffer::new_with_alignment(buffer, alignment),
281        }
282    }
283
284    pub fn set_offset(&mut self, offset: u64) {
285        self.inner.set_offset(offset);
286    }
287
288    pub fn into_inner(self) -> B {
289        self.inner.inner
290    }
291}
292
293impl<B> From<B> for DynamicUniformBuffer<B> {
294    fn from(buffer: B) -> Self {
295        Self::new(buffer)
296    }
297}
298
299impl<B> AsRef<B> for DynamicUniformBuffer<B> {
300    fn as_ref(&self) -> &B {
301        &self.inner.inner
302    }
303}
304
305impl<B> AsMut<B> for DynamicUniformBuffer<B> {
306    fn as_mut(&mut self) -> &mut B {
307        &mut self.inner.inner
308    }
309}
310
311impl<B: BufferMut> DynamicUniformBuffer<B> {
312    pub fn write<T>(&mut self, value: &T) -> Result<u64>
313    where
314        T: ?Sized + ShaderType + WriteInto,
315    {
316        T::assert_uniform_compat();
317        self.inner.write(value)
318    }
319}
320
321impl<B: BufferRef> DynamicUniformBuffer<B> {
322    pub fn read<T>(&mut self, value: &mut T) -> Result<()>
323    where
324        T: ?Sized + ShaderType + ReadFrom,
325    {
326        T::assert_uniform_compat();
327        self.inner.read(value)
328    }
329
330    pub fn create<T>(&mut self) -> Result<T>
331    where
332        T: ShaderType + CreateFrom,
333    {
334        T::assert_uniform_compat();
335        self.inner.create()
336    }
337}