OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2015 Google Inc. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license that can be | |
5 * found in the LICENSE file. | |
6 */ | |
7 | |
8 #ifndef SkNx_DEFINED | |
9 #define SkNx_DEFINED | |
10 | |
11 //#define SKNX_NO_SIMD | |
12 | |
13 #include "SkScalar.h" | |
14 #include "SkTypes.h" | |
15 #include <limits> | |
16 #include <math.h> | |
17 #include <type_traits> | |
18 | |
19 #define SI static inline | |
20 | |
21 // The default SkNx<N,T> just proxies down to a pair of SkNx<N/2, T>. | |
22 template <int N, typename T> | |
23 struct SkNx { | |
24 typedef SkNx<N/2, T> Half; | |
25 | |
26 Half fLo, fHi; | |
27 | |
28 SkNx() = default; | |
29 SkNx(const Half& lo, const Half& hi) : fLo(lo), fHi(hi) {} | |
30 | |
31 SkNx(T v) : fLo(v), fHi(v) {} | |
32 | |
33 SkNx(T a, T b) : fLo(a) , fHi(b) { static_assert(N==2, ""); } | |
34 SkNx(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) { static_assert(N==4, ""); } | |
35 SkNx(T a, T b, T c, T d, T e, T f, T g, T h) : fLo(a,b,c,d), fHi(e,f,g,h) { | |
36 static_assert(N==8, ""); | |
37 } | |
38 SkNx(T a, T b, T c, T d, T e, T f, T g, T h, | |
39 T i, T j, T k, T l, T m, T n, T o, T p) : fLo(a,b,c,d, e,f,g,h), fHi(i
,j,k,l, m,n,o,p) { | |
40 static_assert(N==16, ""); | |
41 } | |
42 | |
43 T operator[](int k) const { | |
44 SkASSERT(0 <= k && k < N); | |
45 return k < N/2 ? fLo[k] : fHi[k-N/2]; | |
46 } | |
47 | |
48 static SkNx Load(const void* vptr) { | |
49 auto ptr = (const char*)vptr; | |
50 return { Half::Load(ptr), Half::Load(ptr + N/2*sizeof(T)) }; | |
51 } | |
52 void store(void* vptr) const { | |
53 auto ptr = (char*)vptr; | |
54 fLo.store(ptr); | |
55 fHi.store(ptr + N/2*sizeof(T)); | |
56 } | |
57 | |
58 bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } | |
59 bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } | |
60 | |
61 SkNx abs() const { return { fLo. abs(), fHi. abs() }; } | |
62 SkNx sqrt() const { return { fLo. sqrt(), fHi. sqrt() }; } | |
63 SkNx rsqrt() const { return { fLo. rsqrt(), fHi. rsqrt() }; } | |
64 SkNx floor() const { return { fLo. floor(), fHi. floor() }; } | |
65 SkNx invert() const { return { fLo.invert(), fHi.invert() }; } | |
66 | |
67 SkNx operator!() const { return { !fLo, !fHi }; } | |
68 SkNx operator-() const { return { -fLo, -fHi }; } | |
69 SkNx operator~() const { return { ~fLo, ~fHi }; } | |
70 | |
71 SkNx operator<<(int bits) const { return { fLo << bits, fHi << bits }; } | |
72 SkNx operator>>(int bits) const { return { fLo >> bits, fHi >> bits }; } | |
73 | |
74 SkNx operator+(const SkNx& y) const { return { fLo + y.fLo, fHi + y.fHi }; } | |
75 SkNx operator-(const SkNx& y) const { return { fLo - y.fLo, fHi - y.fHi }; } | |
76 SkNx operator*(const SkNx& y) const { return { fLo * y.fLo, fHi * y.fHi }; } | |
77 SkNx operator/(const SkNx& y) const { return { fLo / y.fLo, fHi / y.fHi }; } | |
78 | |
79 SkNx operator&(const SkNx& y) const { return { fLo & y.fLo, fHi & y.fHi }; } | |
80 SkNx operator|(const SkNx& y) const { return { fLo | y.fLo, fHi | y.fHi }; } | |
81 SkNx operator^(const SkNx& y) const { return { fLo ^ y.fLo, fHi ^ y.fHi }; } | |
82 | |
83 SkNx operator==(const SkNx& y) const { return { fLo == y.fLo, fHi == y.fHi }
; } | |
84 SkNx operator!=(const SkNx& y) const { return { fLo != y.fLo, fHi != y.fHi }
; } | |
85 SkNx operator<=(const SkNx& y) const { return { fLo <= y.fLo, fHi <= y.fHi }
; } | |
86 SkNx operator>=(const SkNx& y) const { return { fLo >= y.fLo, fHi >= y.fHi }
; } | |
87 SkNx operator< (const SkNx& y) const { return { fLo < y.fLo, fHi < y.fHi }
; } | |
88 SkNx operator> (const SkNx& y) const { return { fLo > y.fLo, fHi > y.fHi }
; } | |
89 | |
90 SkNx saturatedAdd(const SkNx& y) const { | |
91 return { fLo.saturatedAdd(y.fLo), fHi.saturatedAdd(y.fHi) }; | |
92 } | |
93 SkNx thenElse(const SkNx& t, const SkNx& e) const { | |
94 return { fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi) }; | |
95 } | |
96 | |
97 static SkNx Min(const SkNx& x, const SkNx& y) { | |
98 return { Half::Min(x.fLo, y.fLo), Half::Min(x.fHi, y.fHi) }; | |
99 } | |
100 static SkNx Max(const SkNx& x, const SkNx& y) { | |
101 return { Half::Max(x.fLo, y.fLo), Half::Max(x.fHi, y.fHi) }; | |
102 } | |
103 }; | |
104 | |
105 // The N -> N/2 recursion bottoms out at N == 1, a scalar value. | |
106 template <typename T> | |
107 struct SkNx<1,T> { | |
108 T fVal; | |
109 | |
110 SkNx() = default; | |
111 SkNx(T v) : fVal(v) {} | |
112 | |
113 T operator[](int k) const { | |
114 SkASSERT(k == 0); | |
115 return fVal; | |
116 } | |
117 | |
118 static SkNx Load(const void* ptr) { | |
119 SkNx v; | |
120 memcpy(&v, ptr, sizeof(T)); | |
121 return v; | |
122 } | |
123 void store(void* ptr) const { memcpy(ptr, &fVal, sizeof(T)); } | |
124 | |
125 bool anyTrue() const { return fVal != 0; } | |
126 bool allTrue() const { return fVal != 0; } | |
127 | |
128 SkNx abs() const { return Abs(fVal); } | |
129 SkNx sqrt() const { return Sqrt(fVal); } | |
130 SkNx rsqrt() const { return T(1) / this->sqrt(); } | |
131 SkNx floor() const { return Floor(fVal); } | |
132 SkNx invert() const { return T(1) / *this; } | |
133 | |
134 SkNx operator!() const { return !fVal; } | |
135 SkNx operator-() const { return -fVal; } | |
136 SkNx operator~() const { return FromBits(~ToBits(fVal)); } | |
137 | |
138 SkNx operator<<(int bits) const { return fVal << bits; } | |
139 SkNx operator>>(int bits) const { return fVal >> bits; } | |
140 | |
141 SkNx operator+(const SkNx& y) const { return fVal + y.fVal; } | |
142 SkNx operator-(const SkNx& y) const { return fVal - y.fVal; } | |
143 SkNx operator*(const SkNx& y) const { return fVal * y.fVal; } | |
144 SkNx operator/(const SkNx& y) const { return fVal / y.fVal; } | |
145 | |
146 SkNx operator&(const SkNx& y) const { return FromBits(ToBits(fVal) & ToBits(
y.fVal)); } | |
147 SkNx operator|(const SkNx& y) const { return FromBits(ToBits(fVal) | ToBits(
y.fVal)); } | |
148 SkNx operator^(const SkNx& y) const { return FromBits(ToBits(fVal) ^ ToBits(
y.fVal)); } | |
149 | |
150 SkNx operator==(const SkNx& y) const { return FromBits(fVal == y.fVal ? ~0 :
0); } | |
151 SkNx operator!=(const SkNx& y) const { return FromBits(fVal != y.fVal ? ~0 :
0); } | |
152 SkNx operator<=(const SkNx& y) const { return FromBits(fVal <= y.fVal ? ~0 :
0); } | |
153 SkNx operator>=(const SkNx& y) const { return FromBits(fVal >= y.fVal ? ~0 :
0); } | |
154 SkNx operator< (const SkNx& y) const { return FromBits(fVal < y.fVal ? ~0 :
0); } | |
155 SkNx operator> (const SkNx& y) const { return FromBits(fVal > y.fVal ? ~0 :
0); } | |
156 | |
157 static SkNx Min(const SkNx& x, const SkNx& y) { return x.fVal < y.fVal ? x :
y; } | |
158 static SkNx Max(const SkNx& x, const SkNx& y) { return x.fVal > y.fVal ? x :
y; } | |
159 | |
160 SkNx saturatedAdd(const SkNx& y) const { | |
161 static_assert(std::is_unsigned<T>::value, ""); | |
162 T sum = fVal + y.fVal; | |
163 return sum < fVal ? std::numeric_limits<T>::max() : sum; | |
164 } | |
165 | |
166 SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e
; } | |
167 | |
168 private: | |
169 // Helper functions to choose the right float/double methods. (In <cmath> m
adness lies...) | |
170 static float Abs(float val) { return ::fabsf(val); } | |
171 static float Sqrt(float val) { return ::sqrtf(val); } | |
172 static float Floor(float val) { return ::floorf(val); } | |
173 | |
174 static double Abs(double val) { return ::fabs(val); } | |
175 static double Sqrt(double val) { return ::sqrt(val); } | |
176 static double Floor(double val) { return ::floor(val); } | |
177 | |
178 // Helper functions for working with floats/doubles as bit patterns. | |
179 template <typename U> static U ToBits(U v) { return v; } | |
180 static int32_t ToBits(float v) { int32_t bits; memcpy(&bits, &v, sizeof(v))
; return bits; } | |
181 static int64_t ToBits(double v) { int64_t bits; memcpy(&bits, &v, sizeof(v))
; return bits; } | |
182 | |
183 template <typename Bits> static T FromBits(Bits bits) { | |
184 static_assert(std::is_pod<T >::value && | |
185 std::is_pod<Bits>::value && | |
186 sizeof(T) <= sizeof(Bits), ""); | |
187 T val; | |
188 memcpy(&val, &bits, sizeof(T)); | |
189 return val; | |
190 } | |
191 }; | |
192 | |
193 // Allow scalars on the left or right of binary operators, and things like +=, &
=, etc. | |
194 #define V template <int N, typename T> SI SkNx<N,T> | |
195 V operator+ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) + y; } | |
196 V operator- (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) - y; } | |
197 V operator* (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) * y; } | |
198 V operator/ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) / y; } | |
199 V operator& (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) & y; } | |
200 V operator| (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) | y; } | |
201 V operator^ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) ^ y; } | |
202 V operator==(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) == y; } | |
203 V operator!=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) != y; } | |
204 V operator<=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) <= y; } | |
205 V operator>=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) >= y; } | |
206 V operator< (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) < y; } | |
207 V operator> (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) > y; } | |
208 | |
209 V operator+ (const SkNx<N,T>& x, T y) { return x + SkNx<N,T>(y); } | |
210 V operator- (const SkNx<N,T>& x, T y) { return x - SkNx<N,T>(y); } | |
211 V operator* (const SkNx<N,T>& x, T y) { return x * SkNx<N,T>(y); } | |
212 V operator/ (const SkNx<N,T>& x, T y) { return x / SkNx<N,T>(y); } | |
213 V operator& (const SkNx<N,T>& x, T y) { return x & SkNx<N,T>(y); } | |
214 V operator| (const SkNx<N,T>& x, T y) { return x | SkNx<N,T>(y); } | |
215 V operator^ (const SkNx<N,T>& x, T y) { return x ^ SkNx<N,T>(y); } | |
216 V operator==(const SkNx<N,T>& x, T y) { return x == SkNx<N,T>(y); } | |
217 V operator!=(const SkNx<N,T>& x, T y) { return x != SkNx<N,T>(y); } | |
218 V operator<=(const SkNx<N,T>& x, T y) { return x <= SkNx<N,T>(y); } | |
219 V operator>=(const SkNx<N,T>& x, T y) { return x >= SkNx<N,T>(y); } | |
220 V operator< (const SkNx<N,T>& x, T y) { return x < SkNx<N,T>(y); } | |
221 V operator> (const SkNx<N,T>& x, T y) { return x > SkNx<N,T>(y); } | |
222 | |
223 V& operator<<=(SkNx<N,T>& x, int bits) { return (x = x << bits); } | |
224 V& operator>>=(SkNx<N,T>& x, int bits) { return (x = x >> bits); } | |
225 | |
226 V& operator +=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x + y); } | |
227 V& operator -=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x - y); } | |
228 V& operator *=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x * y); } | |
229 V& operator /=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x / y); } | |
230 V& operator &=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x & y); } | |
231 V& operator |=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x | y); } | |
232 V& operator ^=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x ^ y); } | |
233 | |
234 V& operator +=(SkNx<N,T>& x, T y) { return (x = x + SkNx<N,T>(y)); } | |
235 V& operator -=(SkNx<N,T>& x, T y) { return (x = x - SkNx<N,T>(y)); } | |
236 V& operator *=(SkNx<N,T>& x, T y) { return (x = x * SkNx<N,T>(y)); } | |
237 V& operator /=(SkNx<N,T>& x, T y) { return (x = x / SkNx<N,T>(y)); } | |
238 V& operator &=(SkNx<N,T>& x, T y) { return (x = x & SkNx<N,T>(y)); } | |
239 V& operator |=(SkNx<N,T>& x, T y) { return (x = x | SkNx<N,T>(y)); } | |
240 V& operator ^=(SkNx<N,T>& x, T y) { return (x = x ^ SkNx<N,T>(y)); } | |
241 #undef V | |
242 | |
243 // SkNx<N,T> ~~> SkNx<N/2,T> + SkNx<N/2,T> | |
244 template <int N, typename T> | |
245 SI void SkNx_split(const SkNx<N,T>& v, SkNx<N/2,T>* lo, SkNx<N/2,T>* hi) { | |
246 *lo = v.fLo; | |
247 *hi = v.fHi; | |
248 } | |
249 | |
250 // SkNx<N/2,T> + SkNx<N/2,T> ~~> SkNx<N,T> | |
251 template <int N, typename T> | |
252 SI SkNx<N*2,T> SkNx_join(const SkNx<N,T>& lo, const SkNx<N,T>& hi) { | |
253 return { lo, hi }; | |
254 } | |
255 | |
256 // A very generic shuffle. Can reorder, duplicate, contract, expand... | |
257 // Sk4f v = { R,G,B,A }; | |
258 // SkNx_shuffle<2,1,0,3>(v) ~~> {B,G,R,A} | |
259 // SkNx_shuffle<2,1>(v) ~~> {B,G} | |
260 // SkNx_shuffle<2,1,2,1,2,1,2,1>(v) ~~> {B,G,B,G,B,G,B,G} | |
261 // SkNx_shuffle<3,3,3,3>(v) ~~> {A,A,A,A} | |
262 template <int... Ix, int N, typename T> | |
263 SI SkNx<sizeof...(Ix),T> SkNx_shuffle(const SkNx<N,T>& v) { | |
264 return { v[Ix]... }; | |
265 } | |
266 | |
267 // Cast from SkNx<N, Src> to SkNx<N, Dst>, as if you called static_cast<Dst>(Src
). | |
268 template <typename Dst, typename Src, int N> | |
269 SI SkNx<N,Dst> SkNx_cast(const SkNx<N,Src>& v) { | |
270 return { SkNx_cast<Dst>(v.fLo), SkNx_cast<Dst>(v.fHi) }; | |
271 } | |
272 template <typename Dst, typename Src> | |
273 SI SkNx<1,Dst> SkNx_cast(const SkNx<1,Src>& v) { | |
274 return static_cast<Dst>(v.fVal); | |
275 } | |
276 | |
277 typedef SkNx<2, float> Sk2f; | |
278 typedef SkNx<4, float> Sk4f; | |
279 typedef SkNx<8, float> Sk8f; | |
280 typedef SkNx<16, float> Sk16f; | |
281 | |
282 typedef SkNx<2, SkScalar> Sk2s; | |
283 typedef SkNx<4, SkScalar> Sk4s; | |
284 typedef SkNx<8, SkScalar> Sk8s; | |
285 typedef SkNx<16, SkScalar> Sk16s; | |
286 | |
287 typedef SkNx<4, uint8_t> Sk4b; | |
288 typedef SkNx<8, uint8_t> Sk8b; | |
289 typedef SkNx<16, uint8_t> Sk16b; | |
290 | |
291 typedef SkNx<4, uint16_t> Sk4h; | |
292 typedef SkNx<8, uint16_t> Sk8h; | |
293 typedef SkNx<16, uint16_t> Sk16h; | |
294 | |
295 typedef SkNx<4, int> Sk4i; | |
296 | |
297 // Include platform specific specializations if available. | |
298 #if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 | |
299 #include "../opts/SkNx_sse.h" | |
300 #elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) | |
301 #include "../opts/SkNx_neon.h" | |
302 #endif | |
303 | |
304 SI void Sk4f_ToBytes(uint8_t p[16], const Sk4f& a, const Sk4f& b, const Sk4f& c,
const Sk4f& d) { | |
305 SkNx_cast<uint8_t>(SkNx_join(SkNx_join(a,b), SkNx_join(c,d))).store(p); | |
306 } | |
307 | |
308 #undef SI | |
309 | |
310 #endif//SkNx_DEFINED | |
OLD | NEW |