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
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
20// 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 {
26public:
27    SkNb() {}
28    SkNb(const SkNb<N/2, Bytes>& lo, const SkNb<N/2, Bytes>& hi) : fLo(lo), fHi(hi) {}
29
30    bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); }
31    bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); }
32
33protected:
34    REQUIRE(0 == (N & (N-1)));
35    SkNb<N/2, Bytes> fLo, fHi;
36};
37
38template <int N, typename T>
39class SkNi {
40public:
41    SkNi() {}
42    SkNi(const SkNi<N/2, T>& lo, const SkNi<N/2, T>& hi) : fLo(lo), fHi(hi) {}
43    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    SkNi(T a, T b, T c, T d,  T e, T f, T g, T h,
52         T i, T j, T k, T l,  T m, T n, T o, T p)
53        : fLo(a,b,c,d, e,f,g,h), fHi(i,j,k,l, m,n,o,p) { REQUIRE(N==16); }
54
55    void store(T vals[N]) const {
56        fLo.store(vals);
57        fHi.store(vals+N/2);
58    }
59
60    SkNi saturatedAdd(const SkNi& o) const {
61        return SkNi(fLo.saturatedAdd(o.fLo), fHi.saturatedAdd(o.fHi));
62    }
63
64    SkNi operator + (const SkNi& o) const { return SkNi(fLo + o.fLo, fHi + o.fHi); }
65    SkNi operator - (const SkNi& o) const { return SkNi(fLo - o.fLo, fHi - o.fHi); }
66    SkNi operator * (const SkNi& o) const { return SkNi(fLo * o.fLo, fHi * o.fHi); }
67
68    SkNi operator << (int bits) const { return SkNi(fLo << bits, fHi << bits); }
69    SkNi operator >> (int bits) const { return SkNi(fLo >> bits, fHi >> bits); }
70
71    static SkNi Min(const SkNi& a, const SkNi& b) {
72        return SkNi(SkNi<N/2, T>::Min(a.fLo, b.fLo), SkNi<N/2, T>::Min(a.fHi, b.fHi));
73    }
74
75    // TODO: comparisons, max?
76
77    template <int k> T kth() const {
78        SkASSERT(0 <= k && k < N);
79        return k < N/2 ? fLo.template kth<k>() : fHi.template kth<k-N/2>();
80    }
81
82protected:
83    REQUIRE(0 == (N & (N-1)));
84
85    SkNi<N/2, T> fLo, fHi;
86};
87
88template <int N, typename T>
89class SkNf {
90    typedef SkNb<N, sizeof(T)> Nb;
91
92    static int32_t MyNi(float);
93    static int64_t MyNi(double);
94    typedef SkNi<N, decltype(MyNi(T()))> Ni;
95public:
96    SkNf() {}
97    explicit SkNf(T val) : fLo(val),  fHi(val) {}
98    static SkNf Load(const T vals[N]) {
99        return SkNf(SkNf<N/2,T>::Load(vals), SkNf<N/2,T>::Load(vals+N/2));
100    }
101
102    SkNf(T a, T b)                               : fLo(a),       fHi(b)       { REQUIRE(N==2); }
103    SkNf(T a, T b, T c, T d)                     : fLo(a,b),     fHi(c,d)     { REQUIRE(N==4); }
104    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); }
105
106    void store(T vals[N]) const {
107        fLo.store(vals);
108        fHi.store(vals+N/2);
109    }
110
111    Ni castTrunc() const { return Ni(fLo.castTrunc(), fHi.castTrunc()); }
112
113    SkNf operator + (const SkNf& o) const { return SkNf(fLo + o.fLo, fHi + o.fHi); }
114    SkNf operator - (const SkNf& o) const { return SkNf(fLo - o.fLo, fHi - o.fHi); }
115    SkNf operator * (const SkNf& o) const { return SkNf(fLo * o.fLo, fHi * o.fHi); }
116    SkNf operator / (const SkNf& o) const { return SkNf(fLo / o.fLo, fHi / o.fHi); }
117
118    Nb operator == (const SkNf& o) const { return Nb(fLo == o.fLo, fHi == o.fHi); }
119    Nb operator != (const SkNf& o) const { return Nb(fLo != o.fLo, fHi != o.fHi); }
120    Nb operator  < (const SkNf& o) const { return Nb(fLo  < o.fLo, fHi  < o.fHi); }
121    Nb operator  > (const SkNf& o) const { return Nb(fLo  > o.fLo, fHi  > o.fHi); }
122    Nb operator <= (const SkNf& o) const { return Nb(fLo <= o.fLo, fHi <= o.fHi); }
123    Nb operator >= (const SkNf& o) const { return Nb(fLo >= o.fLo, fHi >= o.fHi); }
124
125    static SkNf Min(const SkNf& l, const SkNf& r) {
126        return SkNf(SkNf<N/2,T>::Min(l.fLo, r.fLo), SkNf<N/2,T>::Min(l.fHi, r.fHi));
127    }
128    static SkNf Max(const SkNf& l, const SkNf& r) {
129        return SkNf(SkNf<N/2,T>::Max(l.fLo, r.fLo), SkNf<N/2,T>::Max(l.fHi, r.fHi));
130    }
131
132    SkNf  sqrt() const { return SkNf(fLo. sqrt(), fHi. sqrt()); }
133
134    // Generally, increasing precision, increasing cost.
135    SkNf rsqrt0() const { return SkNf(fLo.rsqrt0(), fHi.rsqrt0()); }
136    SkNf rsqrt1() const { return SkNf(fLo.rsqrt1(), fHi.rsqrt1()); }
137    SkNf rsqrt2() const { return SkNf(fLo.rsqrt2(), fHi.rsqrt2()); }
138
139    SkNf       invert() const { return SkNf(fLo.      invert(), fHi.      invert()); }
140    SkNf approxInvert() const { return SkNf(fLo.approxInvert(), fHi.approxInvert()); }
141
142    template <int k> T kth() const {
143        SkASSERT(0 <= k && k < N);
144        return k < N/2 ? fLo.template kth<k>() : fHi.template kth<k-N/2>();
145    }
146
147protected:
148    REQUIRE(0 == (N & (N-1)));
149    SkNf(const SkNf<N/2, T>& lo, const SkNf<N/2, T>& hi) : fLo(lo), fHi(hi) {}
150
151    SkNf<N/2, T> fLo, fHi;
152};
153
154
155// Bottom out the default implementations with scalars when nothing's been specialized.
156
157template <int Bytes>
158class SkNb<1, Bytes> {
159public:
160    SkNb() {}
161    explicit SkNb(bool val) : fVal(val) {}
162    bool allTrue() const { return fVal; }
163    bool anyTrue() const { return fVal; }
164protected:
165    bool fVal;
166};
167
168template <typename T>
169class SkNi<1,T> {
170public:
171    SkNi() {}
172    explicit SkNi(T val) : fVal(val) {}
173    static SkNi Load(const T vals[1]) { return SkNi(vals[0]); }
174
175    void store(T vals[1]) const { vals[0] = fVal; }
176
177    SkNi saturatedAdd(const SkNi& o) const {
178        SkASSERT((T)(~0) > 0); // TODO: support signed T
179        T sum = fVal + o.fVal;
180        return SkNi(sum > fVal ? sum : (T)(~0));
181    }
182
183    SkNi operator + (const SkNi& o) const { return SkNi(fVal + o.fVal); }
184    SkNi operator - (const SkNi& o) const { return SkNi(fVal - o.fVal); }
185    SkNi operator * (const SkNi& o) const { return SkNi(fVal * o.fVal); }
186
187    SkNi operator << (int bits) const { return SkNi(fVal << bits); }
188    SkNi operator >> (int bits) const { return SkNi(fVal >> bits); }
189
190    static SkNi Min(const SkNi& a, const SkNi& b) { return SkNi(SkTMin(a.fVal, b.fVal)); }
191
192    template <int k> T kth() const {
193        SkASSERT(0 == k);
194        return fVal;
195    }
196
197protected:
198    T fVal;
199};
200
201template <typename T>
202class SkNf<1,T> {
203    typedef SkNb<1, sizeof(T)> Nb;
204
205    static int32_t MyNi(float);
206    static int64_t MyNi(double);
207    typedef SkNi<1, decltype(MyNi(T()))> Ni;
208public:
209    SkNf() {}
210    explicit SkNf(T val) : fVal(val) {}
211    static SkNf Load(const T vals[1]) { return SkNf(vals[0]); }
212
213    void store(T vals[1]) const { vals[0] = fVal; }
214
215    Ni castTrunc() const { return Ni(fVal); }
216
217    SkNf operator + (const SkNf& o) const { return SkNf(fVal + o.fVal); }
218    SkNf operator - (const SkNf& o) const { return SkNf(fVal - o.fVal); }
219    SkNf operator * (const SkNf& o) const { return SkNf(fVal * o.fVal); }
220    SkNf operator / (const SkNf& o) const { return SkNf(fVal / o.fVal); }
221
222    Nb operator == (const SkNf& o) const { return Nb(fVal == o.fVal); }
223    Nb operator != (const SkNf& o) const { return Nb(fVal != o.fVal); }
224    Nb operator  < (const SkNf& o) const { return Nb(fVal  < o.fVal); }
225    Nb operator  > (const SkNf& o) const { return Nb(fVal  > o.fVal); }
226    Nb operator <= (const SkNf& o) const { return Nb(fVal <= o.fVal); }
227    Nb operator >= (const SkNf& o) const { return Nb(fVal >= o.fVal); }
228
229    static SkNf Min(const SkNf& l, const SkNf& r) { return SkNf(SkTMin(l.fVal, r.fVal)); }
230    static SkNf Max(const SkNf& l, const SkNf& r) { return SkNf(SkTMax(l.fVal, r.fVal)); }
231
232    SkNf  sqrt() const { return SkNf(Sqrt(fVal));        }
233    SkNf rsqrt0() const { return SkNf((T)1 / Sqrt(fVal)); }
234    SkNf rsqrt1() const { return this->rsqrt0(); }
235    SkNf rsqrt2() const { return this->rsqrt1(); }
236
237    SkNf       invert() const { return SkNf((T)1 / fVal); }
238    SkNf approxInvert() const { return this->invert();    }
239
240    template <int k> T kth() const {
241        SkASSERT(k == 0);
242        return fVal;
243    }
244
245protected:
246    // We do double sqrts natively, or via floats for any other type.
247    template <typename U>
248    static U      Sqrt(U      val) { return (U) ::sqrtf((float)val); }
249    static double Sqrt(double val) { return     ::sqrt (       val); }
250
251    T fVal;
252};
253
254
255// Generic syntax sugar that should work equally well for all implementations.
256template <typename T> T operator - (const T& l) { return T(0) - l; }
257
258template <typename L, typename R> L& operator += (L& l, const R& r) { return (l = l + r); }
259template <typename L, typename R> L& operator -= (L& l, const R& r) { return (l = l - r); }
260template <typename L, typename R> L& operator *= (L& l, const R& r) { return (l = l * r); }
261template <typename L, typename R> L& operator /= (L& l, const R& r) { return (l = l / r); }
262
263template <typename L> L& operator <<= (L& l, int bits) { return (l = l << bits); }
264template <typename L> L& operator >>= (L& l, int bits) { return (l = l >> bits); }
265
266// Include platform specific specializations if available.
267#ifndef SKNX_NO_SIMD
268    #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
269        #include "../opts/SkNx_sse.h"
270    #elif defined(SK_ARM_HAS_NEON)
271        #include "../opts/SkNx_neon.h"
272    #endif
273#endif
274
275#undef REQUIRE
276
277typedef SkNf<2,    float> Sk2f;
278typedef SkNf<2,   double> Sk2d;
279typedef SkNf<2, SkScalar> Sk2s;
280
281typedef SkNf<4,    float> Sk4f;
282typedef SkNf<4,   double> Sk4d;
283typedef SkNf<4, SkScalar> Sk4s;
284
285typedef SkNi<4,  uint16_t> Sk4h;
286typedef SkNi<8,  uint16_t> Sk8h;
287typedef SkNi<16, uint16_t> Sk16h;
288
289typedef SkNi<16, uint8_t> Sk16b;
290
291typedef SkNi<4,  int32_t> Sk4i;
292typedef SkNi<4, uint32_t> Sk4u;
293
294#endif//SkNx_DEFINED
295