| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #ifndef SkNx_DEFINED | 8 #ifndef SkNx_DEFINED |
| 9 #define SkNx_DEFINED | 9 #define SkNx_DEFINED |
| 10 | 10 |
| 11 | |
| 12 //#define SKNX_NO_SIMD | 11 //#define SKNX_NO_SIMD |
| 13 | 12 |
| 14 #include "SkScalar.h" | 13 #include "SkScalar.h" |
| 15 #include "SkTypes.h" | 14 #include "SkTypes.h" |
| 16 #include <math.h> | 15 #include <math.h> |
| 17 #define REQUIRE(x) static_assert(x, #x) | |
| 18 | |
| 19 // This file may be included multiple times by .cpp files with different flags,
leading | |
| 20 // to different definitions. Usually that doesn't matter because it's all inlin
ed, but | |
| 21 // in Debug modes the compilers may not inline everything. So wrap everything i
n an | |
| 22 // anonymous namespace to give each includer their own silo of this code (or the
linker | |
| 23 // will probably pick one randomly for us, which is rarely correct). | |
| 24 namespace { | |
| 25 | 16 |
| 26 // The default implementations just fall back on a pair of size N/2. | 17 // The default implementations just fall back on a pair of size N/2. |
| 27 // These support the union of operations we might do to ints and floats, but | 18 // These support the union of operations we might do to ints and floats, but |
| 28 // platform specializations might support fewer (e.g. no float <<, no int /). | 19 // platform specializations might support fewer (e.g. no float <<, no int /). |
| 29 template <int N, typename T> | 20 template <int N, typename T> |
| 30 class SkNx { | 21 class SkNx { |
| 31 public: | 22 public: |
| 32 SkNx() {} | 23 SkNx() {} |
| 33 SkNx(const SkNx<N/2, T>& lo, const SkNx<N/2, T>& hi) : fLo(lo), fHi(hi) {} | |
| 34 SkNx(T val) : fLo(val), fHi(val) {} | 24 SkNx(T val) : fLo(val), fHi(val) {} |
| 25 |
| 26 typedef SkNx<N/2, T> Half; |
| 27 SkNx(const Half& lo, const Half& hi) : fLo(lo), fHi(hi) {} |
| 28 |
| 29 SkNx(T a, T b) : fLo(a), fHi(b) {
} |
| 30 SkNx(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) {
} |
| 31 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) {
} |
| 32 SkNx(T a, T b, T c, T d, T e, T f, T g, T h, |
| 33 T i, T j, T k, T l, T m, T n, T o, T p) : fLo(a,b,c,d, e,f,g,h), fHi(i
,j,k,l, m,n,o,p) {} |
| 34 |
| 35 static SkNx Load(const void* ptr) { | 35 static SkNx Load(const void* ptr) { |
| 36 auto vals = (const T*)ptr; | 36 auto vals = (const T*)ptr; |
| 37 return SkNx(SkNx<N/2,T>::Load(vals), SkNx<N/2,T>::Load(vals+N/2)); | 37 return SkNx(Half::Load(vals), Half::Load(vals+N/2)); |
| 38 } | 38 } |
| 39 | 39 |
| 40 SkNx(T a, T b) : fLo(a), fHi(b) {
REQUIRE(N==2); } | |
| 41 SkNx(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) {
REQUIRE(N==4); } | |
| 42 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) {
REQUIRE(N==8); } | |
| 43 SkNx(T a, T b, T c, T d, T e, T f, T g, T h, | |
| 44 T i, T j, T k, T l, T m, T n, T o, T p) | |
| 45 : fLo(a,b,c,d, e,f,g,h), fHi(i,j,k,l, m,n,o,p) { REQUIRE(N==16); } | |
| 46 | |
| 47 void store(void* ptr) const { | 40 void store(void* ptr) const { |
| 48 auto vals = (T*)ptr; | 41 auto vals = (T*)ptr; |
| 49 fLo.store(vals); | 42 fLo.store(vals); |
| 50 fHi.store(vals+N/2); | 43 fHi.store(vals+N/2); |
| 51 } | 44 } |
| 52 | 45 |
| 53 SkNx saturatedAdd(const SkNx& o) const { | 46 #define OP(op) SkNx operator op(const SkNx& o) const { return {fLo op o.fLo, fHi
op o.fHi}; } |
| 54 return SkNx(fLo.saturatedAdd(o.fLo), fHi.saturatedAdd(o.fHi)); | 47 OP(+) OP(-) OP(*) OP(/) |
| 55 } | 48 OP(&) OP(|) OP(^) |
| 49 OP(==) OP(!=) OP(<) OP(>) OP(<=) OP(>=) |
| 50 #undef OP |
| 56 | 51 |
| 57 SkNx operator + (const SkNx& o) const { return SkNx(fLo + o.fLo, fHi + o.fHi
); } | 52 #define OP(op) SkNx op() const { return {fLo.op(), fHi.op()}; } |
| 58 SkNx operator - (const SkNx& o) const { return SkNx(fLo - o.fLo, fHi - o.fHi
); } | 53 OP(abs) |
| 59 SkNx operator * (const SkNx& o) const { return SkNx(fLo * o.fLo, fHi * o.fHi
); } | 54 OP(sqrt) OP(rsqrt0) OP(rsqrt1) OP(rsqrt2) |
| 60 SkNx operator / (const SkNx& o) const { return SkNx(fLo / o.fLo, fHi / o.fHi
); } | 55 OP(invert) OP(approxInvert) |
| 56 #undef OP |
| 61 | 57 |
| 62 SkNx operator << (int bits) const { return SkNx(fLo << bits, fHi << bits); } | 58 SkNx operator << (int bits) const { return SkNx(fLo << bits, fHi << bits); } |
| 63 SkNx operator >> (int bits) const { return SkNx(fLo >> bits, fHi >> bits); } | 59 SkNx operator >> (int bits) const { return SkNx(fLo >> bits, fHi >> bits); } |
| 64 | 60 |
| 65 SkNx operator == (const SkNx& o) const { return SkNx(fLo == o.fLo, fHi == o.
fHi); } | 61 SkNx saturatedAdd(const SkNx& o) const { |
| 66 SkNx operator != (const SkNx& o) const { return SkNx(fLo != o.fLo, fHi != o.
fHi); } | 62 return {fLo.saturatedAdd(o.fLo), fHi.saturatedAdd(o.fHi)}; |
| 67 SkNx operator < (const SkNx& o) const { return SkNx(fLo < o.fLo, fHi < o.
fHi); } | 63 } |
| 68 SkNx operator > (const SkNx& o) const { return SkNx(fLo > o.fLo, fHi > o.
fHi); } | |
| 69 SkNx operator <= (const SkNx& o) const { return SkNx(fLo <= o.fLo, fHi <= o.
fHi); } | |
| 70 SkNx operator >= (const SkNx& o) const { return SkNx(fLo >= o.fLo, fHi >= o.
fHi); } | |
| 71 | 64 |
| 72 static SkNx Min(const SkNx& a, const SkNx& b) { | 65 static SkNx Min(const SkNx& a, const SkNx& b) { |
| 73 return SkNx(SkNx<N/2, T>::Min(a.fLo, b.fLo), SkNx<N/2, T>::Min(a.fHi, b.
fHi)); | 66 return {Half::Min(a.fLo, b.fLo), Half::Min(a.fHi, b.fHi)}; |
| 74 } | 67 } |
| 75 static SkNx Max(const SkNx& a, const SkNx& b) { | 68 static SkNx Max(const SkNx& a, const SkNx& b) { |
| 76 return SkNx(SkNx<N/2, T>::Max(a.fLo, b.fLo), SkNx<N/2, T>::Max(a.fHi, b.
fHi)); | 69 return {Half::Max(a.fLo, b.fLo), Half::Max(a.fHi, b.fHi)}; |
| 77 } | 70 } |
| 78 | 71 |
| 79 SkNx abs() const { return SkNx(fLo.abs(), fHi.abs()); } | 72 T operator[](int k) const { |
| 73 SkASSERT(0 <= k && k < N); |
| 74 return k < N/2 ? fLo[k] : fHi[k-N/2]; |
| 75 } |
| 80 | 76 |
| 81 SkNx sqrt() const { return SkNx(fLo.sqrt(), fHi.sqrt()); } | 77 template <int k> T kth() const { return (*this)[k]; } |
| 82 // Generally, increasing precision, increasing cost. | |
| 83 SkNx rsqrt0() const { return SkNx(fLo.rsqrt0(), fHi.rsqrt0()); } | |
| 84 SkNx rsqrt1() const { return SkNx(fLo.rsqrt1(), fHi.rsqrt1()); } | |
| 85 SkNx rsqrt2() const { return SkNx(fLo.rsqrt2(), fHi.rsqrt2()); } | |
| 86 | |
| 87 SkNx invert() const { return SkNx(fLo. invert(), fHi. invert
()); } | |
| 88 SkNx approxInvert() const { return SkNx(fLo.approxInvert(), fHi.approxInvert
()); } | |
| 89 | |
| 90 template <int k> T kth() const { | |
| 91 SkASSERT(0 <= k && k < N); | |
| 92 return k < N/2 ? fLo.template kth<k>() : fHi.template kth<k-N/2>(); | |
| 93 } | |
| 94 | 78 |
| 95 bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } | 79 bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } |
| 96 bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } | 80 bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } |
| 97 SkNx thenElse(const SkNx& t, const SkNx& e) const { | 81 SkNx thenElse(const SkNx& t, const SkNx& e) const { |
| 98 return SkNx(fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi)); | 82 return SkNx(fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi)); |
| 99 } | 83 } |
| 100 | 84 |
| 101 protected: | 85 protected: |
| 102 REQUIRE(0 == (N & (N-1))); | 86 static_assert(0 == (N & (N-1)), "N must be a power of 2."); |
| 103 | 87 |
| 104 SkNx<N/2, T> fLo, fHi; | 88 Half fLo, fHi; |
| 105 }; | 89 }; |
| 106 | 90 |
| 107 // Bottom out the default implementations with scalars when nothing's been speci
alized. | 91 // Bottom out the default implementations with scalars when nothing's been speci
alized. |
| 108 template <typename T> | 92 template <typename T> |
| 109 class SkNx<1,T> { | 93 class SkNx<1, T> { |
| 110 public: | 94 public: |
| 111 SkNx() {} | 95 SkNx() {} |
| 112 SkNx(T val) : fVal(val) {} | 96 SkNx(T val) : fVal(val) {} |
| 97 |
| 113 static SkNx Load(const void* ptr) { | 98 static SkNx Load(const void* ptr) { |
| 114 auto vals = (const T*)ptr; | 99 auto vals = (const T*)ptr; |
| 115 return SkNx(vals[0]); | 100 return SkNx(vals[0]); |
| 116 } | 101 } |
| 117 | 102 |
| 118 void store(void* ptr) const { | 103 void store(void* ptr) const { |
| 119 auto vals = (T*) ptr; | 104 auto vals = (T*) ptr; |
| 120 vals[0] = fVal; | 105 vals[0] = fVal; |
| 121 } | 106 } |
| 122 | 107 |
| 108 #define OP(op) SkNx operator op(const SkNx& o) const { return fVal op o.fVal; } |
| 109 OP(+) OP(-) OP(*) OP(/) |
| 110 OP(&) OP(|) OP(^) |
| 111 OP(==) OP(!=) OP(<) OP(>) OP(<=) OP(>=) |
| 112 #undef OP |
| 113 |
| 114 SkNx operator << (int bits) const { return fVal << bits; } |
| 115 SkNx operator >> (int bits) const { return fVal >> bits; } |
| 116 |
| 123 SkNx saturatedAdd(const SkNx& o) const { | 117 SkNx saturatedAdd(const SkNx& o) const { |
| 124 SkASSERT((T)(~0) > 0); // TODO: support signed T | 118 SkASSERT((T)(~0) > 0); // TODO: support signed T? |
| 125 T sum = fVal + o.fVal; | 119 T sum = fVal + o.fVal; |
| 126 return SkNx(sum < fVal ? (T)(~0) : sum); | 120 return sum < fVal ? (T)(~0) : sum; |
| 127 } | 121 } |
| 128 | 122 |
| 129 SkNx operator + (const SkNx& o) const { return SkNx(fVal + o.fVal); } | 123 static SkNx Min(const SkNx& a, const SkNx& b) { return SkTMin(a.fVal, b.fVal
); } |
| 130 SkNx operator - (const SkNx& o) const { return SkNx(fVal - o.fVal); } | 124 static SkNx Max(const SkNx& a, const SkNx& b) { return SkTMax(a.fVal, b.fVal
); } |
| 131 SkNx operator * (const SkNx& o) const { return SkNx(fVal * o.fVal); } | |
| 132 SkNx operator / (const SkNx& o) const { return SkNx(fVal / o.fVal); } | |
| 133 | |
| 134 SkNx operator << (int bits) const { return SkNx(fVal << bits); } | |
| 135 SkNx operator >> (int bits) const { return SkNx(fVal >> bits); } | |
| 136 | |
| 137 SkNx operator == (const SkNx& o) const { return SkNx(fVal == o.fVal); } | |
| 138 SkNx operator != (const SkNx& o) const { return SkNx(fVal != o.fVal); } | |
| 139 SkNx operator < (const SkNx& o) const { return SkNx(fVal < o.fVal); } | |
| 140 SkNx operator > (const SkNx& o) const { return SkNx(fVal > o.fVal); } | |
| 141 SkNx operator <= (const SkNx& o) const { return SkNx(fVal <= o.fVal); } | |
| 142 SkNx operator >= (const SkNx& o) const { return SkNx(fVal >= o.fVal); } | |
| 143 | |
| 144 static SkNx Min(const SkNx& a, const SkNx& b) { return SkNx(SkTMin(a.fVal, b
.fVal)); } | |
| 145 static SkNx Max(const SkNx& a, const SkNx& b) { return SkNx(SkTMax(a.fVal, b
.fVal)); } | |
| 146 | 125 |
| 147 SkNx abs() const { return SkTAbs(fVal); } | 126 SkNx abs() const { return SkTAbs(fVal); } |
| 148 | 127 |
| 149 SkNx sqrt () const { return SkNx(Sqrt(fVal)); } | 128 SkNx sqrt () const { return Sqrt(fVal); } |
| 150 SkNx rsqrt0() const { return this->sqrt().invert(); } | 129 SkNx rsqrt0() const { return this->sqrt().invert(); } |
| 151 SkNx rsqrt1() const { return this->rsqrt0(); } | 130 SkNx rsqrt1() const { return this->rsqrt0(); } |
| 152 SkNx rsqrt2() const { return this->rsqrt1(); } | 131 SkNx rsqrt2() const { return this->rsqrt1(); } |
| 153 | 132 |
| 154 SkNx invert() const { return SkNx(1) / SkNx(fVal); } | 133 SkNx invert() const { return 1 / fVal; } |
| 155 SkNx approxInvert() const { return this->invert(); } | 134 SkNx approxInvert() const { return this->invert(); } |
| 156 | 135 |
| 157 template <int k> T kth() const { | 136 T operator[](int k) const { |
| 158 SkASSERT(0 == k); | 137 SkASSERT(0 == k); |
| 159 return fVal; | 138 return fVal; |
| 160 } | 139 } |
| 161 | 140 |
| 141 template <int k> T kth() const { return (*this)[k]; } |
| 142 |
| 162 bool allTrue() const { return fVal != 0; } | 143 bool allTrue() const { return fVal != 0; } |
| 163 bool anyTrue() const { return fVal != 0; } | 144 bool anyTrue() const { return fVal != 0; } |
| 164 SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e
; } | 145 SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e
; } |
| 165 | 146 |
| 166 protected: | 147 protected: |
| 167 static double Sqrt(double val) { return ::sqrt (val); } | 148 static double Sqrt(double val) { return ::sqrt (val); } |
| 168 static float Sqrt(float val) { return ::sqrtf(val); } | 149 static float Sqrt(float val) { return ::sqrtf(val); } |
| 169 | 150 |
| 170 T fVal; | 151 T fVal; |
| 171 }; | 152 }; |
| 172 | 153 |
| 173 // This default implementation can be specialized by ../opts/SkNx_foo.h | 154 // This generic shuffle can be called to create any valid SkNx<N,T>. |
| 174 // if there's a better platform-specific shuffle strategy. | 155 // Sk4f f(a,b,c,d); |
| 175 template <typename Nx, int... Ix> | 156 // Sk2f t = SkNx_shuffle<2,1>(f); // ~~~> Sk2f(c,b) |
| 176 inline Nx SkNx_shuffle_impl(const Nx& src) { return Nx( src.template kth<Ix>()..
. ); } | 157 // f = SkNx_shuffle<0,1,1,0>(t); // ~~~> Sk4f(c,b,b,c) |
| 158 template <int... Ix, int N, typename T> |
| 159 static inline SkNx<sizeof...(Ix), T> SkNx_shuffle(const SkNx<N,T>& src) { return
{ src[Ix]... }; } |
| 177 | 160 |
| 178 // This generic shuffle can be called with 1 or N indices: | 161 // This is a generic cast between two SkNx with the same number of elements N.
E.g. |
| 179 // Sk4f f(a,b,c,d); | 162 // Sk4b bs = ...; // Load 4 bytes. |
| 180 // SkNx_shuffle<3>(f); // ~~~> Sk4f(d,d,d,d) | 163 // Sk4f fs = SkNx_cast<float>(bs); // Cast each byte to a float. |
| 181 // SkNx_shuffle<2,1,0,3>(f); // ~~~> Sk4f(c,b,a,d) | 164 // Sk4h hs = SkNx_cast<uint16_t>(fs); // Cast each float to uint16_t. |
| 182 template <int... Ix, typename Nx> | 165 template <typename D, typename S> |
| 183 inline Nx SkNx_shuffle(const Nx& src) { return SkNx_shuffle_impl<Nx, Ix...>(src)
; } | 166 static inline SkNx<2,D> SkNx_cast(const SkNx<2,S>& src) { |
| 184 | 167 return { (D)src[0], (D)src[1] }; |
| 185 // A reminder alias that shuffles can be used to duplicate a single index across
a vector. | |
| 186 template <int Ix, typename Nx> | |
| 187 inline Nx SkNx_dup(const Nx& src) { return SkNx_shuffle<Ix>(src); } | |
| 188 | |
| 189 // This is a poor-man's std::make_index_sequence from C++14. | |
| 190 // I'd implement it fully, but it hurts my head. | |
| 191 template <int...> struct SkIntSequence {}; | |
| 192 template <int N> struct MakeSkIntSequence; | |
| 193 template <> struct MakeSkIntSequence< 1> : SkIntSequence<0
>{}; | |
| 194 template <> struct MakeSkIntSequence< 2> : SkIntSequence<0,1
>{}; | |
| 195 template <> struct MakeSkIntSequence< 4> : SkIntSequence<0,1,2,3
>{}; | |
| 196 template <> struct MakeSkIntSequence< 8> : SkIntSequence<0,1,2,3,4,5,6,7
>{}; | |
| 197 template <> struct MakeSkIntSequence<16> : SkIntSequence<0,1,2,3,4,5,6,7,8,9,10,
11,12,13,14,15>{}; | |
| 198 | |
| 199 // This is the default/fallback implementation for SkNx_cast. Best to specializ
e SkNx_cast! | |
| 200 template <typename D, typename S, int N, int... Ix> | |
| 201 SkNx<N,D> SkNx_cast_fallback(const SkNx<N,S>& src, SkIntSequence<Ix...>) { | |
| 202 return SkNx<N,D>( (D)src.template kth<Ix>()... ); | |
| 203 } | 168 } |
| 204 | 169 |
| 205 // This is a generic cast between two SkNx with the same number of elements N.
E.g. | 170 template <typename D, typename S> |
| 206 // Sk4b bs = ...; // Load 4 bytes. | 171 static inline SkNx<4,D> SkNx_cast(const SkNx<4,S>& src) { |
| 207 // Sk4f fs = SkNx_cast<float>(bs); // Cast each byte to a float. | 172 return { (D)src[0], (D)src[1], (D)src[2], (D)src[3] }; |
| 208 // Sk4i is = SkNx_cast<int>(fs); // Cast each float to int. | |
| 209 // This can be specialized in ../opts/SkNx_foo.h if there's a better platform-sp
ecific cast. | |
| 210 template <typename D, typename S, int N> | |
| 211 SkNx<N,D> SkNx_cast(const SkNx<N,S>& src) { | |
| 212 return SkNx_cast_fallback<D,S,N>(src, MakeSkIntSequence<N>()); | |
| 213 } | 173 } |
| 214 | 174 |
| 215 } // namespace | 175 template <typename D, typename S> |
| 176 static inline SkNx<8,D> SkNx_cast(const SkNx<8,S>& src) { |
| 177 return { (D)src[0], (D)src[1], (D)src[2], (D)src[3], |
| 178 (D)src[4], (D)src[5], (D)src[6], (D)src[7] }; |
| 179 } |
| 216 | 180 |
| 217 typedef SkNx<2, float> Sk2f; | 181 template <typename D, typename S> |
| 218 typedef SkNx<4, float> Sk4f; | 182 static inline SkNx<16,D> SkNx_cast(const SkNx<16,S>& src) { |
| 219 typedef SkNx<8, float> Sk8f; | 183 return { (D)src[ 0], (D)src[ 1], (D)src[ 2], (D)src[ 3], |
| 184 (D)src[ 4], (D)src[ 5], (D)src[ 6], (D)src[ 7], |
| 185 (D)src[ 8], (D)src[ 9], (D)src[10], (D)src[11], |
| 186 (D)src[12], (D)src[13], (D)src[14], (D)src[15] }; |
| 187 } |
| 220 | 188 |
| 221 typedef SkNx<2, double> Sk2d; | 189 typedef SkNx<2, float> Sk2f; |
| 222 typedef SkNx<4, double> Sk4d; | 190 typedef SkNx<4, float> Sk4f; |
| 223 typedef SkNx<8, double> Sk8d; | 191 typedef SkNx<2, SkScalar> Sk2s; |
| 192 typedef SkNx<4, SkScalar> Sk4s; |
| 224 | 193 |
| 225 typedef SkNx<2, SkScalar> Sk2s; | 194 typedef SkNx<4, uint8_t> Sk4b; |
| 226 typedef SkNx<4, SkScalar> Sk4s; | 195 typedef SkNx<16, uint8_t> Sk16b; |
| 227 typedef SkNx<8, SkScalar> Sk8s; | 196 typedef SkNx<4, uint16_t> Sk4h; |
| 228 | |
| 229 typedef SkNx< 4, uint16_t> Sk4h; | |
| 230 typedef SkNx< 8, uint16_t> Sk8h; | |
| 231 typedef SkNx<16, uint16_t> Sk16h; | 197 typedef SkNx<16, uint16_t> Sk16h; |
| 232 | 198 |
| 233 typedef SkNx< 4, uint8_t> Sk4b; | |
| 234 typedef SkNx< 8, uint8_t> Sk8b; | |
| 235 typedef SkNx<16, uint8_t> Sk16b; | |
| 236 | |
| 237 typedef SkNx<4, int> Sk4i; | |
| 238 | |
| 239 // Include platform specific specializations if available. | 199 // Include platform specific specializations if available. |
| 240 #if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 | 200 #if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
| 241 #include "../opts/SkNx_sse.h" | 201 #include "../opts/SkNx_sse.h" |
| 242 #elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) | 202 #elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) |
| 243 #include "../opts/SkNx_neon.h" | 203 #include "../opts/SkNx_neon.h" |
| 244 #else | 204 #else |
| 245 static inline | 205 static inline |
| 246 void Sk4f_ToBytes(uint8_t p[16], const Sk4f& a, const Sk4f& b, const Sk4f& c
, const Sk4f& d) { | 206 void Sk4f_ToBytes(uint8_t p[16], const Sk4f& a, const Sk4f& b, const Sk4f& c
, const Sk4f& d) { |
| 247 SkNx_cast<uint8_t>(a).store(p+ 0); | 207 SkNx_cast<uint8_t>(a).store(p+ 0); |
| 248 SkNx_cast<uint8_t>(b).store(p+ 4); | 208 SkNx_cast<uint8_t>(b).store(p+ 4); |
| 249 SkNx_cast<uint8_t>(c).store(p+ 8); | 209 SkNx_cast<uint8_t>(c).store(p+ 8); |
| 250 SkNx_cast<uint8_t>(d).store(p+12); | 210 SkNx_cast<uint8_t>(d).store(p+12); |
| 251 } | 211 } |
| 252 #endif | 212 #endif |
| 253 | 213 |
| 254 #undef REQUIRE | |
| 255 | |
| 256 | |
| 257 #endif//SkNx_DEFINED | 214 #endif//SkNx_DEFINED |
| OLD | NEW |