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 | |
Mike Klein | e9f78b4 | 2016-11-22 08:57:45 -0500 | [diff] [blame] | 11 | #include "SkSafe_math.h" |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 12 | #include "SkScalar.h" |
| 13 | #include "SkTypes.h" |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 14 | #include <limits> |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 15 | #include <type_traits> |
mtklein | 082e329 | 2015-08-12 11:56:43 -0700 | [diff] [blame] | 16 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 17 | // Every single SkNx method wants to be fully inlined. (We know better than MSVC). |
| 18 | #define AI SK_ALWAYS_INLINE |
Mike Klein | 1e76464 | 2016-10-14 17:09:03 -0400 | [diff] [blame] | 19 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 20 | namespace { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 21 | |
| 22 | // The default SkNx<N,T> just proxies down to a pair of SkNx<N/2, T>. |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 23 | template <int N, typename T> |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 24 | struct SkNx { |
mtklein | e4c0bee | 2016-02-09 10:35:27 -0800 | [diff] [blame] | 25 | typedef SkNx<N/2, T> Half; |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 26 | |
| 27 | Half fLo, fHi; |
| 28 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 29 | AI SkNx() = default; |
| 30 | AI SkNx(const Half& lo, const Half& hi) : fLo(lo), fHi(hi) {} |
mtklein | e4c0bee | 2016-02-09 10:35:27 -0800 | [diff] [blame] | 31 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 32 | AI SkNx(T v) : fLo(v), fHi(v) {} |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 33 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 34 | 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) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 37 | static_assert(N==8, ""); |
| 38 | } |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 39 | 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) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 42 | static_assert(N==16, ""); |
mtklein | 6f37b4a | 2015-12-14 11:25:18 -0800 | [diff] [blame] | 43 | } |
| 44 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 45 | AI T operator[](int k) const { |
mtklein | 115acee | 2015-04-14 14:02:52 -0700 | [diff] [blame] | 46 | SkASSERT(0 <= k && k < N); |
mtklein | e4c0bee | 2016-02-09 10:35:27 -0800 | [diff] [blame] | 47 | return k < N/2 ? fLo[k] : fHi[k-N/2]; |
mtklein | 115acee | 2015-04-14 14:02:52 -0700 | [diff] [blame] | 48 | } |
| 49 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 50 | AI static SkNx Load(const void* vptr) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 51 | auto ptr = (const char*)vptr; |
| 52 | return { Half::Load(ptr), Half::Load(ptr + N/2*sizeof(T)) }; |
| 53 | } |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 54 | AI void store(void* vptr) const { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 55 | auto ptr = (char*)vptr; |
| 56 | fLo.store(ptr); |
| 57 | fHi.store(ptr + N/2*sizeof(T)); |
mtklein | b5e8611 | 2015-06-24 15:18:39 -0700 | [diff] [blame] | 58 | } |
| 59 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 60 | AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) { |
Mike Klein | 33cbfd7 | 2016-10-06 11:09:27 -0400 | [diff] [blame] | 61 | 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 Sarett | 5bee0b6 | 2017-01-19 12:04:32 -0500 | [diff] [blame^] | 71 | 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 Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 81 | AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { |
Mike Klein | 33cbfd7 | 2016-10-06 11:09:27 -0400 | [diff] [blame] | 82 | 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 Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 87 | AI bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } |
| 88 | AI bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } |
mtklein | 115acee | 2015-04-14 14:02:52 -0700 | [diff] [blame] | 89 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 90 | 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() }; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 95 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 96 | AI SkNx operator!() const { return { !fLo, !fHi }; } |
| 97 | AI SkNx operator-() const { return { -fLo, -fHi }; } |
| 98 | AI SkNx operator~() const { return { ~fLo, ~fHi }; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 99 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 100 | AI SkNx operator<<(int bits) const { return { fLo << bits, fHi << bits }; } |
| 101 | AI SkNx operator>>(int bits) const { return { fLo >> bits, fHi >> bits }; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 102 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 103 | 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 }; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 107 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 108 | 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 }; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 111 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 112 | 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 }; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 118 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 119 | AI SkNx saturatedAdd(const SkNx& y) const { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 120 | return { fLo.saturatedAdd(y.fLo), fHi.saturatedAdd(y.fHi) }; |
| 121 | } |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 122 | AI SkNx thenElse(const SkNx& t, const SkNx& e) const { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 123 | return { fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi) }; |
| 124 | } |
| 125 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 126 | AI static SkNx Min(const SkNx& x, const SkNx& y) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 127 | return { Half::Min(x.fLo, y.fLo), Half::Min(x.fHi, y.fHi) }; |
| 128 | } |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 129 | AI static SkNx Max(const SkNx& x, const SkNx& y) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 130 | return { Half::Max(x.fLo, y.fLo), Half::Max(x.fHi, y.fHi) }; |
| 131 | } |
mtklein | 115acee | 2015-04-14 14:02:52 -0700 | [diff] [blame] | 132 | }; |
| 133 | |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 134 | // The N -> N/2 recursion bottoms out at N == 1, a scalar value. |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 135 | template <typename T> |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 136 | struct SkNx<1,T> { |
| 137 | T fVal; |
mtklein | e4c0bee | 2016-02-09 10:35:27 -0800 | [diff] [blame] | 138 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 139 | AI SkNx() = default; |
| 140 | AI SkNx(T v) : fVal(v) {} |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 141 | |
reed | 1264472 | 2016-07-12 09:12:30 -0700 | [diff] [blame] | 142 | // Android complains against unused parameters, so we guard it |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 143 | AI T operator[](int SkDEBUGCODE(k)) const { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 144 | SkASSERT(k == 0); |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 145 | return fVal; |
| 146 | } |
| 147 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 148 | AI static SkNx Load(const void* ptr) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 149 | SkNx v; |
| 150 | memcpy(&v, ptr, sizeof(T)); |
| 151 | return v; |
| 152 | } |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 153 | AI void store(void* ptr) const { memcpy(ptr, &fVal, sizeof(T)); } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 154 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 155 | AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) { |
Mike Klein | 33cbfd7 | 2016-10-06 11:09:27 -0400 | [diff] [blame] | 156 | auto ptr = (const char*)vptr; |
| 157 | *a = Load(ptr + 0*sizeof(T)); |
| 158 | *b = Load(ptr + 1*sizeof(T)); |
| 159 | *c = Load(ptr + 2*sizeof(T)); |
| 160 | *d = Load(ptr + 3*sizeof(T)); |
| 161 | } |
Matt Sarett | 5bee0b6 | 2017-01-19 12:04:32 -0500 | [diff] [blame^] | 162 | AI static void Load3(const void* vptr, SkNx* a, SkNx* b, SkNx* c) { |
| 163 | auto ptr = (const char*)vptr; |
| 164 | *a = Load(ptr + 0*sizeof(T)); |
| 165 | *b = Load(ptr + 1*sizeof(T)); |
| 166 | *c = Load(ptr + 2*sizeof(T)); |
| 167 | } |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 168 | AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { |
Mike Klein | 33cbfd7 | 2016-10-06 11:09:27 -0400 | [diff] [blame] | 169 | auto ptr = (char*)vptr; |
| 170 | a.store(ptr + 0*sizeof(T)); |
| 171 | b.store(ptr + 1*sizeof(T)); |
| 172 | c.store(ptr + 2*sizeof(T)); |
| 173 | d.store(ptr + 3*sizeof(T)); |
| 174 | } |
| 175 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 176 | AI bool anyTrue() const { return fVal != 0; } |
| 177 | AI bool allTrue() const { return fVal != 0; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 178 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 179 | AI SkNx abs() const { return Abs(fVal); } |
| 180 | AI SkNx sqrt() const { return Sqrt(fVal); } |
| 181 | AI SkNx rsqrt() const { return T(1) / this->sqrt(); } |
| 182 | AI SkNx floor() const { return Floor(fVal); } |
| 183 | AI SkNx invert() const { return T(1) / *this; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 184 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 185 | AI SkNx operator!() const { return !fVal; } |
| 186 | AI SkNx operator-() const { return -fVal; } |
| 187 | AI SkNx operator~() const { return FromBits(~ToBits(fVal)); } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 188 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 189 | AI SkNx operator<<(int bits) const { return fVal << bits; } |
| 190 | AI SkNx operator>>(int bits) const { return fVal >> bits; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 191 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 192 | AI SkNx operator+(const SkNx& y) const { return fVal + y.fVal; } |
| 193 | AI SkNx operator-(const SkNx& y) const { return fVal - y.fVal; } |
| 194 | AI SkNx operator*(const SkNx& y) const { return fVal * y.fVal; } |
| 195 | AI SkNx operator/(const SkNx& y) const { return fVal / y.fVal; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 196 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 197 | AI SkNx operator&(const SkNx& y) const { return FromBits(ToBits(fVal) & ToBits(y.fVal)); } |
| 198 | AI SkNx operator|(const SkNx& y) const { return FromBits(ToBits(fVal) | ToBits(y.fVal)); } |
| 199 | AI SkNx operator^(const SkNx& y) const { return FromBits(ToBits(fVal) ^ ToBits(y.fVal)); } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 200 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 201 | AI SkNx operator==(const SkNx& y) const { return FromBits(fVal == y.fVal ? ~0 : 0); } |
| 202 | AI SkNx operator!=(const SkNx& y) const { return FromBits(fVal != y.fVal ? ~0 : 0); } |
| 203 | AI SkNx operator<=(const SkNx& y) const { return FromBits(fVal <= y.fVal ? ~0 : 0); } |
| 204 | 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); } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 207 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 208 | AI static SkNx Min(const SkNx& x, const SkNx& y) { return x.fVal < y.fVal ? x : y; } |
| 209 | AI static SkNx Max(const SkNx& x, const SkNx& y) { return x.fVal > y.fVal ? x : y; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 210 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 211 | AI SkNx saturatedAdd(const SkNx& y) const { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 212 | static_assert(std::is_unsigned<T>::value, ""); |
| 213 | T sum = fVal + y.fVal; |
| 214 | return sum < fVal ? std::numeric_limits<T>::max() : sum; |
| 215 | } |
| 216 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 217 | AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e; } |
mtklein | b5e8611 | 2015-06-24 15:18:39 -0700 | [diff] [blame] | 218 | |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 219 | private: |
| 220 | // Helper functions to choose the right float/double methods. (In <cmath> madness lies...) |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 221 | AI static float Abs(float val) { return ::fabsf(val); } |
| 222 | AI static float Sqrt(float val) { return ::sqrtf(val); } |
| 223 | AI static float Floor(float val) { return ::floorf(val); } |
mtklein | b5e8611 | 2015-06-24 15:18:39 -0700 | [diff] [blame] | 224 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 225 | AI static double Abs(double val) { return ::fabs(val); } |
| 226 | AI static double Sqrt(double val) { return ::sqrt(val); } |
| 227 | AI static double Floor(double val) { return ::floor(val); } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 228 | |
| 229 | // Helper functions for working with floats/doubles as bit patterns. |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 230 | template <typename U> |
| 231 | AI static U ToBits(U v) { return v; } |
| 232 | AI static int32_t ToBits(float v) { int32_t bits; memcpy(&bits, &v, sizeof(v)); return bits; } |
| 233 | AI static int64_t ToBits(double v) { int64_t bits; memcpy(&bits, &v, sizeof(v)); return bits; } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 234 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 235 | template <typename Bits> |
| 236 | AI static T FromBits(Bits bits) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 237 | static_assert(std::is_pod<T >::value && |
| 238 | std::is_pod<Bits>::value && |
| 239 | sizeof(T) <= sizeof(Bits), ""); |
| 240 | T val; |
| 241 | memcpy(&val, &bits, sizeof(T)); |
| 242 | return val; |
| 243 | } |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 244 | }; |
| 245 | |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 246 | // Allow scalars on the left or right of binary operators, and things like +=, &=, etc. |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 247 | #define V template <int N, typename T> AI static SkNx<N,T> |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 248 | V operator+ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) + y; } |
| 249 | V operator- (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) - y; } |
| 250 | V operator* (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) * y; } |
| 251 | V operator/ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) / y; } |
| 252 | V operator& (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) & y; } |
| 253 | V operator| (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) | y; } |
| 254 | V operator^ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) ^ y; } |
| 255 | V operator==(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) == y; } |
| 256 | V operator!=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) != y; } |
| 257 | V operator<=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) <= y; } |
| 258 | V operator>=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) >= y; } |
| 259 | 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 | |
| 262 | V operator+ (const SkNx<N,T>& x, T y) { return x + SkNx<N,T>(y); } |
| 263 | V operator- (const SkNx<N,T>& x, T y) { return x - SkNx<N,T>(y); } |
| 264 | V operator* (const SkNx<N,T>& x, T y) { return x * SkNx<N,T>(y); } |
| 265 | V operator/ (const SkNx<N,T>& x, T y) { return x / SkNx<N,T>(y); } |
| 266 | V operator& (const SkNx<N,T>& x, T y) { return x & SkNx<N,T>(y); } |
| 267 | V operator| (const SkNx<N,T>& x, T y) { return x | SkNx<N,T>(y); } |
| 268 | V operator^ (const SkNx<N,T>& x, T y) { return x ^ SkNx<N,T>(y); } |
| 269 | V operator==(const SkNx<N,T>& x, T y) { return x == SkNx<N,T>(y); } |
| 270 | V operator!=(const SkNx<N,T>& x, T y) { return x != SkNx<N,T>(y); } |
| 271 | V operator<=(const SkNx<N,T>& x, T y) { return x <= SkNx<N,T>(y); } |
| 272 | V operator>=(const SkNx<N,T>& x, T y) { return x >= SkNx<N,T>(y); } |
| 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 | |
| 276 | V& operator<<=(SkNx<N,T>& x, int bits) { return (x = x << bits); } |
| 277 | V& operator>>=(SkNx<N,T>& x, int bits) { return (x = x >> bits); } |
| 278 | |
| 279 | V& operator +=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x + y); } |
| 280 | V& operator -=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x - y); } |
| 281 | V& operator *=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x * y); } |
| 282 | V& operator /=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x / y); } |
| 283 | V& operator &=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x & y); } |
| 284 | V& operator |=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x | y); } |
| 285 | V& operator ^=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x ^ y); } |
| 286 | |
| 287 | V& operator +=(SkNx<N,T>& x, T y) { return (x = x + SkNx<N,T>(y)); } |
| 288 | V& operator -=(SkNx<N,T>& x, T y) { return (x = x - SkNx<N,T>(y)); } |
| 289 | V& operator *=(SkNx<N,T>& x, T y) { return (x = x * SkNx<N,T>(y)); } |
| 290 | V& operator /=(SkNx<N,T>& x, T y) { return (x = x / SkNx<N,T>(y)); } |
| 291 | V& operator &=(SkNx<N,T>& x, T y) { return (x = x & SkNx<N,T>(y)); } |
| 292 | V& operator |=(SkNx<N,T>& x, T y) { return (x = x | SkNx<N,T>(y)); } |
| 293 | V& operator ^=(SkNx<N,T>& x, T y) { return (x = x ^ SkNx<N,T>(y)); } |
| 294 | #undef V |
| 295 | |
| 296 | // SkNx<N,T> ~~> SkNx<N/2,T> + SkNx<N/2,T> |
| 297 | template <int N, typename T> |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 298 | AI static void SkNx_split(const SkNx<N,T>& v, SkNx<N/2,T>* lo, SkNx<N/2,T>* hi) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 299 | *lo = v.fLo; |
| 300 | *hi = v.fHi; |
| 301 | } |
| 302 | |
| 303 | // SkNx<N/2,T> + SkNx<N/2,T> ~~> SkNx<N,T> |
| 304 | template <int N, typename T> |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 305 | AI static SkNx<N*2,T> SkNx_join(const SkNx<N,T>& lo, const SkNx<N,T>& hi) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 306 | return { lo, hi }; |
| 307 | } |
| 308 | |
| 309 | // A very generic shuffle. Can reorder, duplicate, contract, expand... |
| 310 | // Sk4f v = { R,G,B,A }; |
| 311 | // SkNx_shuffle<2,1,0,3>(v) ~~> {B,G,R,A} |
| 312 | // SkNx_shuffle<2,1>(v) ~~> {B,G} |
| 313 | // SkNx_shuffle<2,1,2,1,2,1,2,1>(v) ~~> {B,G,B,G,B,G,B,G} |
| 314 | // SkNx_shuffle<3,3,3,3>(v) ~~> {A,A,A,A} |
mtklein | e4c0bee | 2016-02-09 10:35:27 -0800 | [diff] [blame] | 315 | template <int... Ix, int N, typename T> |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 316 | AI static SkNx<sizeof...(Ix),T> SkNx_shuffle(const SkNx<N,T>& v) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 317 | return { v[Ix]... }; |
mtklein | 6c221b4 | 2015-11-20 13:53:19 -0800 | [diff] [blame] | 318 | } |
mtklein | a1c0ee4 | 2015-09-10 14:16:07 -0700 | [diff] [blame] | 319 | |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 320 | // Cast from SkNx<N, Src> to SkNx<N, Dst>, as if you called static_cast<Dst>(Src). |
| 321 | template <typename Dst, typename Src, int N> |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 322 | AI static SkNx<N,Dst> SkNx_cast(const SkNx<N,Src>& v) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 323 | return { SkNx_cast<Dst>(v.fLo), SkNx_cast<Dst>(v.fHi) }; |
mtklein | e4c0bee | 2016-02-09 10:35:27 -0800 | [diff] [blame] | 324 | } |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 325 | template <typename Dst, typename Src> |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 326 | AI static SkNx<1,Dst> SkNx_cast(const SkNx<1,Src>& v) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 327 | return static_cast<Dst>(v.fVal); |
mtklein | e4c0bee | 2016-02-09 10:35:27 -0800 | [diff] [blame] | 328 | } |
mtklein | fce612a | 2015-12-15 07:38:54 -0800 | [diff] [blame] | 329 | |
Mike Klein | 04adfda | 2016-10-12 09:52:55 -0400 | [diff] [blame] | 330 | template <int N, typename T> |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 331 | AI static SkNx<N,T> SkNx_fma(const SkNx<N,T>& f, const SkNx<N,T>& m, const SkNx<N,T>& a) { |
Mike Klein | 04adfda | 2016-10-12 09:52:55 -0400 | [diff] [blame] | 332 | return f*m+a; |
| 333 | } |
| 334 | |
Mike Klein | 1e76464 | 2016-10-14 17:09:03 -0400 | [diff] [blame] | 335 | } // namespace |
| 336 | |
mtklein | e4c0bee | 2016-02-09 10:35:27 -0800 | [diff] [blame] | 337 | typedef SkNx<2, float> Sk2f; |
| 338 | typedef SkNx<4, float> Sk4f; |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 339 | typedef SkNx<8, float> Sk8f; |
| 340 | typedef SkNx<16, float> Sk16f; |
| 341 | |
mtklein | e4c0bee | 2016-02-09 10:35:27 -0800 | [diff] [blame] | 342 | typedef SkNx<2, SkScalar> Sk2s; |
| 343 | typedef SkNx<4, SkScalar> Sk4s; |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 344 | typedef SkNx<8, SkScalar> Sk8s; |
| 345 | typedef SkNx<16, SkScalar> Sk16s; |
mtklein | c9adb05 | 2015-03-30 10:50:27 -0700 | [diff] [blame] | 346 | |
mtklein | e4c0bee | 2016-02-09 10:35:27 -0800 | [diff] [blame] | 347 | typedef SkNx<4, uint8_t> Sk4b; |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 348 | typedef SkNx<8, uint8_t> Sk8b; |
mtklein | e4c0bee | 2016-02-09 10:35:27 -0800 | [diff] [blame] | 349 | typedef SkNx<16, uint8_t> Sk16b; |
mtklein | 6f37b4a | 2015-12-14 11:25:18 -0800 | [diff] [blame] | 350 | |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 351 | typedef SkNx<4, uint16_t> Sk4h; |
| 352 | typedef SkNx<8, uint16_t> Sk8h; |
| 353 | typedef SkNx<16, uint16_t> Sk16h; |
| 354 | |
mtklein | d05a875 | 2016-07-29 10:10:15 -0700 | [diff] [blame] | 355 | typedef SkNx<4, int32_t> Sk4i; |
Mike Klein | 04adfda | 2016-10-12 09:52:55 -0400 | [diff] [blame] | 356 | typedef SkNx<8, int32_t> Sk8i; |
mtklein | d05a875 | 2016-07-29 10:10:15 -0700 | [diff] [blame] | 357 | typedef SkNx<4, uint32_t> Sk4u; |
mtklein | ff9febf | 2016-02-16 14:33:08 -0800 | [diff] [blame] | 358 | |
mtklein | 6f37b4a | 2015-12-14 11:25:18 -0800 | [diff] [blame] | 359 | // Include platform specific specializations if available. |
mtklein | 81bb79b | 2016-02-08 15:50:22 -0800 | [diff] [blame] | 360 | #if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
msarett | afb8539 | 2016-07-11 14:57:26 -0700 | [diff] [blame] | 361 | #include "../opts/SkNx_sse.h" |
mtklein | 6f37b4a | 2015-12-14 11:25:18 -0800 | [diff] [blame] | 362 | #elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) |
msarett | afb8539 | 2016-07-11 14:57:26 -0700 | [diff] [blame] | 363 | #include "../opts/SkNx_neon.h" |
msarett | 7d3ff71 | 2016-07-12 14:55:45 -0700 | [diff] [blame] | 364 | #else |
| 365 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 366 | AI static Sk4i Sk4f_round(const Sk4f& x) { |
msarett | 7d3ff71 | 2016-07-12 14:55:45 -0700 | [diff] [blame] | 367 | return { (int) lrintf (x[0]), |
| 368 | (int) lrintf (x[1]), |
| 369 | (int) lrintf (x[2]), |
| 370 | (int) lrintf (x[3]), }; |
| 371 | } |
| 372 | |
mtklein | 6f37b4a | 2015-12-14 11:25:18 -0800 | [diff] [blame] | 373 | #endif |
| 374 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 375 | AI static void Sk4f_ToBytes(uint8_t p[16], |
| 376 | const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) { |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 377 | SkNx_cast<uint8_t>(SkNx_join(SkNx_join(a,b), SkNx_join(c,d))).store(p); |
| 378 | } |
| 379 | |
Mike Klein | 7c78f3a | 2016-10-19 09:21:11 -0400 | [diff] [blame] | 380 | #undef AI |
mtklein | f8f90e4 | 2016-03-21 10:04:46 -0700 | [diff] [blame] | 381 | |
mtklein | 3e490b7 | 2015-03-20 06:33:02 -0700 | [diff] [blame] | 382 | #endif//SkNx_DEFINED |