mtklein | 3e490b7 | 2015-03-20 06:33:02 -0700 | [diff] [blame] | 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 | |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 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 | |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 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. |
| 24 | template <int N, int Bytes> |
| 25 | class SkNb { |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 26 | public: |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 27 | SkNb() {} |
| 28 | SkNb(const SkNb<N/2, Bytes>& lo, const SkNb<N/2, Bytes>& hi) : fLo(lo), fHi(hi) {} |
| 29 | |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 30 | bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } |
| 31 | bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } |
| 32 | |
| 33 | private: |
| 34 | REQUIRE(0 == (N & (N-1))); |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 35 | SkNb<N/2, Bytes> fLo, fHi; |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 36 | }; |
| 37 | |
| 38 | template <int N, typename T> |
mtklein | 115acee | 2015-04-14 14:02:52 -0700 | [diff] [blame] | 39 | class SkNi { |
| 40 | public: |
| 41 | SkNi() {} |
mtklein | 1113da7 | 2015-04-27 12:08:01 -0700 | [diff] [blame^] | 42 | SkNi(const SkNi<N/2, T>& lo, const SkNi<N/2, T>& hi) : fLo(lo), fHi(hi) {} |
mtklein | 115acee | 2015-04-14 14:02:52 -0700 | [diff] [blame] | 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 | |
| 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 | |
| 71 | private: |
| 72 | REQUIRE(0 == (N & (N-1))); |
mtklein | 115acee | 2015-04-14 14:02:52 -0700 | [diff] [blame] | 73 | |
| 74 | SkNi<N/2, T> fLo, fHi; |
| 75 | }; |
| 76 | |
| 77 | template <int N, typename T> |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 78 | class SkNf { |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 79 | typedef SkNb<N, sizeof(T)> Nb; |
mtklein | 1113da7 | 2015-04-27 12:08:01 -0700 | [diff] [blame^] | 80 | |
| 81 | static int32_t MyNi(float); |
| 82 | static int64_t MyNi(double); |
| 83 | typedef SkNi<N, decltype(MyNi(T()))> Ni; |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 84 | public: |
| 85 | SkNf() {} |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 86 | explicit SkNf(T val) : fLo(val), fHi(val) {} |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 87 | 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 | |
mtklein | 1113da7 | 2015-04-27 12:08:01 -0700 | [diff] [blame^] | 100 | Ni castTrunc() const { return Ni(fLo.castTrunc(), fHi.castTrunc()); } |
| 101 | |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 102 | 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 | |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 107 | 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); } |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 113 | |
| 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 | |
mtklein | a156a8f | 2015-04-03 06:16:13 -0700 | [diff] [blame] | 127 | template <int k> T kth() const { |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 128 | SkASSERT(0 <= k && k < N); |
mtklein | a156a8f | 2015-04-03 06:16:13 -0700 | [diff] [blame] | 129 | return k < N/2 ? fLo.template kth<k>() : fHi.template kth<k-N/2>(); |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 130 | } |
| 131 | |
| 132 | private: |
| 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 | |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 140 | // Bottom out the default implementations with scalars when nothing's been specialized. |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 141 | |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 142 | template <int Bytes> |
| 143 | class SkNb<1, Bytes> { |
| 144 | public: |
| 145 | SkNb() {} |
| 146 | explicit SkNb(bool val) : fVal(val) {} |
| 147 | bool allTrue() const { return fVal; } |
| 148 | bool anyTrue() const { return fVal; } |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 149 | private: |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 150 | bool fVal; |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 151 | }; |
| 152 | |
| 153 | template <typename T> |
mtklein | 115acee | 2015-04-14 14:02:52 -0700 | [diff] [blame] | 154 | class SkNi<1,T> { |
| 155 | public: |
| 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 | |
| 174 | private: |
| 175 | T fVal; |
| 176 | }; |
| 177 | |
| 178 | template <typename T> |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 179 | class SkNf<1,T> { |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 180 | typedef SkNb<1, sizeof(T)> Nb; |
mtklein | 1113da7 | 2015-04-27 12:08:01 -0700 | [diff] [blame^] | 181 | |
| 182 | static int32_t MyNi(float); |
| 183 | static int64_t MyNi(double); |
| 184 | typedef SkNi<1, decltype(MyNi(T()))> Ni; |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 185 | public: |
| 186 | SkNf() {} |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 187 | explicit SkNf(T val) : fVal(val) {} |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 188 | static SkNf Load(const T vals[1]) { return SkNf(vals[0]); } |
| 189 | |
| 190 | void store(T vals[1]) const { vals[0] = fVal; } |
| 191 | |
mtklein | 1113da7 | 2015-04-27 12:08:01 -0700 | [diff] [blame^] | 192 | Ni castTrunc() const { return Ni(fVal); } |
| 193 | |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 194 | 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 | |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 199 | 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); } |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 205 | |
| 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 | |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 209 | SkNf sqrt() const { return SkNf(Sqrt(fVal)); } |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 210 | 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 | |
mtklein | a156a8f | 2015-04-03 06:16:13 -0700 | [diff] [blame] | 215 | template <int k> T kth() const { |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 216 | SkASSERT(k == 0); |
| 217 | return fVal; |
| 218 | } |
| 219 | |
| 220 | private: |
| 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 | |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 230 | // Generic syntax sugar that should work equally well for all implementations. |
| 231 | template <typename T> T operator - (const T& l) { return T(0) - l; } |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 232 | |
mtklein | 8fe8fff | 2015-04-14 11:49:14 -0700 | [diff] [blame] | 233 | template <typename L, typename R> L& operator += (L& l, const R& r) { return (l = l + r); } |
| 234 | template <typename L, typename R> L& operator -= (L& l, const R& r) { return (l = l - r); } |
| 235 | template <typename L, typename R> L& operator *= (L& l, const R& r) { return (l = l * r); } |
| 236 | template <typename L, typename R> L& operator /= (L& l, const R& r) { return (l = l / r); } |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 237 | |
mtklein | 115acee | 2015-04-14 14:02:52 -0700 | [diff] [blame] | 238 | template <typename L> L& operator <<= (L& l, int bits) { return (l = l << bits); } |
| 239 | template <typename L> L& operator >>= (L& l, int bits) { return (l = l >> bits); } |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 240 | |
| 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 | |
| 252 | typedef SkNf<2, float> Sk2f; |
| 253 | typedef SkNf<2, double> Sk2d; |
| 254 | typedef SkNf<2, SkScalar> Sk2s; |
| 255 | |
| 256 | typedef SkNf<4, float> Sk4f; |
| 257 | typedef SkNf<4, double> Sk4d; |
| 258 | typedef SkNf<4, SkScalar> Sk4s; |
| 259 | |
mtklein | 115acee | 2015-04-14 14:02:52 -0700 | [diff] [blame] | 260 | typedef SkNi<4, uint16_t> Sk4h; |
| 261 | typedef SkNi<8, uint16_t> Sk8h; |
| 262 | |
mtklein | 1113da7 | 2015-04-27 12:08:01 -0700 | [diff] [blame^] | 263 | typedef SkNi<4, int> Sk4i; |
| 264 | |
mtklein | 3e490b7 | 2015-03-20 06:33:02 -0700 | [diff] [blame] | 265 | #endif//SkNx_DEFINED |