1#![warn(missing_docs)]
22
23use crate::core::{
27 algebra::{Matrix2, Matrix3, Matrix4, Vector2, Vector3, Vector4},
28 array_as_u8_slice,
29 arrayvec::ArrayVec,
30 color::Color,
31 value_as_u8_slice,
32};
33
34pub trait ByteStorage {
36 fn reset(&mut self);
38 fn bytes(&self) -> &[u8];
40 fn bytes_count(&self) -> usize;
42 fn write_bytes(&mut self, bytes: &[u8]);
44 fn write_zeros(&mut self, count: usize);
46 fn push_padding(&mut self, alignment: usize) {
49 debug_assert!(alignment.is_power_of_two());
50 let bytes_count = self.bytes_count();
51 let remainder = (alignment - 1) & bytes_count;
52 if remainder > 0 {
53 let padding = alignment - remainder;
54 self.write_zeros(padding);
55 }
56 }
57}
58
59impl<const N: usize> ByteStorage for ArrayVec<u8, N> {
60 fn reset(&mut self) {
61 self.clear();
62 }
63
64 fn bytes(&self) -> &[u8] {
65 self.as_slice()
66 }
67
68 fn bytes_count(&self) -> usize {
69 self.len()
70 }
71
72 fn write_bytes(&mut self, bytes: &[u8]) {
73 self.try_extend_from_slice(bytes).unwrap()
74 }
75
76 fn write_zeros(&mut self, count: usize) {
77 let old_len = self.len();
78 let new_len = old_len + count;
79 assert!(new_len <= self.capacity());
80 unsafe {
82 self.set_len(new_len);
83 std::ptr::write_bytes(self.as_mut_ptr().add(old_len), 0, count)
84 }
85 }
86}
87
88impl ByteStorage for Vec<u8> {
89 fn reset(&mut self) {
90 self.clear();
91 }
92
93 fn bytes(&self) -> &[u8] {
94 self.as_slice()
95 }
96
97 fn bytes_count(&self) -> usize {
98 self.len()
99 }
100
101 fn write_bytes(&mut self, bytes: &[u8]) {
102 self.extend_from_slice(bytes)
103 }
104
105 #[allow(clippy::uninit_vec)]
108 fn write_zeros(&mut self, count: usize) {
109 let old_len = self.len();
110 let new_len = old_len + count;
111 self.reserve(count);
112 unsafe {
114 self.set_len(new_len);
115 std::ptr::write_bytes(self.as_mut_ptr().add(old_len), 0, count)
116 }
117 }
118}
119
120#[derive(Default)]
138pub struct UniformBuffer<S: ByteStorage> {
139 storage: S,
140}
141
142pub type StaticUniformBuffer<const N: usize> = UniformBuffer<ArrayVec<u8, N>>;
144
145pub type DynamicUniformBuffer = UniformBuffer<Vec<u8>>;
147
148pub trait Std140 {
150 fn write(&self, dest: &mut dyn ByteStorage);
152}
153
154macro_rules! default_write_impl {
155 ($alignment:expr) => {
156 fn write(&self, dest: &mut dyn ByteStorage) {
157 dest.push_padding($alignment);
158 dest.write_bytes(value_as_u8_slice(self))
159 }
160 };
161}
162
163impl Std140 for f32 {
164 default_write_impl!(4);
165}
166
167impl Std140 for u32 {
168 default_write_impl!(4);
169}
170
171impl Std140 for i32 {
172 default_write_impl!(4);
173}
174
175impl Std140 for Vector2<f32> {
176 default_write_impl!(8);
177}
178
179impl Std140 for Vector3<f32> {
180 default_write_impl!(16);
181}
182
183impl Std140 for Vector4<f32> {
184 default_write_impl!(16);
185}
186
187impl Std140 for Matrix4<f32> {
188 default_write_impl!(16);
189}
190
191impl Std140 for Matrix3<f32> {
192 fn write(&self, dest: &mut dyn ByteStorage) {
193 dest.push_padding(16);
194 for row in (self as &dyn AsRef<[[f32; 3]; 3]>).as_ref() {
195 dest.write_bytes(array_as_u8_slice(row));
196 dest.write_bytes(&[0; size_of::<f32>()]);
197 }
198 }
199}
200
201impl Std140 for Matrix2<f32> {
202 fn write(&self, dest: &mut dyn ByteStorage) {
203 dest.push_padding(16);
204 for row in (self as &dyn AsRef<[[f32; 2]; 2]>).as_ref() {
205 dest.write_bytes(array_as_u8_slice(row));
206 dest.write_bytes(&[0; 2 * size_of::<f32>()]);
207 }
208 }
209}
210
211impl Std140 for Color {
212 fn write(&self, dest: &mut dyn ByteStorage) {
213 dest.push_padding(16);
214 let frgba = self.as_frgba();
215 dest.write_bytes(value_as_u8_slice(&frgba));
216 }
217}
218
219impl Std140 for bool {
220 fn write(&self, dest: &mut dyn ByteStorage) {
221 dest.push_padding(4);
222 let integer = if *self { 1 } else { 0 };
223 dest.write_bytes(value_as_u8_slice(&integer));
224 }
225}
226
227fn write_array(arr: &[impl Std140], dest: &mut dyn ByteStorage) {
228 for item in arr {
229 dest.push_padding(16);
230 item.write(dest);
231 dest.push_padding(16);
232 }
233}
234
235impl<T: Std140, const N: usize> Std140 for [T; N] {
236 fn write(&self, dest: &mut dyn ByteStorage) {
237 write_array(self, dest)
238 }
239}
240
241impl<T: Std140> Std140 for [T] {
242 fn write(&self, dest: &mut dyn ByteStorage) {
243 write_array(self, dest)
244 }
245}
246
247impl<S> UniformBuffer<S>
248where
249 S: ByteStorage,
250{
251 pub fn new() -> Self
253 where
254 S: Default,
255 {
256 Self {
257 storage: S::default(),
258 }
259 }
260
261 pub fn with_storage(storage: S) -> Self {
263 Self { storage }
264 }
265
266 pub fn clear(&mut self) {
268 self.storage.reset();
269 }
270
271 pub fn len(&self) -> usize {
275 self.storage.bytes_count()
276 }
277
278 pub fn is_empty(&self) -> bool {
280 self.len() == 0
281 }
282
283 pub fn push_padding(&mut self, alignment: usize) {
285 self.storage.push_padding(alignment);
286 }
287
288 pub fn push<T>(&mut self, value: &T) -> &mut Self
291 where
292 T: Std140 + ?Sized,
293 {
294 value.write(&mut self.storage);
295 self
296 }
297
298 pub fn with<T>(mut self, value: &T) -> Self
300 where
301 T: Std140 + ?Sized,
302 {
303 self.push(value);
304 self
305 }
306
307 fn push_array_element<T: Std140>(&mut self, item: &T) {
308 self.push_padding(16);
309 item.write(&mut self.storage);
310 self.push_padding(16);
311 }
312
313 pub fn push_slice_with_max_size<T: Std140 + Default>(
316 &mut self,
317 slice: &[T],
318 max_len: usize,
319 ) -> &mut Self {
320 let len = slice.len();
321 if !slice.is_empty() {
322 let end = max_len.min(len);
323 self.push(&slice[0..end]);
324 }
325 let remainder = max_len.saturating_sub(len);
326 let item = T::default();
327 for _ in 0..remainder {
328 self.push_array_element(&item);
329 }
330 self
331 }
332
333 pub fn with_slice_with_max_size<T: Std140 + Default>(
335 mut self,
336 slice: &[T],
337 max_len: usize,
338 ) -> Self {
339 self.push_slice_with_max_size(slice, max_len);
340 self
341 }
342
343 pub fn storage(&self) -> &S {
345 &self.storage
346 }
347
348 pub fn finish(mut self) -> S {
352 self.push_padding(16);
353 self.storage
354 }
355
356 pub fn next_write_aligned_position(&self, alignment: usize) -> usize {
358 let position = self.storage.bytes_count();
359 let remainder = (alignment - 1) & position;
360 if remainder > 0 {
361 let padding = alignment - remainder;
362 position + padding
363 } else {
364 position
365 }
366 }
367
368 pub fn write_bytes_with_alignment(&mut self, bytes: &[u8], alignment: usize) -> usize {
372 self.push_padding(alignment);
373 let data_location = self.storage.bytes_count();
374 self.storage.write_bytes(bytes);
375 data_location
376 }
377}
378
379#[cfg(test)]
380mod test {
381 use crate::{
382 core::algebra::{Matrix3, Vector3, Vector4},
383 uniform::DynamicUniformBuffer,
384 };
385 use fyrox_core::transmute_slice;
386
387 #[test]
388 fn test_uniform_buffer() {
389 let mut buffer = DynamicUniformBuffer::default();
390 buffer.push(&123.321);
391 assert_eq!(buffer.len(), 4);
392 buffer.push(&Vector3::new(1.0, 2.0, 3.0));
393 assert_eq!(buffer.len(), 28);
394 buffer.push(&Vector4::new(1.0, 2.0, 3.0, 4.0));
395 assert_eq!(buffer.len(), 48);
396 buffer.push(&Matrix3::default());
397 assert_eq!(buffer.len(), 96);
398 buffer.push(&123.0);
399 assert_eq!(buffer.len(), 100);
400 buffer.push(&[1.0, 2.0, 3.0, 4.0]);
401 assert_eq!(buffer.len(), 176);
402 buffer.push(&[1.0, 2.0, 3.0]);
403 assert_eq!(buffer.len(), 224);
404 buffer.push(&[1.0, 2.0]);
405 assert_eq!(buffer.len(), 256);
406 let bytes = buffer.finish();
407 assert_eq!(bytes.len(), 256);
408 }
409
410 #[test]
411 fn test_uniform_buffer_mixed_alignment() {
412 let mut buffer = DynamicUniformBuffer::default();
413 buffer.push(&Vector3::repeat(1.0));
414 assert_eq!(buffer.len(), 12);
415 buffer.push(&1.0);
416 assert_eq!(buffer.len(), 16);
417 }
418
419 #[test]
420 fn test_push_with_max_len() {
421 let mut buffer = DynamicUniformBuffer::default();
422 buffer.push_slice_with_max_size(&[1.0, 2.0, 3.0, 4.0], 6);
423 let floats: &[f32] = transmute_slice(buffer.storage().as_slice());
424 assert_eq!(
425 floats,
426 &[
427 1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ]
434 );
435 buffer.clear();
436 buffer.push_slice_with_max_size(&[1.0, 2.0], 1);
437 let floats: &[f32] = transmute_slice(buffer.storage().as_slice());
438 assert_eq!(floats, &[1.0, 0.0, 0.0, 0.0,]);
439 }
440}