luminance_std140/
lib.rs

1//! Types and traits implementing the [std140] OpenGL rule.
2//!
3//! [std140]: https://www.khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf#page=159
4
5use luminance::shader::types::{Mat22, Mat33, Mat44, Vec2, Vec3, Vec4};
6
7/// Types that have a `std140` representation.
8///
9/// This trait allows to encode types into their `std140` representation but also decode such representation into the
10/// proper type.
11pub trait Std140: Copy {
12  type Encoded: Copy;
13
14  /// Encode the value into its `std140` representation.
15  fn std140_encode(self) -> Self::Encoded;
16
17  /// Decode a value from its `std140` representation.
18  fn std140_decode(encoded: Self::Encoded) -> Self;
19}
20
21/// 4-bytes aligned wrapper.
22///
23/// This wrapper type wraps its inner type on 4-bytes, allowing for fast encode/decode operations.
24#[repr(C, align(4))]
25#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
26pub struct Aligned4<T>(pub T);
27
28/// 8-bytes aligned wrapper.
29///
30/// This wrapper type wraps its inner type on 8-bytes, allowing for fast encode/decode operations.
31#[repr(C, align(8))]
32#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
33pub struct Aligned8<T>(pub T);
34
35/// 16-bytes aligned wrapper.
36///
37/// This wrapper type wraps its inner type on 16-bytes, allowing for fast encode/decode operations.
38#[repr(C, align(16))]
39#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
40pub struct Aligned16<T>(pub T);
41
42/// 32-bytes aligned wrapper.
43///
44/// This wrapper type wraps its inner type on 32-bytes, allowing for fast encode/decode operations.
45#[repr(C, align(32))]
46#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
47pub struct Aligned32<T>(pub T);
48
49/// Implement [`Std140`] for a type as an identity
50macro_rules! impl_Std140_id {
51  ($t:ty) => {
52    impl Std140 for $t {
53      type Encoded = $t;
54
55      fn std140_encode(self) -> Self::Encoded {
56        self
57      }
58
59      fn std140_decode(encoded: Self::Encoded) -> Self {
60        encoded
61      }
62    }
63  };
64}
65
66/// Implement [`Std140`] for a type by wrapping it in [`Aligned4`].
67macro_rules! impl_Std140_Aligned4 {
68  ($t:ty) => {
69    impl Std140 for $t {
70      type Encoded = Aligned4<$t>;
71
72      fn std140_encode(self) -> Self::Encoded {
73        Aligned4(self)
74      }
75
76      fn std140_decode(encoded: Self::Encoded) -> Self {
77        encoded.0
78      }
79    }
80  };
81}
82
83/// Implement [`Std140`] for a type by wrapping it in [`Aligned8`].
84macro_rules! impl_Std140_Aligned8 {
85  ($t:ty) => {
86    impl Std140 for $t {
87      type Encoded = Aligned8<$t>;
88
89      fn std140_encode(self) -> Self::Encoded {
90        Aligned8(self)
91      }
92
93      fn std140_decode(encoded: Self::Encoded) -> Self {
94        encoded.0
95      }
96    }
97  };
98}
99
100/// Implement [`Std140`] for a type by wrapping it in [`Aligned16`].
101macro_rules! impl_Std140_Aligned16 {
102  ($t:ty) => {
103    impl Std140 for $t {
104      type Encoded = Aligned16<$t>;
105
106      fn std140_encode(self) -> Self::Encoded {
107        Aligned16(self)
108      }
109
110      fn std140_decode(encoded: Self::Encoded) -> Self {
111        encoded.0
112      }
113    }
114  };
115}
116
117/// Implement [`Std140`] for a type by wrapping it in [`Aligned32`].
118macro_rules! impl_Std140_Aligned32 {
119  ($t:ty) => {
120    impl Std140 for $t {
121      type Encoded = Aligned32<$t>;
122
123      fn std140_encode(self) -> Self::Encoded {
124        Aligned32(self)
125      }
126
127      fn std140_decode(encoded: Self::Encoded) -> Self {
128        encoded.0
129      }
130    }
131  };
132}
133
134impl_Std140_id!(f32);
135impl_Std140_Aligned8!(Vec2<f32>);
136impl_Std140_Aligned16!(Vec3<f32>);
137impl_Std140_Aligned16!(Vec4<f32>);
138
139impl_Std140_id!(f64);
140impl_Std140_Aligned16!(Vec2<f64>);
141impl_Std140_Aligned32!(Vec3<f64>);
142impl_Std140_Aligned32!(Vec4<f64>);
143
144impl_Std140_id!(i32);
145impl_Std140_Aligned8!(Vec2<i32>);
146impl_Std140_Aligned16!(Vec3<i32>);
147impl_Std140_Aligned16!(Vec4<i32>);
148
149impl_Std140_id!(u32);
150impl_Std140_Aligned8!(Vec2<u32>);
151impl_Std140_Aligned16!(Vec3<u32>);
152impl_Std140_Aligned16!(Vec4<u32>);
153
154impl_Std140_Aligned4!(bool);
155
156impl Std140 for Vec2<bool> {
157  type Encoded = Aligned8<Vec2<Aligned4<bool>>>;
158
159  fn std140_encode(self) -> Self::Encoded {
160    let Vec2([x, y]) = self;
161    Aligned8(Vec2::new(Aligned4(x), Aligned4(y)))
162  }
163
164  fn std140_decode(encoded: Self::Encoded) -> Self {
165    let Aligned8(Vec2([Aligned4(x), Aligned4(y)])) = encoded;
166    Vec2::new(x, y)
167  }
168}
169
170impl_Std140_Aligned16!(Vec3<bool>);
171impl_Std140_Aligned16!(Vec4<bool>);
172
173impl Std140 for Mat22<f32> {
174  type Encoded = Aligned16<[Aligned16<[f32; 2]>; 2]>;
175
176  fn std140_encode(self) -> Self::Encoded {
177    let [a, b]: [[f32; 2]; 2] = self.into();
178    Aligned16([Aligned16(a), Aligned16(b)])
179  }
180
181  fn std140_decode(encoded: Self::Encoded) -> Self {
182    let Aligned16([Aligned16(a), Aligned16(b)]) = encoded;
183    [a, b].into()
184  }
185}
186
187impl Std140 for Mat22<f64> {
188  type Encoded = Aligned32<[Aligned32<[f64; 2]>; 2]>;
189
190  fn std140_encode(self) -> Self::Encoded {
191    let [a, b]: [[f64; 2]; 2] = self.into();
192    Aligned32([Aligned32(a), Aligned32(b)])
193  }
194
195  fn std140_decode(encoded: Self::Encoded) -> Self {
196    let Aligned32([Aligned32(a), Aligned32(b)]) = encoded;
197    [a, b].into()
198  }
199}
200
201impl Std140 for Mat33<f32> {
202  type Encoded = Aligned16<[Aligned16<[f32; 3]>; 3]>;
203
204  fn std140_encode(self) -> Self::Encoded {
205    let [a, b, c]: [[f32; 3]; 3] = self.into();
206    Aligned16([Aligned16(a), Aligned16(b), Aligned16(c)])
207  }
208
209  fn std140_decode(encoded: Self::Encoded) -> Self {
210    let Aligned16([Aligned16(a), Aligned16(b), Aligned16(c)]) = encoded;
211    [a, b, c].into()
212  }
213}
214
215impl Std140 for Mat33<f64> {
216  type Encoded = Aligned32<[Aligned32<[f64; 3]>; 3]>;
217
218  fn std140_encode(self) -> Self::Encoded {
219    let [a, b, c]: [[f64; 3]; 3] = self.into();
220    Aligned32([Aligned32(a), Aligned32(b), Aligned32(c)])
221  }
222
223  fn std140_decode(encoded: Self::Encoded) -> Self {
224    let Aligned32([Aligned32(a), Aligned32(b), Aligned32(c)]) = encoded;
225    [a, b, c].into()
226  }
227}
228
229impl Std140 for Mat44<f32> {
230  type Encoded = Aligned16<[Aligned16<[f32; 4]>; 4]>;
231
232  fn std140_encode(self) -> Self::Encoded {
233    let [a, b, c, d]: [[f32; 4]; 4] = self.into();
234    Aligned16([Aligned16(a), Aligned16(b), Aligned16(c), Aligned16(d)])
235  }
236
237  fn std140_decode(encoded: Self::Encoded) -> Self {
238    let Aligned16([Aligned16(a), Aligned16(b), Aligned16(c), Aligned16(d)]) = encoded;
239    [a, b, c, d].into()
240  }
241}
242
243impl Std140 for Mat44<f64> {
244  type Encoded = Aligned32<[Aligned32<[f64; 4]>; 4]>;
245
246  fn std140_encode(self) -> Self::Encoded {
247    let [a, b, c, d]: [[f64; 4]; 4] = self.into();
248    Aligned32([Aligned32(a), Aligned32(b), Aligned32(c), Aligned32(d)])
249  }
250
251  fn std140_decode(encoded: Self::Encoded) -> Self {
252    let Aligned32([Aligned32(a), Aligned32(b), Aligned32(c), Aligned32(d)]) = encoded;
253    [a, b, c, d].into()
254  }
255}
256
257/// Type wrapper for values inside arrays.
258#[repr(transparent)]
259#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
260pub struct ArrElem<T>(pub T);
261
262impl<T> Std140 for ArrElem<T>
263where
264  T: Std140,
265{
266  type Encoded = Aligned16<<T as Std140>::Encoded>;
267
268  fn std140_encode(self) -> Self::Encoded {
269    Aligned16(self.0.std140_encode())
270  }
271
272  fn std140_decode(encoded: Self::Encoded) -> Self {
273    ArrElem(<T as Std140>::std140_decode(encoded.0))
274  }
275}
276
277#[cfg(test)]
278mod tests {
279  use super::*;
280  use luminance::shader::types::{Vec3, Vec4};
281  use std::mem;
282
283  fn assert_size_align<T>(size: usize, align: usize)
284  where
285    T: Std140,
286  {
287    assert_eq!(mem::size_of::<<T as Std140>::Encoded>(), size);
288    assert_eq!(mem::align_of::<<T as Std140>::Encoded>(), align);
289  }
290
291  #[test]
292  fn f32() {
293    assert_size_align::<f32>(4, 4);
294  }
295
296  #[test]
297  fn aligned16() {
298    assert_eq!(std::mem::size_of::<Aligned16<f32>>(), 16);
299    assert_eq!(std::mem::size_of::<Aligned16<Aligned16<f32>>>(), 16);
300  }
301
302  #[test]
303  fn vec2() {
304    assert_size_align::<Vec2<f32>>(8, 8);
305    assert_size_align::<Vec2<f64>>(16, 16);
306  }
307
308  #[test]
309  fn vec3() {
310    assert_size_align::<Vec3<f32>>(16, 16);
311    assert_size_align::<Vec3<f64>>(32, 32);
312  }
313
314  #[test]
315  fn vec4() {
316    assert_size_align::<Vec4<f32>>(16, 16);
317    assert_size_align::<Vec4<f64>>(32, 32);
318  }
319
320  #[test]
321  fn i32() {
322    assert_size_align::<i32>(4, 4);
323  }
324
325  #[test]
326  fn ivec2() {
327    assert_size_align::<Vec2<i32>>(8, 8);
328  }
329
330  #[test]
331  fn ivec3() {
332    assert_size_align::<Vec3<i32>>(16, 16);
333  }
334
335  #[test]
336  fn ivec4() {
337    assert_size_align::<Vec4<i32>>(16, 16);
338  }
339
340  #[test]
341  fn u32() {
342    assert_size_align::<u32>(4, 4);
343  }
344
345  #[test]
346  fn uvec2() {
347    assert_size_align::<Vec2<u32>>(8, 8);
348  }
349
350  #[test]
351  fn uvec3() {
352    assert_size_align::<Vec3<i32>>(16, 16);
353  }
354
355  #[test]
356  fn uvec4() {
357    assert_size_align::<Vec4<i32>>(16, 16);
358  }
359
360  #[test]
361  fn bool() {
362    assert_size_align::<bool>(4, 4);
363  }
364
365  #[test]
366  fn bvec2() {
367    assert_size_align::<Vec2<bool>>(8, 8);
368  }
369
370  #[test]
371  fn bvec3() {
372    assert_size_align::<Vec3<bool>>(16, 16);
373  }
374
375  #[test]
376  fn bvec4() {
377    assert_size_align::<Vec4<bool>>(16, 16);
378  }
379
380  #[test]
381  fn mat22() {
382    assert_size_align::<Mat22<f32>>(32, 16);
383  }
384
385  #[test]
386  fn mat33() {
387    assert_size_align::<Mat33<f32>>(48, 16);
388  }
389
390  #[test]
391  fn mat44() {
392    assert_size_align::<Mat44<f32>>(64, 16);
393  }
394
395  #[test]
396  fn vec2_arrayed() {
397    assert_size_align::<ArrElem<Vec2<f32>>>(16, 16);
398    assert_size_align::<ArrElem<Vec2<f64>>>(16, 16);
399  }
400
401  #[test]
402  fn vec3_array() {
403    assert_size_align::<ArrElem<Vec3<f32>>>(16, 16);
404    assert_size_align::<ArrElem<Vec3<f64>>>(32, 32);
405  }
406
407  #[test]
408  fn vec4_array() {
409    assert_size_align::<ArrElem<Vec4<f32>>>(16, 16);
410    assert_size_align::<ArrElem<Vec4<f64>>>(32, 32);
411  }
412
413  #[test]
414  fn mat22_array() {
415    assert_size_align::<ArrElem<Mat22<f32>>>(32, 16);
416    assert_size_align::<ArrElem<Mat22<f64>>>(64, 32);
417  }
418
419  #[test]
420  fn mat33_array() {
421    assert_size_align::<ArrElem<Mat33<f32>>>(48, 16);
422    assert_size_align::<ArrElem<Mat33<f64>>>(96, 32);
423  }
424
425  #[test]
426  fn mat44_array() {
427    assert_size_align::<ArrElem<Mat44<f32>>>(64, 16);
428    assert_size_align::<ArrElem<Mat44<f64>>>(128, 32);
429  }
430}