SkNx.h revision a156a8ffbe1342a9c329e66ad1438934ac309d70
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 of SkNi<N,T> and SkNf<N,T> just fall back on a pair of size N/2.
21template <int N, typename T>
22class SkNi {
23public:
24    // For now SkNi is a _very_ minimal sketch just to support comparison operators on SkNf.
25    SkNi() {}
26    SkNi(const SkNi<N/2, T>& lo, const SkNi<N/2, T>& hi) : fLo(lo), fHi(hi) {}
27    bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); }
28    bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); }
29
30private:
31    REQUIRE(0 == (N & (N-1)));
32    SkNi<N/2, T> fLo, fHi;
33};
34
35template <int N, typename T>
36class SkNf {
37    static SkNi<N,int32_t> ToNi(float);
38    static SkNi<N,int64_t> ToNi(double);
39    typedef decltype(ToNi(T())) Ni;
40public:
41    SkNf() {}
42    explicit SkNf(T val)           : fLo(val),  fHi(val)      {}
43    static SkNf Load(const T vals[N]) {
44        return SkNf(SkNf<N/2,T>::Load(vals), SkNf<N/2,T>::Load(vals+N/2));
45    }
46
47    SkNf(T a, T b)                               : fLo(a),       fHi(b)       { REQUIRE(N==2); }
48    SkNf(T a, T b, T c, T d)                     : fLo(a,b),     fHi(c,d)     { REQUIRE(N==4); }
49    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); }
50
51    void store(T vals[N]) const {
52        fLo.store(vals);
53        fHi.store(vals+N/2);
54    }
55
56    SkNf operator + (const SkNf& o) const { return SkNf(fLo + o.fLo, fHi + o.fHi); }
57    SkNf operator - (const SkNf& o) const { return SkNf(fLo - o.fLo, fHi - o.fHi); }
58    SkNf operator * (const SkNf& o) const { return SkNf(fLo * o.fLo, fHi * o.fHi); }
59    SkNf operator / (const SkNf& o) const { return SkNf(fLo / o.fLo, fHi / o.fHi); }
60
61    Ni operator == (const SkNf& o) const { return Ni(fLo == o.fLo, fHi == o.fHi); }
62    Ni operator != (const SkNf& o) const { return Ni(fLo != o.fLo, fHi != o.fHi); }
63    Ni operator  < (const SkNf& o) const { return Ni(fLo  < o.fLo, fHi  < o.fHi); }
64    Ni operator  > (const SkNf& o) const { return Ni(fLo  > o.fLo, fHi  > o.fHi); }
65    Ni operator <= (const SkNf& o) const { return Ni(fLo <= o.fLo, fHi <= o.fHi); }
66    Ni operator >= (const SkNf& o) const { return Ni(fLo >= o.fLo, fHi >= o.fHi); }
67
68    static SkNf Min(const SkNf& l, const SkNf& r) {
69        return SkNf(SkNf<N/2,T>::Min(l.fLo, r.fLo), SkNf<N/2,T>::Min(l.fHi, r.fHi));
70    }
71    static SkNf Max(const SkNf& l, const SkNf& r) {
72        return SkNf(SkNf<N/2,T>::Max(l.fLo, r.fLo), SkNf<N/2,T>::Max(l.fHi, r.fHi));
73    }
74
75    SkNf  sqrt() const { return SkNf(fLo. sqrt(), fHi. sqrt()); }
76    SkNf rsqrt() const { return SkNf(fLo.rsqrt(), fHi.rsqrt()); }
77
78    SkNf       invert() const { return SkNf(fLo.      invert(), fHi.      invert()); }
79    SkNf approxInvert() const { return SkNf(fLo.approxInvert(), fHi.approxInvert()); }
80
81    template <int k> T kth() const {
82        SkASSERT(0 <= k && k < N);
83        return k < N/2 ? fLo.template kth<k>() : fHi.template kth<k-N/2>();
84    }
85
86private:
87    REQUIRE(0 == (N & (N-1)));
88    SkNf(const SkNf<N/2, T>& lo, const SkNf<N/2, T>& hi) : fLo(lo), fHi(hi) {}
89
90    SkNf<N/2, T> fLo, fHi;
91};
92
93
94// Bottom out the default implementation with scalars when nothing's been specialized.
95template <typename T>
96class SkNi<1,T> {
97public:
98    SkNi() {}
99    explicit SkNi(T val) : fVal(val) {}
100    bool allTrue() const { return (bool)fVal; }
101    bool anyTrue() const { return (bool)fVal; }
102
103private:
104    T fVal;
105};
106
107template <typename T>
108class SkNf<1,T> {
109    static SkNi<1,int32_t> ToNi(float);
110    static SkNi<1,int64_t> ToNi(double);
111    typedef decltype(ToNi(T())) Ni;
112public:
113    SkNf() {}
114    explicit SkNf(T val)           : fVal(val)     {}
115    static SkNf Load(const T vals[1]) { return SkNf(vals[0]); }
116
117    void store(T vals[1]) const { vals[0] = fVal; }
118
119    SkNf operator + (const SkNf& o) const { return SkNf(fVal + o.fVal); }
120    SkNf operator - (const SkNf& o) const { return SkNf(fVal - o.fVal); }
121    SkNf operator * (const SkNf& o) const { return SkNf(fVal * o.fVal); }
122    SkNf operator / (const SkNf& o) const { return SkNf(fVal / o.fVal); }
123
124    Ni operator == (const SkNf& o) const { return Ni(fVal == o.fVal); }
125    Ni operator != (const SkNf& o) const { return Ni(fVal != o.fVal); }
126    Ni operator  < (const SkNf& o) const { return Ni(fVal  < o.fVal); }
127    Ni operator  > (const SkNf& o) const { return Ni(fVal  > o.fVal); }
128    Ni operator <= (const SkNf& o) const { return Ni(fVal <= o.fVal); }
129    Ni operator >= (const SkNf& o) const { return Ni(fVal >= o.fVal); }
130
131    static SkNf Min(const SkNf& l, const SkNf& r) { return SkNf(SkTMin(l.fVal, r.fVal)); }
132    static SkNf Max(const SkNf& l, const SkNf& r) { return SkNf(SkTMax(l.fVal, r.fVal)); }
133
134    SkNf  sqrt() const { return SkNf(Sqrt(fVal));          }
135    SkNf rsqrt() const { return SkNf((T)1 / Sqrt(fVal)); }
136
137    SkNf       invert() const { return SkNf((T)1 / fVal); }
138    SkNf approxInvert() const { return this->invert();    }
139
140    template <int k> T kth() const {
141        SkASSERT(k == 0);
142        return fVal;
143    }
144
145private:
146    // We do double sqrts natively, or via floats for any other type.
147    template <typename U>
148    static U      Sqrt(U      val) { return (U) ::sqrtf((float)val); }
149    static double Sqrt(double val) { return     ::sqrt (       val); }
150
151    T fVal;
152};
153
154
155// Generic syntax sugar that should work equally well for all SkNi and SkNf implementations.
156template <typename SkNx> SkNx operator - (const SkNx& l) { return SkNx(0) - l; }
157
158template <typename SkNx> SkNx& operator += (SkNx& l, const SkNx& r) { return (l = l + r); }
159template <typename SkNx> SkNx& operator -= (SkNx& l, const SkNx& r) { return (l = l - r); }
160template <typename SkNx> SkNx& operator *= (SkNx& l, const SkNx& r) { return (l = l * r); }
161template <typename SkNx> SkNx& operator /= (SkNx& l, const SkNx& r) { return (l = l / r); }
162
163
164// Include platform specific specializations if available.
165#ifndef SKNX_NO_SIMD
166    #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
167        #include "../opts/SkNx_sse.h"
168    #elif defined(SK_ARM_HAS_NEON)
169        #include "../opts/SkNx_neon.h"
170    #endif
171#endif
172
173#undef REQUIRE
174
175typedef SkNf<2,    float> Sk2f;
176typedef SkNf<2,   double> Sk2d;
177typedef SkNf<2, SkScalar> Sk2s;
178
179typedef SkNf<4,    float> Sk4f;
180typedef SkNf<4,   double> Sk4d;
181typedef SkNf<4, SkScalar> Sk4s;
182
183typedef SkNi<4, int32_t> Sk4i;
184
185#endif//SkNx_DEFINED
186