tiny_skia/wide/
f32x16_t.rs

1// Copyright 2020 Yevhenii Reizner
2//
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5
6use super::{f32x8, u16x16};
7
8#[derive(Copy, Clone, Debug)]
9#[repr(C, align(32))]
10pub struct f32x16(pub f32x8, pub f32x8);
11
12unsafe impl bytemuck::Zeroable for f32x16 {}
13unsafe impl bytemuck::Pod for f32x16 {}
14
15impl Default for f32x16 {
16    fn default() -> Self {
17        Self::splat(0.0)
18    }
19}
20
21impl f32x16 {
22    pub fn splat(n: f32) -> Self {
23        Self(f32x8::splat(n), f32x8::splat(n))
24    }
25
26    #[inline]
27    pub fn abs(&self) -> Self {
28        // Yes, Skia does it in the same way.
29        let abs = |x| bytemuck::cast::<i32, f32>(bytemuck::cast::<f32, i32>(x) & 0x7fffffff);
30
31        let n0: [f32; 8] = self.0.into();
32        let n1: [f32; 8] = self.1.into();
33        Self(
34            f32x8::from([
35                abs(n0[0]),
36                abs(n0[1]),
37                abs(n0[2]),
38                abs(n0[3]),
39                abs(n0[4]),
40                abs(n0[5]),
41                abs(n0[6]),
42                abs(n0[7]),
43            ]),
44            f32x8::from([
45                abs(n1[0]),
46                abs(n1[1]),
47                abs(n1[2]),
48                abs(n1[3]),
49                abs(n1[4]),
50                abs(n1[5]),
51                abs(n1[6]),
52                abs(n1[7]),
53            ]),
54        )
55    }
56
57    pub fn cmp_gt(self, rhs: &Self) -> Self {
58        Self(self.0.cmp_gt(rhs.0), self.1.cmp_gt(rhs.1))
59    }
60
61    pub fn blend(self, t: Self, f: Self) -> Self {
62        Self(self.0.blend(t.0, f.0), self.1.blend(t.1, f.1))
63    }
64
65    pub fn normalize(&self) -> Self {
66        Self(self.0.normalize(), self.1.normalize())
67    }
68
69    pub fn floor(&self) -> Self {
70        // Yes, Skia does it in the same way.
71        let roundtrip = self.round();
72        roundtrip
73            - roundtrip
74                .cmp_gt(self)
75                .blend(f32x16::splat(1.0), f32x16::splat(0.0))
76    }
77
78    pub fn sqrt(&self) -> Self {
79        Self(self.0.sqrt(), self.1.sqrt())
80    }
81
82    pub fn round(&self) -> Self {
83        Self(self.0.round(), self.1.round())
84    }
85
86    // This method is too heavy and shouldn't be inlined.
87    pub fn save_to_u16x16(&self, dst: &mut u16x16) {
88        // Do not use to_i32x8, because it involves rounding,
89        // and Skia cast's without it.
90
91        let n0: [f32; 8] = self.0.into();
92        let n1: [f32; 8] = self.1.into();
93
94        dst.0[0] = n0[0] as u16;
95        dst.0[1] = n0[1] as u16;
96        dst.0[2] = n0[2] as u16;
97        dst.0[3] = n0[3] as u16;
98
99        dst.0[4] = n0[4] as u16;
100        dst.0[5] = n0[5] as u16;
101        dst.0[6] = n0[6] as u16;
102        dst.0[7] = n0[7] as u16;
103
104        dst.0[8] = n1[0] as u16;
105        dst.0[9] = n1[1] as u16;
106        dst.0[10] = n1[2] as u16;
107        dst.0[11] = n1[3] as u16;
108
109        dst.0[12] = n1[4] as u16;
110        dst.0[13] = n1[5] as u16;
111        dst.0[14] = n1[6] as u16;
112        dst.0[15] = n1[7] as u16;
113    }
114}
115
116impl core::ops::Add<f32x16> for f32x16 {
117    type Output = Self;
118
119    fn add(self, rhs: Self) -> Self::Output {
120        Self(self.0 + rhs.0, self.1 + rhs.1)
121    }
122}
123
124impl core::ops::Sub<f32x16> for f32x16 {
125    type Output = Self;
126
127    fn sub(self, rhs: Self) -> Self::Output {
128        Self(self.0 - rhs.0, self.1 - rhs.1)
129    }
130}
131
132impl core::ops::Mul<f32x16> for f32x16 {
133    type Output = Self;
134
135    fn mul(self, rhs: Self) -> Self::Output {
136        Self(self.0 * rhs.0, self.1 * rhs.1)
137    }
138}