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: Default {
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}
47
48impl<const N: usize> ByteStorage for ArrayVec<u8, N> {
49 fn reset(&mut self) {
50 self.clear();
51 }
52
53 fn bytes(&self) -> &[u8] {
54 self.as_slice()
55 }
56
57 fn bytes_count(&self) -> usize {
58 self.len()
59 }
60
61 fn write_bytes(&mut self, bytes: &[u8]) {
62 self.try_extend_from_slice(bytes).unwrap()
63 }
64
65 fn write_zeros(&mut self, count: usize) {
66 let old_len = self.len();
67 let new_len = old_len + count;
68 assert!(new_len <= self.capacity());
69 unsafe {
71 self.set_len(new_len);
72 std::ptr::write_bytes(self.as_mut_ptr().add(old_len), 0, count)
73 }
74 }
75}
76
77impl ByteStorage for Vec<u8> {
78 fn reset(&mut self) {
79 self.clear();
80 }
81
82 fn bytes(&self) -> &[u8] {
83 self.as_slice()
84 }
85
86 fn bytes_count(&self) -> usize {
87 self.len()
88 }
89
90 fn write_bytes(&mut self, bytes: &[u8]) {
91 self.extend_from_slice(bytes)
92 }
93
94 #[allow(clippy::uninit_vec)]
97 fn write_zeros(&mut self, count: usize) {
98 let old_len = self.len();
99 let new_len = old_len + count;
100 self.reserve(count);
101 unsafe {
103 self.set_len(new_len);
104 std::ptr::write_bytes(self.as_mut_ptr().add(old_len), 0, count)
105 }
106 }
107}
108
109#[derive(Default)]
127pub struct UniformBuffer<S: ByteStorage> {
128 storage: S,
129}
130
131pub type StaticUniformBuffer<const N: usize> = UniformBuffer<ArrayVec<u8, N>>;
133
134pub type DynamicUniformBuffer = UniformBuffer<Vec<u8>>;
136
137pub trait Std140 {
139 const ALIGNMENT: usize;
141
142 fn write<T: ByteStorage>(&self, dest: &mut T);
144}
145
146macro_rules! default_write_impl {
147 () => {
148 fn write<T: ByteStorage>(&self, dest: &mut T) {
149 dest.write_bytes(value_as_u8_slice(self))
150 }
151 };
152}
153
154impl Std140 for f32 {
155 const ALIGNMENT: usize = 4;
156 default_write_impl!();
157}
158
159impl Std140 for u32 {
160 const ALIGNMENT: usize = 4;
161 default_write_impl!();
162}
163
164impl Std140 for i32 {
165 const ALIGNMENT: usize = 4;
166 default_write_impl!();
167}
168
169impl Std140 for Vector2<f32> {
170 const ALIGNMENT: usize = 8;
171 default_write_impl!();
172}
173
174impl Std140 for Vector3<f32> {
175 const ALIGNMENT: usize = 16;
176 default_write_impl!();
177}
178
179impl Std140 for Vector4<f32> {
180 const ALIGNMENT: usize = 16;
181 default_write_impl!();
182}
183
184impl Std140 for [f32; 2] {
185 const ALIGNMENT: usize = 8;
186 default_write_impl!();
187}
188
189impl Std140 for [f32; 3] {
190 const ALIGNMENT: usize = 16;
191
192 fn write<T: ByteStorage>(&self, dest: &mut T) {
193 dest.write_bytes(value_as_u8_slice(self));
194 dest.write_bytes(&[0; size_of::<f32>()]);
195 }
196}
197
198impl Std140 for Matrix4<f32> {
199 const ALIGNMENT: usize = 16;
200 default_write_impl!();
201}
202
203impl Std140 for Matrix3<f32> {
204 const ALIGNMENT: usize = 16;
205
206 fn write<T: ByteStorage>(&self, dest: &mut T) {
207 for row in (self as &dyn AsRef<[[f32; 3]; 3]>).as_ref() {
208 dest.write_bytes(array_as_u8_slice(row));
209 dest.write_bytes(&[0; size_of::<f32>()]);
210 }
211 }
212}
213
214impl Std140 for Matrix2<f32> {
215 const ALIGNMENT: usize = 16;
216
217 fn write<T: ByteStorage>(&self, dest: &mut T) {
218 for row in (self as &dyn AsRef<[[f32; 2]; 2]>).as_ref() {
219 dest.write_bytes(array_as_u8_slice(row));
220 dest.write_bytes(&[0; 2 * size_of::<f32>()]);
221 }
222 }
223}
224
225impl Std140 for [f32; 4] {
226 const ALIGNMENT: usize = 16;
227 default_write_impl!();
228}
229
230impl Std140 for Color {
231 const ALIGNMENT: usize = 16;
232
233 fn write<T: ByteStorage>(&self, dest: &mut T) {
234 let frgba = self.as_frgba();
235 dest.write_bytes(value_as_u8_slice(&frgba));
236 }
237}
238
239impl Std140 for bool {
240 const ALIGNMENT: usize = 4;
241
242 fn write<T: ByteStorage>(&self, dest: &mut T) {
243 let integer = if *self { 1 } else { 0 };
244 dest.write_bytes(value_as_u8_slice(&integer));
245 }
246}
247
248impl<S> UniformBuffer<S>
249where
250 S: ByteStorage + Default,
251{
252 pub fn new() -> Self {
254 Self {
255 storage: S::default(),
256 }
257 }
258
259 pub fn with_storage(storage: S) -> Self {
261 Self { storage }
262 }
263
264 pub fn clear(&mut self) {
266 self.storage.reset();
267 }
268
269 pub fn len(&self) -> usize {
273 self.storage.bytes_count()
274 }
275
276 pub fn is_empty(&self) -> bool {
278 self.len() == 0
279 }
280
281 pub fn push_padding(&mut self, alignment: usize) {
283 debug_assert!(alignment.is_power_of_two());
284 let bytes_count = self.storage.bytes_count();
285 let remainder = (alignment - 1) & bytes_count;
286 if remainder > 0 {
287 let padding = alignment - remainder;
288 self.storage.write_zeros(padding);
289 }
290 }
291
292 pub fn push<T>(&mut self, value: &T) -> &mut Self
295 where
296 T: Std140,
297 {
298 self.push_padding(T::ALIGNMENT);
299 value.write(&mut self.storage);
300 self
301 }
302
303 pub fn with<T>(mut self, value: &T) -> Self
305 where
306 T: Std140,
307 {
308 self.push(value);
309 self
310 }
311
312 fn push_array_element<T: Std140>(&mut self, item: &T) {
313 self.push_padding(16);
314 item.write(&mut self.storage);
315 self.push_padding(16);
316 }
317
318 pub fn push_slice<T>(&mut self, slice: &[T]) -> &mut Self
322 where
323 T: Std140,
324 {
325 for item in slice {
326 self.push_array_element(item);
327 }
328 self
329 }
330
331 pub fn push_slice_with_max_size<T: Std140 + Default>(
334 &mut self,
335 slice: &[T],
336 max_len: usize,
337 ) -> &mut Self {
338 let len = slice.len();
339 if !slice.is_empty() {
340 let end = max_len.min(len);
341 self.push_slice(&slice[0..end]);
342 }
343 let remainder = max_len.saturating_sub(len);
344 let item = T::default();
345 for _ in 0..remainder {
346 self.push_array_element(&item);
347 }
348 self
349 }
350
351 pub fn with_slice_with_max_size<T: Std140 + Default>(
353 mut self,
354 slice: &[T],
355 max_len: usize,
356 ) -> Self {
357 self.push_slice_with_max_size(slice, max_len);
358 self
359 }
360
361 pub fn with_slice<T>(mut self, slice: &[T]) -> Self
363 where
364 T: Std140,
365 {
366 self.push_slice(slice);
367 self
368 }
369
370 pub fn storage(&self) -> &S {
372 &self.storage
373 }
374
375 pub fn finish(mut self) -> S {
379 self.push_padding(16);
380 self.storage
381 }
382
383 pub fn next_write_aligned_position(&self, alignment: usize) -> usize {
385 let position = self.storage.bytes_count();
386 let remainder = (alignment - 1) & position;
387 if remainder > 0 {
388 let padding = alignment - remainder;
389 position + padding
390 } else {
391 position
392 }
393 }
394
395 pub fn write_bytes_with_alignment(&mut self, bytes: &[u8], alignment: usize) -> usize {
399 self.push_padding(alignment);
400 let data_location = self.storage.bytes_count();
401 self.storage.write_bytes(bytes);
402 data_location
403 }
404}
405
406#[cfg(test)]
407mod test {
408 use crate::{
409 core::algebra::{Matrix3, Vector3, Vector4},
410 uniform::DynamicUniformBuffer,
411 };
412 use fyrox_core::transmute_slice;
413
414 #[test]
415 fn test_uniform_buffer() {
416 let mut buffer = DynamicUniformBuffer::default();
417 buffer.push(&123.321);
418 assert_eq!(buffer.len(), 4);
419 buffer.push(&Vector3::new(1.0, 2.0, 3.0));
420 assert_eq!(buffer.len(), 28);
421 buffer.push(&Vector4::new(1.0, 2.0, 3.0, 4.0));
422 assert_eq!(buffer.len(), 48);
423 buffer.push(&Matrix3::default());
424 assert_eq!(buffer.len(), 96);
425 buffer.push(&123.0);
426 assert_eq!(buffer.len(), 100);
427 buffer.push_slice(&[1.0, 2.0, 3.0, 4.0]);
428 assert_eq!(buffer.len(), 176);
429 let bytes = buffer.finish();
430 assert_eq!(bytes.len(), 176);
431 }
432
433 #[test]
434 fn test_uniform_buffer_mixed_alignment() {
435 let mut buffer = DynamicUniformBuffer::default();
436 buffer.push(&Vector3::repeat(1.0));
437 assert_eq!(buffer.len(), 12);
438 buffer.push(&1.0);
439 assert_eq!(buffer.len(), 16);
440 }
441
442 #[test]
443 fn test_push_with_max_len() {
444 let mut buffer = DynamicUniformBuffer::default();
445 buffer.push_slice_with_max_size(&[1.0, 2.0, 3.0, 4.0], 6);
446 let floats: &[f32] = transmute_slice(buffer.storage().as_slice());
447 assert_eq!(
448 floats,
449 &[
450 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, ]
457 );
458 buffer.clear();
459 buffer.push_slice_with_max_size(&[1.0, 2.0], 1);
460 let floats: &[f32] = transmute_slice(buffer.storage().as_slice());
461 assert_eq!(floats, &[1.0, 0.0, 0.0, 0.0,]);
462 }
463}