blob: 65b5b97a83e536cc928b897f17653b8c5622143f [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
mtkleinc9adb052015-03-30 10:50:27 -070011
12#define SKNX_NO_SIMDx // Remove the x to disable SIMD for all SkNx types.
13
14
15#include "SkScalar.h"
16#include "SkTypes.h"
17#include <math.h>
18#define REQUIRE(x) static_assert(x, #x)
19
mtklein8fe8fff2015-04-14 11:49:14 -070020// The default implementations just fall back on a pair of size N/2.
21
22// SkNb is a _very_ minimal class representing a vector of bools returned by comparison operators.
23// We pass along the byte size of the compared types (Bytes) to help platform specializations.
24template <int N, int Bytes>
25class SkNb {
mtkleinc9adb052015-03-30 10:50:27 -070026public:
mtklein8fe8fff2015-04-14 11:49:14 -070027 SkNb() {}
28 SkNb(const SkNb<N/2, Bytes>& lo, const SkNb<N/2, Bytes>& hi) : fLo(lo), fHi(hi) {}
29
mtkleinc9adb052015-03-30 10:50:27 -070030 bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); }
31 bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); }
32
33private:
34 REQUIRE(0 == (N & (N-1)));
mtklein8fe8fff2015-04-14 11:49:14 -070035 SkNb<N/2, Bytes> fLo, fHi;
mtkleinc9adb052015-03-30 10:50:27 -070036};
37
38template <int N, typename T>
mtklein115acee2015-04-14 14:02:52 -070039class SkNi {
40public:
41 SkNi() {}
mtklein1113da72015-04-27 12:08:01 -070042 SkNi(const SkNi<N/2, T>& lo, const SkNi<N/2, T>& hi) : fLo(lo), fHi(hi) {}
mtklein115acee2015-04-14 14:02:52 -070043 explicit SkNi(T val) : fLo(val), fHi(val) {}
44 static SkNi Load(const T vals[N]) {
45 return SkNi(SkNi<N/2,T>::Load(vals), SkNi<N/2,T>::Load(vals+N/2));
46 }
47
48 SkNi(T a, T b) : fLo(a), fHi(b) { REQUIRE(N==2); }
49 SkNi(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) { REQUIRE(N==4); }
50 SkNi(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) { REQUIRE(N==8); }
51
52 void store(T vals[N]) const {
53 fLo.store(vals);
54 fHi.store(vals+N/2);
55 }
56
57 SkNi operator + (const SkNi& o) const { return SkNi(fLo + o.fLo, fHi + o.fHi); }
58 SkNi operator - (const SkNi& o) const { return SkNi(fLo - o.fLo, fHi - o.fHi); }
59 SkNi operator * (const SkNi& o) const { return SkNi(fLo * o.fLo, fHi * o.fHi); }
60
61 SkNi operator << (int bits) const { return SkNi(fLo << bits, fHi << bits); }
62 SkNi operator >> (int bits) const { return SkNi(fLo >> bits, fHi >> bits); }
63
64 // TODO: comparisons, min, max?
65
66 template <int k> T kth() const {
67 SkASSERT(0 <= k && k < N);
68 return k < N/2 ? fLo.template kth<k>() : fHi.template kth<k-N/2>();
69 }
70
71private:
72 REQUIRE(0 == (N & (N-1)));
mtklein115acee2015-04-14 14:02:52 -070073
74 SkNi<N/2, T> fLo, fHi;
75};
76
77template <int N, typename T>
mtkleinc9adb052015-03-30 10:50:27 -070078class SkNf {
mtklein8fe8fff2015-04-14 11:49:14 -070079 typedef SkNb<N, sizeof(T)> Nb;
mtklein1113da72015-04-27 12:08:01 -070080
81 static int32_t MyNi(float);
82 static int64_t MyNi(double);
83 typedef SkNi<N, decltype(MyNi(T()))> Ni;
mtkleinc9adb052015-03-30 10:50:27 -070084public:
85 SkNf() {}
mtklein8fe8fff2015-04-14 11:49:14 -070086 explicit SkNf(T val) : fLo(val), fHi(val) {}
mtkleinc9adb052015-03-30 10:50:27 -070087 static SkNf Load(const T vals[N]) {
88 return SkNf(SkNf<N/2,T>::Load(vals), SkNf<N/2,T>::Load(vals+N/2));
89 }
90
91 SkNf(T a, T b) : fLo(a), fHi(b) { REQUIRE(N==2); }
92 SkNf(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) { REQUIRE(N==4); }
93 SkNf(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) { REQUIRE(N==8); }
94
95 void store(T vals[N]) const {
96 fLo.store(vals);
97 fHi.store(vals+N/2);
98 }
99
mtklein1113da72015-04-27 12:08:01 -0700100 Ni castTrunc() const { return Ni(fLo.castTrunc(), fHi.castTrunc()); }
101
mtkleinc9adb052015-03-30 10:50:27 -0700102 SkNf operator + (const SkNf& o) const { return SkNf(fLo + o.fLo, fHi + o.fHi); }
103 SkNf operator - (const SkNf& o) const { return SkNf(fLo - o.fLo, fHi - o.fHi); }
104 SkNf operator * (const SkNf& o) const { return SkNf(fLo * o.fLo, fHi * o.fHi); }
105 SkNf operator / (const SkNf& o) const { return SkNf(fLo / o.fLo, fHi / o.fHi); }
106
mtklein8fe8fff2015-04-14 11:49:14 -0700107 Nb operator == (const SkNf& o) const { return Nb(fLo == o.fLo, fHi == o.fHi); }
108 Nb operator != (const SkNf& o) const { return Nb(fLo != o.fLo, fHi != o.fHi); }
109 Nb operator < (const SkNf& o) const { return Nb(fLo < o.fLo, fHi < o.fHi); }
110 Nb operator > (const SkNf& o) const { return Nb(fLo > o.fLo, fHi > o.fHi); }
111 Nb operator <= (const SkNf& o) const { return Nb(fLo <= o.fLo, fHi <= o.fHi); }
112 Nb operator >= (const SkNf& o) const { return Nb(fLo >= o.fLo, fHi >= o.fHi); }
mtkleinc9adb052015-03-30 10:50:27 -0700113
114 static SkNf Min(const SkNf& l, const SkNf& r) {
115 return SkNf(SkNf<N/2,T>::Min(l.fLo, r.fLo), SkNf<N/2,T>::Min(l.fHi, r.fHi));
116 }
117 static SkNf Max(const SkNf& l, const SkNf& r) {
118 return SkNf(SkNf<N/2,T>::Max(l.fLo, r.fLo), SkNf<N/2,T>::Max(l.fHi, r.fHi));
119 }
120
121 SkNf sqrt() const { return SkNf(fLo. sqrt(), fHi. sqrt()); }
122 SkNf rsqrt() const { return SkNf(fLo.rsqrt(), fHi.rsqrt()); }
123
124 SkNf invert() const { return SkNf(fLo. invert(), fHi. invert()); }
125 SkNf approxInvert() const { return SkNf(fLo.approxInvert(), fHi.approxInvert()); }
126
mtkleina156a8f2015-04-03 06:16:13 -0700127 template <int k> T kth() const {
mtkleinc9adb052015-03-30 10:50:27 -0700128 SkASSERT(0 <= k && k < N);
mtkleina156a8f2015-04-03 06:16:13 -0700129 return k < N/2 ? fLo.template kth<k>() : fHi.template kth<k-N/2>();
mtkleinc9adb052015-03-30 10:50:27 -0700130 }
131
132private:
133 REQUIRE(0 == (N & (N-1)));
134 SkNf(const SkNf<N/2, T>& lo, const SkNf<N/2, T>& hi) : fLo(lo), fHi(hi) {}
135
136 SkNf<N/2, T> fLo, fHi;
137};
138
139
mtklein8fe8fff2015-04-14 11:49:14 -0700140// Bottom out the default implementations with scalars when nothing's been specialized.
mtkleinc9adb052015-03-30 10:50:27 -0700141
mtklein8fe8fff2015-04-14 11:49:14 -0700142template <int Bytes>
143class SkNb<1, Bytes> {
144public:
145 SkNb() {}
146 explicit SkNb(bool val) : fVal(val) {}
147 bool allTrue() const { return fVal; }
148 bool anyTrue() const { return fVal; }
mtkleinc9adb052015-03-30 10:50:27 -0700149private:
mtklein8fe8fff2015-04-14 11:49:14 -0700150 bool fVal;
mtkleinc9adb052015-03-30 10:50:27 -0700151};
152
153template <typename T>
mtklein115acee2015-04-14 14:02:52 -0700154class SkNi<1,T> {
155public:
156 SkNi() {}
157 explicit SkNi(T val) : fVal(val) {}
158 static SkNi Load(const T vals[1]) { return SkNi(vals[0]); }
159
160 void store(T vals[1]) const { vals[0] = fVal; }
161
162 SkNi operator + (const SkNi& o) const { return SkNi(fVal + o.fVal); }
163 SkNi operator - (const SkNi& o) const { return SkNi(fVal - o.fVal); }
164 SkNi operator * (const SkNi& o) const { return SkNi(fVal * o.fVal); }
165
166 SkNi operator << (int bits) const { return SkNi(fVal << bits); }
167 SkNi operator >> (int bits) const { return SkNi(fVal >> bits); }
168
169 template <int k> T kth() const {
170 SkASSERT(0 == k);
171 return fVal;
172 }
173
174private:
175 T fVal;
176};
177
178template <typename T>
mtkleinc9adb052015-03-30 10:50:27 -0700179class SkNf<1,T> {
mtklein8fe8fff2015-04-14 11:49:14 -0700180 typedef SkNb<1, sizeof(T)> Nb;
mtklein1113da72015-04-27 12:08:01 -0700181
182 static int32_t MyNi(float);
183 static int64_t MyNi(double);
184 typedef SkNi<1, decltype(MyNi(T()))> Ni;
mtkleinc9adb052015-03-30 10:50:27 -0700185public:
186 SkNf() {}
mtklein8fe8fff2015-04-14 11:49:14 -0700187 explicit SkNf(T val) : fVal(val) {}
mtkleinc9adb052015-03-30 10:50:27 -0700188 static SkNf Load(const T vals[1]) { return SkNf(vals[0]); }
189
190 void store(T vals[1]) const { vals[0] = fVal; }
191
mtklein1113da72015-04-27 12:08:01 -0700192 Ni castTrunc() const { return Ni(fVal); }
193
mtkleinc9adb052015-03-30 10:50:27 -0700194 SkNf operator + (const SkNf& o) const { return SkNf(fVal + o.fVal); }
195 SkNf operator - (const SkNf& o) const { return SkNf(fVal - o.fVal); }
196 SkNf operator * (const SkNf& o) const { return SkNf(fVal * o.fVal); }
197 SkNf operator / (const SkNf& o) const { return SkNf(fVal / o.fVal); }
198
mtklein8fe8fff2015-04-14 11:49:14 -0700199 Nb operator == (const SkNf& o) const { return Nb(fVal == o.fVal); }
200 Nb operator != (const SkNf& o) const { return Nb(fVal != o.fVal); }
201 Nb operator < (const SkNf& o) const { return Nb(fVal < o.fVal); }
202 Nb operator > (const SkNf& o) const { return Nb(fVal > o.fVal); }
203 Nb operator <= (const SkNf& o) const { return Nb(fVal <= o.fVal); }
204 Nb operator >= (const SkNf& o) const { return Nb(fVal >= o.fVal); }
mtkleinc9adb052015-03-30 10:50:27 -0700205
206 static SkNf Min(const SkNf& l, const SkNf& r) { return SkNf(SkTMin(l.fVal, r.fVal)); }
207 static SkNf Max(const SkNf& l, const SkNf& r) { return SkNf(SkTMax(l.fVal, r.fVal)); }
208
mtklein8fe8fff2015-04-14 11:49:14 -0700209 SkNf sqrt() const { return SkNf(Sqrt(fVal)); }
mtkleinc9adb052015-03-30 10:50:27 -0700210 SkNf rsqrt() const { return SkNf((T)1 / Sqrt(fVal)); }
211
212 SkNf invert() const { return SkNf((T)1 / fVal); }
213 SkNf approxInvert() const { return this->invert(); }
214
mtkleina156a8f2015-04-03 06:16:13 -0700215 template <int k> T kth() const {
mtkleinc9adb052015-03-30 10:50:27 -0700216 SkASSERT(k == 0);
217 return fVal;
218 }
219
220private:
221 // We do double sqrts natively, or via floats for any other type.
222 template <typename U>
223 static U Sqrt(U val) { return (U) ::sqrtf((float)val); }
224 static double Sqrt(double val) { return ::sqrt ( val); }
225
226 T fVal;
227};
228
229
mtklein8fe8fff2015-04-14 11:49:14 -0700230// Generic syntax sugar that should work equally well for all implementations.
231template <typename T> T operator - (const T& l) { return T(0) - l; }
mtkleinc9adb052015-03-30 10:50:27 -0700232
mtklein8fe8fff2015-04-14 11:49:14 -0700233template <typename L, typename R> L& operator += (L& l, const R& r) { return (l = l + r); }
234template <typename L, typename R> L& operator -= (L& l, const R& r) { return (l = l - r); }
235template <typename L, typename R> L& operator *= (L& l, const R& r) { return (l = l * r); }
236template <typename L, typename R> L& operator /= (L& l, const R& r) { return (l = l / r); }
mtkleinc9adb052015-03-30 10:50:27 -0700237
mtklein115acee2015-04-14 14:02:52 -0700238template <typename L> L& operator <<= (L& l, int bits) { return (l = l << bits); }
239template <typename L> L& operator >>= (L& l, int bits) { return (l = l >> bits); }
mtkleinc9adb052015-03-30 10:50:27 -0700240
241// Include platform specific specializations if available.
242#ifndef SKNX_NO_SIMD
243 #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
244 #include "../opts/SkNx_sse.h"
245 #elif defined(SK_ARM_HAS_NEON)
246 #include "../opts/SkNx_neon.h"
247 #endif
248#endif
249
250#undef REQUIRE
251
252typedef SkNf<2, float> Sk2f;
253typedef SkNf<2, double> Sk2d;
254typedef SkNf<2, SkScalar> Sk2s;
255
256typedef SkNf<4, float> Sk4f;
257typedef SkNf<4, double> Sk4d;
258typedef SkNf<4, SkScalar> Sk4s;
259
mtklein115acee2015-04-14 14:02:52 -0700260typedef SkNi<4, uint16_t> Sk4h;
261typedef SkNi<8, uint16_t> Sk8h;
262
mtklein1113da72015-04-27 12:08:01 -0700263typedef SkNi<4, int> Sk4i;
264
mtklein3e490b72015-03-20 06:33:02 -0700265#endif//SkNx_DEFINED