blob: 6957cb0d3827f51a6bd21f9711c3f2d53d1d2cd4 [file] [log] [blame]
mtklein3e490b72015-03-20 06:33:02 -07001/*
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
Mike Kleine9f78b42016-11-22 08:57:45 -050011#include "SkSafe_math.h"
mtkleinc9adb052015-03-30 10:50:27 -070012#include "SkScalar.h"
13#include "SkTypes.h"
mtkleinf8f90e42016-03-21 10:04:46 -070014#include <limits>
mtkleinf8f90e42016-03-21 10:04:46 -070015#include <type_traits>
mtklein082e3292015-08-12 11:56:43 -070016
Mike Klein7c78f3a2016-10-19 09:21:11 -040017// Every single SkNx method wants to be fully inlined. (We know better than MSVC).
18#define AI SK_ALWAYS_INLINE
Mike Klein1e764642016-10-14 17:09:03 -040019
Mike Klein7c78f3a2016-10-19 09:21:11 -040020namespace {
mtkleinf8f90e42016-03-21 10:04:46 -070021
22// The default SkNx<N,T> just proxies down to a pair of SkNx<N/2, T>.
mtkleinc9adb052015-03-30 10:50:27 -070023template <int N, typename T>
mtkleinf8f90e42016-03-21 10:04:46 -070024struct SkNx {
mtkleine4c0bee2016-02-09 10:35:27 -080025 typedef SkNx<N/2, T> Half;
mtkleinf8f90e42016-03-21 10:04:46 -070026
27 Half fLo, fHi;
28
Mike Klein7c78f3a2016-10-19 09:21:11 -040029 AI SkNx() = default;
30 AI SkNx(const Half& lo, const Half& hi) : fLo(lo), fHi(hi) {}
mtkleine4c0bee2016-02-09 10:35:27 -080031
Mike Klein7c78f3a2016-10-19 09:21:11 -040032 AI SkNx(T v) : fLo(v), fHi(v) {}
mtkleinf8f90e42016-03-21 10:04:46 -070033
Mike Klein7c78f3a2016-10-19 09:21:11 -040034 AI SkNx(T a, T b) : fLo(a) , fHi(b) { static_assert(N==2, ""); }
35 AI SkNx(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) { static_assert(N==4, ""); }
36 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) {
mtkleinf8f90e42016-03-21 10:04:46 -070037 static_assert(N==8, "");
38 }
Mike Klein7c78f3a2016-10-19 09:21:11 -040039 AI SkNx(T a, T b, T c, T d, T e, T f, T g, T h,
40 T i, T j, T k, T l, T m, T n, T o, T p)
41 : fLo(a,b,c,d, e,f,g,h), fHi(i,j,k,l, m,n,o,p) {
mtkleinf8f90e42016-03-21 10:04:46 -070042 static_assert(N==16, "");
mtklein6f37b4a2015-12-14 11:25:18 -080043 }
44
Mike Klein7c78f3a2016-10-19 09:21:11 -040045 AI T operator[](int k) const {
mtklein115acee2015-04-14 14:02:52 -070046 SkASSERT(0 <= k && k < N);
mtkleine4c0bee2016-02-09 10:35:27 -080047 return k < N/2 ? fLo[k] : fHi[k-N/2];
mtklein115acee2015-04-14 14:02:52 -070048 }
49
Mike Klein7c78f3a2016-10-19 09:21:11 -040050 AI static SkNx Load(const void* vptr) {
mtkleinf8f90e42016-03-21 10:04:46 -070051 auto ptr = (const char*)vptr;
52 return { Half::Load(ptr), Half::Load(ptr + N/2*sizeof(T)) };
53 }
Mike Klein7c78f3a2016-10-19 09:21:11 -040054 AI void store(void* vptr) const {
mtkleinf8f90e42016-03-21 10:04:46 -070055 auto ptr = (char*)vptr;
56 fLo.store(ptr);
57 fHi.store(ptr + N/2*sizeof(T));
mtkleinb5e86112015-06-24 15:18:39 -070058 }
59
Mike Klein7c78f3a2016-10-19 09:21:11 -040060 AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) {
Mike Klein33cbfd72016-10-06 11:09:27 -040061 auto ptr = (const char*)vptr;
62 Half al, bl, cl, dl,
63 ah, bh, ch, dh;
64 Half::Load4(ptr , &al, &bl, &cl, &dl);
65 Half::Load4(ptr + 4*N/2*sizeof(T), &ah, &bh, &ch, &dh);
66 *a = SkNx{al, ah};
67 *b = SkNx{bl, bh};
68 *c = SkNx{cl, ch};
69 *d = SkNx{dl, dh};
70 }
Matt Sarett5bee0b62017-01-19 12:04:32 -050071 AI static void Load3(const void* vptr, SkNx* a, SkNx* b, SkNx* c) {
72 auto ptr = (const char*)vptr;
73 Half al, bl, cl,
74 ah, bh, ch;
75 Half::Load3(ptr , &al, &bl, &cl);
76 Half::Load3(ptr + 3*N/2*sizeof(T), &ah, &bh, &ch);
77 *a = SkNx{al, ah};
78 *b = SkNx{bl, bh};
79 *c = SkNx{cl, ch};
80 }
Mike Klein7c78f3a2016-10-19 09:21:11 -040081 AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) {
Mike Klein33cbfd72016-10-06 11:09:27 -040082 auto ptr = (char*)vptr;
83 Half::Store4(ptr, a.fLo, b.fLo, c.fLo, d.fLo);
84 Half::Store4(ptr + 4*N/2*sizeof(T), a.fHi, b.fHi, c.fHi, d.fHi);
85 }
86
Mike Klein7c78f3a2016-10-19 09:21:11 -040087 AI bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); }
88 AI bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); }
mtklein115acee2015-04-14 14:02:52 -070089
Mike Klein7c78f3a2016-10-19 09:21:11 -040090 AI SkNx abs() const { return { fLo. abs(), fHi. abs() }; }
91 AI SkNx sqrt() const { return { fLo. sqrt(), fHi. sqrt() }; }
92 AI SkNx rsqrt() const { return { fLo. rsqrt(), fHi. rsqrt() }; }
93 AI SkNx floor() const { return { fLo. floor(), fHi. floor() }; }
94 AI SkNx invert() const { return { fLo.invert(), fHi.invert() }; }
mtkleinf8f90e42016-03-21 10:04:46 -070095
Mike Klein7c78f3a2016-10-19 09:21:11 -040096 AI SkNx operator!() const { return { !fLo, !fHi }; }
97 AI SkNx operator-() const { return { -fLo, -fHi }; }
98 AI SkNx operator~() const { return { ~fLo, ~fHi }; }
mtkleinf8f90e42016-03-21 10:04:46 -070099
Mike Klein7c78f3a2016-10-19 09:21:11 -0400100 AI SkNx operator<<(int bits) const { return { fLo << bits, fHi << bits }; }
101 AI SkNx operator>>(int bits) const { return { fLo >> bits, fHi >> bits }; }
mtkleinf8f90e42016-03-21 10:04:46 -0700102
Mike Klein7c78f3a2016-10-19 09:21:11 -0400103 AI SkNx operator+(const SkNx& y) const { return { fLo + y.fLo, fHi + y.fHi }; }
104 AI SkNx operator-(const SkNx& y) const { return { fLo - y.fLo, fHi - y.fHi }; }
105 AI SkNx operator*(const SkNx& y) const { return { fLo * y.fLo, fHi * y.fHi }; }
106 AI SkNx operator/(const SkNx& y) const { return { fLo / y.fLo, fHi / y.fHi }; }
mtkleinf8f90e42016-03-21 10:04:46 -0700107
Mike Klein7c78f3a2016-10-19 09:21:11 -0400108 AI SkNx operator&(const SkNx& y) const { return { fLo & y.fLo, fHi & y.fHi }; }
109 AI SkNx operator|(const SkNx& y) const { return { fLo | y.fLo, fHi | y.fHi }; }
110 AI SkNx operator^(const SkNx& y) const { return { fLo ^ y.fLo, fHi ^ y.fHi }; }
mtkleinf8f90e42016-03-21 10:04:46 -0700111
Mike Klein7c78f3a2016-10-19 09:21:11 -0400112 AI SkNx operator==(const SkNx& y) const { return { fLo == y.fLo, fHi == y.fHi }; }
113 AI SkNx operator!=(const SkNx& y) const { return { fLo != y.fLo, fHi != y.fHi }; }
114 AI SkNx operator<=(const SkNx& y) const { return { fLo <= y.fLo, fHi <= y.fHi }; }
115 AI SkNx operator>=(const SkNx& y) const { return { fLo >= y.fLo, fHi >= y.fHi }; }
116 AI SkNx operator< (const SkNx& y) const { return { fLo < y.fLo, fHi < y.fHi }; }
117 AI SkNx operator> (const SkNx& y) const { return { fLo > y.fLo, fHi > y.fHi }; }
mtkleinf8f90e42016-03-21 10:04:46 -0700118
Mike Klein7c78f3a2016-10-19 09:21:11 -0400119 AI SkNx saturatedAdd(const SkNx& y) const {
mtkleinf8f90e42016-03-21 10:04:46 -0700120 return { fLo.saturatedAdd(y.fLo), fHi.saturatedAdd(y.fHi) };
121 }
Herb Derby5eb15282017-10-10 17:14:18 -0400122
123 AI SkNx mulHi(const SkNx& m) const {
124 return { fLo.mulHi(m.fLo), fHi.mulHi(m.fHi) };
125 }
Mike Klein7c78f3a2016-10-19 09:21:11 -0400126 AI SkNx thenElse(const SkNx& t, const SkNx& e) const {
mtkleinf8f90e42016-03-21 10:04:46 -0700127 return { fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi) };
128 }
Mike Klein7c78f3a2016-10-19 09:21:11 -0400129 AI static SkNx Min(const SkNx& x, const SkNx& y) {
mtkleinf8f90e42016-03-21 10:04:46 -0700130 return { Half::Min(x.fLo, y.fLo), Half::Min(x.fHi, y.fHi) };
131 }
Mike Klein7c78f3a2016-10-19 09:21:11 -0400132 AI static SkNx Max(const SkNx& x, const SkNx& y) {
mtkleinf8f90e42016-03-21 10:04:46 -0700133 return { Half::Max(x.fLo, y.fLo), Half::Max(x.fHi, y.fHi) };
134 }
mtklein115acee2015-04-14 14:02:52 -0700135};
136
mtkleinf8f90e42016-03-21 10:04:46 -0700137// The N -> N/2 recursion bottoms out at N == 1, a scalar value.
mtkleinc9adb052015-03-30 10:50:27 -0700138template <typename T>
mtkleinf8f90e42016-03-21 10:04:46 -0700139struct SkNx<1,T> {
140 T fVal;
mtkleine4c0bee2016-02-09 10:35:27 -0800141
Mike Klein7c78f3a2016-10-19 09:21:11 -0400142 AI SkNx() = default;
143 AI SkNx(T v) : fVal(v) {}
mtkleinc9adb052015-03-30 10:50:27 -0700144
reed12644722016-07-12 09:12:30 -0700145 // Android complains against unused parameters, so we guard it
Mike Klein7c78f3a2016-10-19 09:21:11 -0400146 AI T operator[](int SkDEBUGCODE(k)) const {
mtkleinf8f90e42016-03-21 10:04:46 -0700147 SkASSERT(k == 0);
mtkleinc9adb052015-03-30 10:50:27 -0700148 return fVal;
149 }
150
Mike Klein7c78f3a2016-10-19 09:21:11 -0400151 AI static SkNx Load(const void* ptr) {
mtkleinf8f90e42016-03-21 10:04:46 -0700152 SkNx v;
153 memcpy(&v, ptr, sizeof(T));
154 return v;
155 }
Mike Klein7c78f3a2016-10-19 09:21:11 -0400156 AI void store(void* ptr) const { memcpy(ptr, &fVal, sizeof(T)); }
mtkleinf8f90e42016-03-21 10:04:46 -0700157
Mike Klein7c78f3a2016-10-19 09:21:11 -0400158 AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) {
Mike Klein33cbfd72016-10-06 11:09:27 -0400159 auto ptr = (const char*)vptr;
160 *a = Load(ptr + 0*sizeof(T));
161 *b = Load(ptr + 1*sizeof(T));
162 *c = Load(ptr + 2*sizeof(T));
163 *d = Load(ptr + 3*sizeof(T));
164 }
Matt Sarett5bee0b62017-01-19 12:04:32 -0500165 AI static void Load3(const void* vptr, SkNx* a, SkNx* b, SkNx* c) {
166 auto ptr = (const char*)vptr;
167 *a = Load(ptr + 0*sizeof(T));
168 *b = Load(ptr + 1*sizeof(T));
169 *c = Load(ptr + 2*sizeof(T));
170 }
Mike Klein7c78f3a2016-10-19 09:21:11 -0400171 AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) {
Mike Klein33cbfd72016-10-06 11:09:27 -0400172 auto ptr = (char*)vptr;
173 a.store(ptr + 0*sizeof(T));
174 b.store(ptr + 1*sizeof(T));
175 c.store(ptr + 2*sizeof(T));
176 d.store(ptr + 3*sizeof(T));
177 }
178
Mike Klein7c78f3a2016-10-19 09:21:11 -0400179 AI bool anyTrue() const { return fVal != 0; }
180 AI bool allTrue() const { return fVal != 0; }
mtkleinf8f90e42016-03-21 10:04:46 -0700181
Mike Klein7c78f3a2016-10-19 09:21:11 -0400182 AI SkNx abs() const { return Abs(fVal); }
183 AI SkNx sqrt() const { return Sqrt(fVal); }
184 AI SkNx rsqrt() const { return T(1) / this->sqrt(); }
185 AI SkNx floor() const { return Floor(fVal); }
186 AI SkNx invert() const { return T(1) / *this; }
mtkleinf8f90e42016-03-21 10:04:46 -0700187
Mike Klein7c78f3a2016-10-19 09:21:11 -0400188 AI SkNx operator!() const { return !fVal; }
189 AI SkNx operator-() const { return -fVal; }
190 AI SkNx operator~() const { return FromBits(~ToBits(fVal)); }
mtkleinf8f90e42016-03-21 10:04:46 -0700191
Mike Klein7c78f3a2016-10-19 09:21:11 -0400192 AI SkNx operator<<(int bits) const { return fVal << bits; }
193 AI SkNx operator>>(int bits) const { return fVal >> bits; }
mtkleinf8f90e42016-03-21 10:04:46 -0700194
Mike Klein7c78f3a2016-10-19 09:21:11 -0400195 AI SkNx operator+(const SkNx& y) const { return fVal + y.fVal; }
196 AI SkNx operator-(const SkNx& y) const { return fVal - y.fVal; }
197 AI SkNx operator*(const SkNx& y) const { return fVal * y.fVal; }
198 AI SkNx operator/(const SkNx& y) const { return fVal / y.fVal; }
mtkleinf8f90e42016-03-21 10:04:46 -0700199
Mike Klein7c78f3a2016-10-19 09:21:11 -0400200 AI SkNx operator&(const SkNx& y) const { return FromBits(ToBits(fVal) & ToBits(y.fVal)); }
201 AI SkNx operator|(const SkNx& y) const { return FromBits(ToBits(fVal) | ToBits(y.fVal)); }
202 AI SkNx operator^(const SkNx& y) const { return FromBits(ToBits(fVal) ^ ToBits(y.fVal)); }
mtkleinf8f90e42016-03-21 10:04:46 -0700203
Mike Klein7c78f3a2016-10-19 09:21:11 -0400204 AI SkNx operator==(const SkNx& y) const { return FromBits(fVal == y.fVal ? ~0 : 0); }
205 AI SkNx operator!=(const SkNx& y) const { return FromBits(fVal != y.fVal ? ~0 : 0); }
206 AI SkNx operator<=(const SkNx& y) const { return FromBits(fVal <= y.fVal ? ~0 : 0); }
207 AI SkNx operator>=(const SkNx& y) const { return FromBits(fVal >= y.fVal ? ~0 : 0); }
208 AI SkNx operator< (const SkNx& y) const { return FromBits(fVal < y.fVal ? ~0 : 0); }
209 AI SkNx operator> (const SkNx& y) const { return FromBits(fVal > y.fVal ? ~0 : 0); }
mtkleinf8f90e42016-03-21 10:04:46 -0700210
Mike Klein7c78f3a2016-10-19 09:21:11 -0400211 AI static SkNx Min(const SkNx& x, const SkNx& y) { return x.fVal < y.fVal ? x : y; }
212 AI static SkNx Max(const SkNx& x, const SkNx& y) { return x.fVal > y.fVal ? x : y; }
mtkleinf8f90e42016-03-21 10:04:46 -0700213
Mike Klein7c78f3a2016-10-19 09:21:11 -0400214 AI SkNx saturatedAdd(const SkNx& y) const {
mtkleinf8f90e42016-03-21 10:04:46 -0700215 static_assert(std::is_unsigned<T>::value, "");
216 T sum = fVal + y.fVal;
217 return sum < fVal ? std::numeric_limits<T>::max() : sum;
218 }
219
Herb Derby5eb15282017-10-10 17:14:18 -0400220 AI SkNx mulHi(const SkNx& m) const {
221 static_assert(std::is_unsigned<T>::value, "");
222 static_assert(sizeof(T) <= 4, "");
223 return static_cast<T>((static_cast<uint64_t>(fVal) * m.fVal) >> (sizeof(T)*8));
224 }
225
Mike Klein7c78f3a2016-10-19 09:21:11 -0400226 AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e; }
mtkleinb5e86112015-06-24 15:18:39 -0700227
mtkleinf8f90e42016-03-21 10:04:46 -0700228private:
229 // Helper functions to choose the right float/double methods. (In <cmath> madness lies...)
Yuqian Li7da6ba22017-07-12 13:36:05 -0400230 AI static int Abs(int val) { return val < 0 ? -val : val; }
231
Mike Klein7c78f3a2016-10-19 09:21:11 -0400232 AI static float Abs(float val) { return ::fabsf(val); }
233 AI static float Sqrt(float val) { return ::sqrtf(val); }
234 AI static float Floor(float val) { return ::floorf(val); }
mtkleinb5e86112015-06-24 15:18:39 -0700235
Mike Klein7c78f3a2016-10-19 09:21:11 -0400236 AI static double Abs(double val) { return ::fabs(val); }
237 AI static double Sqrt(double val) { return ::sqrt(val); }
238 AI static double Floor(double val) { return ::floor(val); }
mtkleinf8f90e42016-03-21 10:04:46 -0700239
240 // Helper functions for working with floats/doubles as bit patterns.
Mike Klein7c78f3a2016-10-19 09:21:11 -0400241 template <typename U>
242 AI static U ToBits(U v) { return v; }
243 AI static int32_t ToBits(float v) { int32_t bits; memcpy(&bits, &v, sizeof(v)); return bits; }
244 AI static int64_t ToBits(double v) { int64_t bits; memcpy(&bits, &v, sizeof(v)); return bits; }
mtkleinf8f90e42016-03-21 10:04:46 -0700245
Mike Klein7c78f3a2016-10-19 09:21:11 -0400246 template <typename Bits>
247 AI static T FromBits(Bits bits) {
mtkleinf8f90e42016-03-21 10:04:46 -0700248 static_assert(std::is_pod<T >::value &&
249 std::is_pod<Bits>::value &&
250 sizeof(T) <= sizeof(Bits), "");
251 T val;
252 memcpy(&val, &bits, sizeof(T));
253 return val;
254 }
mtkleinc9adb052015-03-30 10:50:27 -0700255};
256
mtkleinf8f90e42016-03-21 10:04:46 -0700257// Allow scalars on the left or right of binary operators, and things like +=, &=, etc.
Mike Klein7c78f3a2016-10-19 09:21:11 -0400258#define V template <int N, typename T> AI static SkNx<N,T>
mtkleinf8f90e42016-03-21 10:04:46 -0700259 V operator+ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) + y; }
260 V operator- (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) - y; }
261 V operator* (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) * y; }
262 V operator/ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) / y; }
263 V operator& (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) & y; }
264 V operator| (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) | y; }
265 V operator^ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) ^ y; }
266 V operator==(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) == y; }
267 V operator!=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) != y; }
268 V operator<=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) <= y; }
269 V operator>=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) >= y; }
270 V operator< (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) < y; }
271 V operator> (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) > y; }
272
273 V operator+ (const SkNx<N,T>& x, T y) { return x + SkNx<N,T>(y); }
274 V operator- (const SkNx<N,T>& x, T y) { return x - SkNx<N,T>(y); }
275 V operator* (const SkNx<N,T>& x, T y) { return x * SkNx<N,T>(y); }
276 V operator/ (const SkNx<N,T>& x, T y) { return x / SkNx<N,T>(y); }
277 V operator& (const SkNx<N,T>& x, T y) { return x & SkNx<N,T>(y); }
278 V operator| (const SkNx<N,T>& x, T y) { return x | SkNx<N,T>(y); }
279 V operator^ (const SkNx<N,T>& x, T y) { return x ^ SkNx<N,T>(y); }
280 V operator==(const SkNx<N,T>& x, T y) { return x == SkNx<N,T>(y); }
281 V operator!=(const SkNx<N,T>& x, T y) { return x != SkNx<N,T>(y); }
282 V operator<=(const SkNx<N,T>& x, T y) { return x <= SkNx<N,T>(y); }
283 V operator>=(const SkNx<N,T>& x, T y) { return x >= SkNx<N,T>(y); }
284 V operator< (const SkNx<N,T>& x, T y) { return x < SkNx<N,T>(y); }
285 V operator> (const SkNx<N,T>& x, T y) { return x > SkNx<N,T>(y); }
286
287 V& operator<<=(SkNx<N,T>& x, int bits) { return (x = x << bits); }
288 V& operator>>=(SkNx<N,T>& x, int bits) { return (x = x >> bits); }
289
290 V& operator +=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x + y); }
291 V& operator -=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x - y); }
292 V& operator *=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x * y); }
293 V& operator /=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x / y); }
294 V& operator &=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x & y); }
295 V& operator |=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x | y); }
296 V& operator ^=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x ^ y); }
297
298 V& operator +=(SkNx<N,T>& x, T y) { return (x = x + SkNx<N,T>(y)); }
299 V& operator -=(SkNx<N,T>& x, T y) { return (x = x - SkNx<N,T>(y)); }
300 V& operator *=(SkNx<N,T>& x, T y) { return (x = x * SkNx<N,T>(y)); }
301 V& operator /=(SkNx<N,T>& x, T y) { return (x = x / SkNx<N,T>(y)); }
302 V& operator &=(SkNx<N,T>& x, T y) { return (x = x & SkNx<N,T>(y)); }
303 V& operator |=(SkNx<N,T>& x, T y) { return (x = x | SkNx<N,T>(y)); }
304 V& operator ^=(SkNx<N,T>& x, T y) { return (x = x ^ SkNx<N,T>(y)); }
305#undef V
306
307// SkNx<N,T> ~~> SkNx<N/2,T> + SkNx<N/2,T>
308template <int N, typename T>
Mike Klein7c78f3a2016-10-19 09:21:11 -0400309AI static void SkNx_split(const SkNx<N,T>& v, SkNx<N/2,T>* lo, SkNx<N/2,T>* hi) {
mtkleinf8f90e42016-03-21 10:04:46 -0700310 *lo = v.fLo;
311 *hi = v.fHi;
312}
313
314// SkNx<N/2,T> + SkNx<N/2,T> ~~> SkNx<N,T>
315template <int N, typename T>
Mike Klein7c78f3a2016-10-19 09:21:11 -0400316AI static SkNx<N*2,T> SkNx_join(const SkNx<N,T>& lo, const SkNx<N,T>& hi) {
mtkleinf8f90e42016-03-21 10:04:46 -0700317 return { lo, hi };
318}
319
320// A very generic shuffle. Can reorder, duplicate, contract, expand...
321// Sk4f v = { R,G,B,A };
322// SkNx_shuffle<2,1,0,3>(v) ~~> {B,G,R,A}
323// SkNx_shuffle<2,1>(v) ~~> {B,G}
324// SkNx_shuffle<2,1,2,1,2,1,2,1>(v) ~~> {B,G,B,G,B,G,B,G}
325// SkNx_shuffle<3,3,3,3>(v) ~~> {A,A,A,A}
mtkleine4c0bee2016-02-09 10:35:27 -0800326template <int... Ix, int N, typename T>
Mike Klein7c78f3a2016-10-19 09:21:11 -0400327AI static SkNx<sizeof...(Ix),T> SkNx_shuffle(const SkNx<N,T>& v) {
mtkleinf8f90e42016-03-21 10:04:46 -0700328 return { v[Ix]... };
mtklein6c221b42015-11-20 13:53:19 -0800329}
mtkleina1c0ee42015-09-10 14:16:07 -0700330
mtkleinf8f90e42016-03-21 10:04:46 -0700331// Cast from SkNx<N, Src> to SkNx<N, Dst>, as if you called static_cast<Dst>(Src).
332template <typename Dst, typename Src, int N>
Mike Klein7c78f3a2016-10-19 09:21:11 -0400333AI static SkNx<N,Dst> SkNx_cast(const SkNx<N,Src>& v) {
mtkleinf8f90e42016-03-21 10:04:46 -0700334 return { SkNx_cast<Dst>(v.fLo), SkNx_cast<Dst>(v.fHi) };
mtkleine4c0bee2016-02-09 10:35:27 -0800335}
mtkleinf8f90e42016-03-21 10:04:46 -0700336template <typename Dst, typename Src>
Mike Klein7c78f3a2016-10-19 09:21:11 -0400337AI static SkNx<1,Dst> SkNx_cast(const SkNx<1,Src>& v) {
mtkleinf8f90e42016-03-21 10:04:46 -0700338 return static_cast<Dst>(v.fVal);
mtkleine4c0bee2016-02-09 10:35:27 -0800339}
mtkleinfce612a2015-12-15 07:38:54 -0800340
Mike Klein04adfda2016-10-12 09:52:55 -0400341template <int N, typename T>
Mike Klein7c78f3a2016-10-19 09:21:11 -0400342AI static SkNx<N,T> SkNx_fma(const SkNx<N,T>& f, const SkNx<N,T>& m, const SkNx<N,T>& a) {
Mike Klein04adfda2016-10-12 09:52:55 -0400343 return f*m+a;
344}
345
Mike Klein1e764642016-10-14 17:09:03 -0400346} // namespace
347
mtkleine4c0bee2016-02-09 10:35:27 -0800348typedef SkNx<2, float> Sk2f;
349typedef SkNx<4, float> Sk4f;
mtkleinf8f90e42016-03-21 10:04:46 -0700350typedef SkNx<8, float> Sk8f;
351typedef SkNx<16, float> Sk16f;
352
mtkleine4c0bee2016-02-09 10:35:27 -0800353typedef SkNx<2, SkScalar> Sk2s;
354typedef SkNx<4, SkScalar> Sk4s;
mtkleinf8f90e42016-03-21 10:04:46 -0700355typedef SkNx<8, SkScalar> Sk8s;
356typedef SkNx<16, SkScalar> Sk16s;
mtkleinc9adb052015-03-30 10:50:27 -0700357
mtkleine4c0bee2016-02-09 10:35:27 -0800358typedef SkNx<4, uint8_t> Sk4b;
mtkleinf8f90e42016-03-21 10:04:46 -0700359typedef SkNx<8, uint8_t> Sk8b;
mtkleine4c0bee2016-02-09 10:35:27 -0800360typedef SkNx<16, uint8_t> Sk16b;
mtklein6f37b4a2015-12-14 11:25:18 -0800361
mtkleinf8f90e42016-03-21 10:04:46 -0700362typedef SkNx<4, uint16_t> Sk4h;
363typedef SkNx<8, uint16_t> Sk8h;
364typedef SkNx<16, uint16_t> Sk16h;
365
mtkleind05a8752016-07-29 10:10:15 -0700366typedef SkNx<4, int32_t> Sk4i;
Mike Klein04adfda2016-10-12 09:52:55 -0400367typedef SkNx<8, int32_t> Sk8i;
mtkleind05a8752016-07-29 10:10:15 -0700368typedef SkNx<4, uint32_t> Sk4u;
mtkleinff9febf2016-02-16 14:33:08 -0800369
mtklein6f37b4a2015-12-14 11:25:18 -0800370// Include platform specific specializations if available.
mtklein81bb79b2016-02-08 15:50:22 -0800371#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
msarettafb85392016-07-11 14:57:26 -0700372 #include "../opts/SkNx_sse.h"
mtklein6f37b4a2015-12-14 11:25:18 -0800373#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
msarettafb85392016-07-11 14:57:26 -0700374 #include "../opts/SkNx_neon.h"
msarett7d3ff712016-07-12 14:55:45 -0700375#else
376
Mike Klein7c78f3a2016-10-19 09:21:11 -0400377AI static Sk4i Sk4f_round(const Sk4f& x) {
msarett7d3ff712016-07-12 14:55:45 -0700378 return { (int) lrintf (x[0]),
379 (int) lrintf (x[1]),
380 (int) lrintf (x[2]),
381 (int) lrintf (x[3]), };
382}
383
mtklein6f37b4a2015-12-14 11:25:18 -0800384#endif
385
Mike Klein7c78f3a2016-10-19 09:21:11 -0400386AI static void Sk4f_ToBytes(uint8_t p[16],
387 const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) {
mtkleinf8f90e42016-03-21 10:04:46 -0700388 SkNx_cast<uint8_t>(SkNx_join(SkNx_join(a,b), SkNx_join(c,d))).store(p);
389}
390
Mike Klein7c78f3a2016-10-19 09:21:11 -0400391#undef AI
mtkleinf8f90e42016-03-21 10:04:46 -0700392
mtklein3e490b72015-03-20 06:33:02 -0700393#endif//SkNx_DEFINED