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#include "include/core/SkScalar.h"
12#include "include/core/SkTypes.h"
13#include "include/private/SkSafe_math.h"
14
15#include <algorithm>
16#include <limits>
17#include <type_traits>
18
19// Every single SkNx method wants to be fully inlined. (We know better than MSVC).
20#define AI SK_ALWAYS_INLINE
21
22namespace { // NOLINT(google-build-namespaces)
23
24// The default SkNx<N,T> just proxies down to a pair of SkNx<N/2, T>.
25template <int N, typename T>
26struct SkNx {
27 typedef SkNx<N/2, T> Half;
28
29 Half fLo, fHi;
30
31 AI SkNx() = default;
32 AI SkNx(const Half& lo, const Half& hi) : fLo(lo), fHi(hi) {}
33
34 AI SkNx(T v) : fLo(v), fHi(v) {}
35
36 AI SkNx(T a, T b) : fLo(a) , fHi(b) { static_assert(N==2, ""); }
37 AI SkNx(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) { static_assert(N==4, ""); }
38 AI 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) {
39 static_assert(N==8, "");
40 }
41 AI SkNx(T a, T b, T c, T d, T e, T f, T g, T h,
42 T i, T j, T k, T l, T m, T n, T o, T p)
43 : fLo(a,b,c,d, e,f,g,h), fHi(i,j,k,l, m,n,o,p) {
44 static_assert(N==16, "");
45 }
46
47 AI T operator[](int k) const {
48 SkASSERT(0 <= k && k < N);
49 return k < N/2 ? fLo[k] : fHi[k-N/2];
50 }
51
52 AI static SkNx Load(const void* vptr) {
53 auto ptr = (const char*)vptr;
54 return { Half::Load(ptr), Half::Load(ptr + N/2*sizeof(T)) };
55 }
56 AI void store(void* vptr) const {
57 auto ptr = (char*)vptr;
58 fLo.store(ptr);
59 fHi.store(ptr + N/2*sizeof(T));
60 }
61
62 AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) {
63 auto ptr = (const char*)vptr;
64 Half al, bl, cl, dl,
65 ah, bh, ch, dh;
66 Half::Load4(ptr , &al, &bl, &cl, &dl);
67 Half::Load4(ptr + 4*N/2*sizeof(T), &ah, &bh, &ch, &dh);
68 *a = SkNx{al, ah};
69 *b = SkNx{bl, bh};
70 *c = SkNx{cl, ch};
71 *d = SkNx{dl, dh};
72 }
73 AI static void Load3(const void* vptr, SkNx* a, SkNx* b, SkNx* c) {
74 auto ptr = (const char*)vptr;
75 Half al, bl, cl,
76 ah, bh, ch;
77 Half::Load3(ptr , &al, &bl, &cl);
78 Half::Load3(ptr + 3*N/2*sizeof(T), &ah, &bh, &ch);
79 *a = SkNx{al, ah};
80 *b = SkNx{bl, bh};
81 *c = SkNx{cl, ch};
82 }
83 AI static void Load2(const void* vptr, SkNx* a, SkNx* b) {
84 auto ptr = (const char*)vptr;
85 Half al, bl,
86 ah, bh;
87 Half::Load2(ptr , &al, &bl);
88 Half::Load2(ptr + 2*N/2*sizeof(T), &ah, &bh);
89 *a = SkNx{al, ah};
90 *b = SkNx{bl, bh};
91 }
92 AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) {
93 auto ptr = (char*)vptr;
94 Half::Store4(ptr, a.fLo, b.fLo, c.fLo, d.fLo);
95 Half::Store4(ptr + 4*N/2*sizeof(T), a.fHi, b.fHi, c.fHi, d.fHi);
96 }
97 AI static void Store3(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c) {
98 auto ptr = (char*)vptr;
99 Half::Store3(ptr, a.fLo, b.fLo, c.fLo);
100 Half::Store3(ptr + 3*N/2*sizeof(T), a.fHi, b.fHi, c.fHi);
101 }
102 AI static void Store2(void* vptr, const SkNx& a, const SkNx& b) {
103 auto ptr = (char*)vptr;
104 Half::Store2(ptr, a.fLo, b.fLo);
105 Half::Store2(ptr + 2*N/2*sizeof(T), a.fHi, b.fHi);
106 }
107
108 AI T min() const { return std::min(fLo.min(), fHi.min()); }
109 AI T max() const { return std::max(fLo.max(), fHi.max()); }
110 AI bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); }
111 AI bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); }
112
113 AI SkNx abs() const { return { fLo. abs(), fHi. abs() }; }
114 AI SkNx sqrt() const { return { fLo. sqrt(), fHi. sqrt() }; }
115 AI SkNx rsqrt() const { return { fLo. rsqrt(), fHi. rsqrt() }; }
116 AI SkNx floor() const { return { fLo. floor(), fHi. floor() }; }
117 AI SkNx invert() const { return { fLo.invert(), fHi.invert() }; }
118
119 AI SkNx operator!() const { return { !fLo, !fHi }; }
120 AI SkNx operator-() const { return { -fLo, -fHi }; }
121 AI SkNx operator~() const { return { ~fLo, ~fHi }; }
122
123 AI SkNx operator<<(int bits) const { return { fLo << bits, fHi << bits }; }
124 AI SkNx operator>>(int bits) const { return { fLo >> bits, fHi >> bits }; }
125
126 AI SkNx operator+(const SkNx& y) const { return { fLo + y.fLo, fHi + y.fHi }; }
127 AI SkNx operator-(const SkNx& y) const { return { fLo - y.fLo, fHi - y.fHi }; }
128 AI SkNx operator*(const SkNx& y) const { return { fLo * y.fLo, fHi * y.fHi }; }
129 AI SkNx operator/(const SkNx& y) const { return { fLo / y.fLo, fHi / y.fHi }; }
130
131 AI SkNx operator&(const SkNx& y) const { return { fLo & y.fLo, fHi & y.fHi }; }
132 AI SkNx operator|(const SkNx& y) const { return { fLo | y.fLo, fHi | y.fHi }; }
133 AI SkNx operator^(const SkNx& y) const { return { fLo ^ y.fLo, fHi ^ y.fHi }; }
134
135 AI SkNx operator==(const SkNx& y) const { return { fLo == y.fLo, fHi == y.fHi }; }
136 AI SkNx operator!=(const SkNx& y) const { return { fLo != y.fLo, fHi != y.fHi }; }
137 AI SkNx operator<=(const SkNx& y) const { return { fLo <= y.fLo, fHi <= y.fHi }; }
138 AI SkNx operator>=(const SkNx& y) const { return { fLo >= y.fLo, fHi >= y.fHi }; }
139 AI SkNx operator< (const SkNx& y) const { return { fLo < y.fLo, fHi < y.fHi }; }
140 AI SkNx operator> (const SkNx& y) const { return { fLo > y.fLo, fHi > y.fHi }; }
141
142 AI SkNx saturatedAdd(const SkNx& y) const {
143 return { fLo.saturatedAdd(y.fLo), fHi.saturatedAdd(y.fHi) };
144 }
145
146 AI SkNx mulHi(const SkNx& m) const {
147 return { fLo.mulHi(m.fLo), fHi.mulHi(m.fHi) };
148 }
149 AI SkNx thenElse(const SkNx& t, const SkNx& e) const {
150 return { fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi) };
151 }
152 AI static SkNx Min(const SkNx& x, const SkNx& y) {
153 return { Half::Min(x.fLo, y.fLo), Half::Min(x.fHi, y.fHi) };
154 }
155 AI static SkNx Max(const SkNx& x, const SkNx& y) {
156 return { Half::Max(x.fLo, y.fLo), Half::Max(x.fHi, y.fHi) };
157 }
158};
159
160// The N -> N/2 recursion bottoms out at N == 1, a scalar value.
161template <typename T>
162struct SkNx<1,T> {
163 T fVal;
164
165 AI SkNx() = default;
166 AI SkNx(T v) : fVal(v) {}
167
168 // Android complains against unused parameters, so we guard it
169 AI T operator[](int SkDEBUGCODE(k)) const {
170 SkASSERT(k == 0);
171 return fVal;
172 }
173
174 AI static SkNx Load(const void* ptr) {
175 SkNx v;
176 memcpy(&v, ptr, sizeof(T));
177 return v;
178 }
179 AI void store(void* ptr) const { memcpy(ptr, &fVal, sizeof(T)); }
180
181 AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) {
182 auto ptr = (const char*)vptr;
183 *a = Load(ptr + 0*sizeof(T));
184 *b = Load(ptr + 1*sizeof(T));
185 *c = Load(ptr + 2*sizeof(T));
186 *d = Load(ptr + 3*sizeof(T));
187 }
188 AI static void Load3(const void* vptr, SkNx* a, SkNx* b, SkNx* c) {
189 auto ptr = (const char*)vptr;
190 *a = Load(ptr + 0*sizeof(T));
191 *b = Load(ptr + 1*sizeof(T));
192 *c = Load(ptr + 2*sizeof(T));
193 }
194 AI static void Load2(const void* vptr, SkNx* a, SkNx* b) {
195 auto ptr = (const char*)vptr;
196 *a = Load(ptr + 0*sizeof(T));
197 *b = Load(ptr + 1*sizeof(T));
198 }
199 AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) {
200 auto ptr = (char*)vptr;
201 a.store(ptr + 0*sizeof(T));
202 b.store(ptr + 1*sizeof(T));
203 c.store(ptr + 2*sizeof(T));
204 d.store(ptr + 3*sizeof(T));
205 }
206 AI static void Store3(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c) {
207 auto ptr = (char*)vptr;
208 a.store(ptr + 0*sizeof(T));
209 b.store(ptr + 1*sizeof(T));
210 c.store(ptr + 2*sizeof(T));
211 }
212 AI static void Store2(void* vptr, const SkNx& a, const SkNx& b) {
213 auto ptr = (char*)vptr;
214 a.store(ptr + 0*sizeof(T));
215 b.store(ptr + 1*sizeof(T));
216 }
217
218 AI T min() const { return fVal; }
219 AI T max() const { return fVal; }
220 AI bool anyTrue() const { return fVal != 0; }
221 AI bool allTrue() const { return fVal != 0; }
222
223 AI SkNx abs() const { return Abs(fVal); }
224 AI SkNx sqrt() const { return Sqrt(fVal); }
225 AI SkNx rsqrt() const { return T(1) / this->sqrt(); }
226 AI SkNx floor() const { return Floor(fVal); }
227 AI SkNx invert() const { return T(1) / *this; }
228
229 AI SkNx operator!() const { return !fVal; }
230 AI SkNx operator-() const { return -fVal; }
231 AI SkNx operator~() const { return FromBits(~ToBits(fVal)); }
232
233 AI SkNx operator<<(int bits) const { return fVal << bits; }
234 AI SkNx operator>>(int bits) const { return fVal >> bits; }
235
236 AI SkNx operator+(const SkNx& y) const { return fVal + y.fVal; }
237 AI SkNx operator-(const SkNx& y) const { return fVal - y.fVal; }
238 AI SkNx operator*(const SkNx& y) const { return fVal * y.fVal; }
239 AI SkNx operator/(const SkNx& y) const { return fVal / y.fVal; }
240
241 AI SkNx operator&(const SkNx& y) const { return FromBits(ToBits(fVal) & ToBits(y.fVal)); }
242 AI SkNx operator|(const SkNx& y) const { return FromBits(ToBits(fVal) | ToBits(y.fVal)); }
243 AI SkNx operator^(const SkNx& y) const { return FromBits(ToBits(fVal) ^ ToBits(y.fVal)); }
244
245 AI SkNx operator==(const SkNx& y) const { return FromBits(fVal == y.fVal ? ~0 : 0); }
246 AI SkNx operator!=(const SkNx& y) const { return FromBits(fVal != y.fVal ? ~0 : 0); }
247 AI SkNx operator<=(const SkNx& y) const { return FromBits(fVal <= y.fVal ? ~0 : 0); }
248 AI SkNx operator>=(const SkNx& y) const { return FromBits(fVal >= y.fVal ? ~0 : 0); }
249 AI SkNx operator< (const SkNx& y) const { return FromBits(fVal < y.fVal ? ~0 : 0); }
250 AI SkNx operator> (const SkNx& y) const { return FromBits(fVal > y.fVal ? ~0 : 0); }
251
252 AI static SkNx Min(const SkNx& x, const SkNx& y) { return x.fVal < y.fVal ? x : y; }
253 AI static SkNx Max(const SkNx& x, const SkNx& y) { return x.fVal > y.fVal ? x : y; }
254
255 AI SkNx saturatedAdd(const SkNx& y) const {
256 static_assert(std::is_unsigned<T>::value, "");
257 T sum = fVal + y.fVal;
258 return sum < fVal ? std::numeric_limits<T>::max() : sum;
259 }
260
261 AI SkNx mulHi(const SkNx& m) const {
262 static_assert(std::is_unsigned<T>::value, "");
263 static_assert(sizeof(T) <= 4, "");
264 return static_cast<T>((static_cast<uint64_t>(fVal) * m.fVal) >> (sizeof(T)*8));
265 }
266
267 AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e; }
268
269private:
270 // Helper functions to choose the right float/double methods. (In <cmath> madness lies...)
271 AI static int Abs(int val) { return val < 0 ? -val : val; }
272
273 AI static float Abs(float val) { return ::fabsf(val); }
274 AI static float Sqrt(float val) { return ::sqrtf(val); }
275 AI static float Floor(float val) { return ::floorf(val); }
276
277 AI static double Abs(double val) { return ::fabs(val); }
278 AI static double Sqrt(double val) { return ::sqrt(val); }
279 AI static double Floor(double val) { return ::floor(val); }
280
281 // Helper functions for working with floats/doubles as bit patterns.
282 template <typename U>
283 AI static U ToBits(U v) { return v; }
284 AI static int32_t ToBits(float v) { int32_t bits; memcpy(&bits, &v, sizeof(v)); return bits; }
285 AI static int64_t ToBits(double v) { int64_t bits; memcpy(&bits, &v, sizeof(v)); return bits; }
286
287 template <typename Bits>
288 AI static T FromBits(Bits bits) {
289 static_assert(std::is_pod<T >::value &&
290 std::is_pod<Bits>::value &&
291 sizeof(T) <= sizeof(Bits), "");
292 T val;
293 memcpy(&val, &bits, sizeof(T));
294 return val;
295 }
296};
297
298// Allow scalars on the left or right of binary operators, and things like +=, &=, etc.
299#define V template <int N, typename T> AI static SkNx<N,T>
300 V operator+ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) + y; }
301 V operator- (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) - y; }
302 V operator* (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) * y; }
303 V operator/ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) / y; }
304 V operator& (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) & y; }
305 V operator| (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) | y; }
306 V operator^ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) ^ y; }
307 V operator==(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) == y; }
308 V operator!=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) != y; }
309 V operator<=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) <= y; }
310 V operator>=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) >= y; }
311 V operator< (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) < y; }
312 V operator> (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) > y; }
313
314 V operator+ (const SkNx<N,T>& x, T y) { return x + SkNx<N,T>(y); }
315 V operator- (const SkNx<N,T>& x, T y) { return x - SkNx<N,T>(y); }
316 V operator* (const SkNx<N,T>& x, T y) { return x * SkNx<N,T>(y); }
317 V operator/ (const SkNx<N,T>& x, T y) { return x / SkNx<N,T>(y); }
318 V operator& (const SkNx<N,T>& x, T y) { return x & SkNx<N,T>(y); }
319 V operator| (const SkNx<N,T>& x, T y) { return x | SkNx<N,T>(y); }
320 V operator^ (const SkNx<N,T>& x, T y) { return x ^ SkNx<N,T>(y); }
321 V operator==(const SkNx<N,T>& x, T y) { return x == SkNx<N,T>(y); }
322 V operator!=(const SkNx<N,T>& x, T y) { return x != SkNx<N,T>(y); }
323 V operator<=(const SkNx<N,T>& x, T y) { return x <= SkNx<N,T>(y); }
324 V operator>=(const SkNx<N,T>& x, T y) { return x >= SkNx<N,T>(y); }
325 V operator< (const SkNx<N,T>& x, T y) { return x < SkNx<N,T>(y); }
326 V operator> (const SkNx<N,T>& x, T y) { return x > SkNx<N,T>(y); }
327
328 V& operator<<=(SkNx<N,T>& x, int bits) { return (x = x << bits); }
329 V& operator>>=(SkNx<N,T>& x, int bits) { return (x = x >> bits); }
330
331 V& operator +=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x + y); }
332 V& operator -=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x - y); }
333 V& operator *=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x * y); }
334 V& operator /=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x / y); }
335 V& operator &=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x & y); }
336 V& operator |=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x | y); }
337 V& operator ^=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x ^ y); }
338
339 V& operator +=(SkNx<N,T>& x, T y) { return (x = x + SkNx<N,T>(y)); }
340 V& operator -=(SkNx<N,T>& x, T y) { return (x = x - SkNx<N,T>(y)); }
341 V& operator *=(SkNx<N,T>& x, T y) { return (x = x * SkNx<N,T>(y)); }
342 V& operator /=(SkNx<N,T>& x, T y) { return (x = x / SkNx<N,T>(y)); }
343 V& operator &=(SkNx<N,T>& x, T y) { return (x = x & SkNx<N,T>(y)); }
344 V& operator |=(SkNx<N,T>& x, T y) { return (x = x | SkNx<N,T>(y)); }
345 V& operator ^=(SkNx<N,T>& x, T y) { return (x = x ^ SkNx<N,T>(y)); }
346#undef V
347
348// SkNx<N,T> ~~> SkNx<N/2,T> + SkNx<N/2,T>
349template <int N, typename T>
350AI static void SkNx_split(const SkNx<N,T>& v, SkNx<N/2,T>* lo, SkNx<N/2,T>* hi) {
351 *lo = v.fLo;
352 *hi = v.fHi;
353}
354
355// SkNx<N/2,T> + SkNx<N/2,T> ~~> SkNx<N,T>
356template <int N, typename T>
357AI static SkNx<N*2,T> SkNx_join(const SkNx<N,T>& lo, const SkNx<N,T>& hi) {
358 return { lo, hi };
359}
360
361// A very generic shuffle. Can reorder, duplicate, contract, expand...
362// Sk4f v = { R,G,B,A };
363// SkNx_shuffle<2,1,0,3>(v) ~~> {B,G,R,A}
364// SkNx_shuffle<2,1>(v) ~~> {B,G}
365// SkNx_shuffle<2,1,2,1,2,1,2,1>(v) ~~> {B,G,B,G,B,G,B,G}
366// SkNx_shuffle<3,3,3,3>(v) ~~> {A,A,A,A}
367template <int... Ix, int N, typename T>
368AI static SkNx<sizeof...(Ix),T> SkNx_shuffle(const SkNx<N,T>& v) {
369 return { v[Ix]... };
370}
371
372// Cast from SkNx<N, Src> to SkNx<N, Dst>, as if you called static_cast<Dst>(Src).
373template <typename Dst, typename Src, int N>
374AI static SkNx<N,Dst> SkNx_cast(const SkNx<N,Src>& v) {
375 return { SkNx_cast<Dst>(v.fLo), SkNx_cast<Dst>(v.fHi) };
376}
377template <typename Dst, typename Src>
378AI static SkNx<1,Dst> SkNx_cast(const SkNx<1,Src>& v) {
379 return static_cast<Dst>(v.fVal);
380}
381
382template <int N, typename T>
383AI static SkNx<N,T> SkNx_fma(const SkNx<N,T>& f, const SkNx<N,T>& m, const SkNx<N,T>& a) {
384 return f*m+a;
385}
386
387} // namespace
388
389typedef SkNx<2, float> Sk2f;
390typedef SkNx<4, float> Sk4f;
391typedef SkNx<8, float> Sk8f;
392typedef SkNx<16, float> Sk16f;
393
394typedef SkNx<2, SkScalar> Sk2s;
395typedef SkNx<4, SkScalar> Sk4s;
396typedef SkNx<8, SkScalar> Sk8s;
397typedef SkNx<16, SkScalar> Sk16s;
398
399typedef SkNx<4, uint8_t> Sk4b;
400typedef SkNx<8, uint8_t> Sk8b;
401typedef SkNx<16, uint8_t> Sk16b;
402
403typedef SkNx<4, uint16_t> Sk4h;
404typedef SkNx<8, uint16_t> Sk8h;
405typedef SkNx<16, uint16_t> Sk16h;
406
407typedef SkNx<4, int32_t> Sk4i;
408typedef SkNx<8, int32_t> Sk8i;
409typedef SkNx<4, uint32_t> Sk4u;
410
411// Include platform specific specializations if available.
412#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
413 #include "include/private/SkNx_sse.h"
414#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
415 #include "include/private/SkNx_neon.h"
416#else
417
418AI static Sk4i Sk4f_round(const Sk4f& x) {
419 return { (int) lrintf (x[0]),
420 (int) lrintf (x[1]),
421 (int) lrintf (x[2]),
422 (int) lrintf (x[3]), };
423}
424
425#endif
426
427AI static void Sk4f_ToBytes(uint8_t p[16],
428 const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) {
429 SkNx_cast<uint8_t>(SkNx_join(SkNx_join(a,b), SkNx_join(c,d))).store(p);
430}
431
432#undef AI
433
434#endif//SkNx_DEFINED
435