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 //#define SKNX_NO_SIMD | 11 //#define SKNX_NO_SIMD |
12 | 12 |
13 #include "SkScalar.h" | 13 #include "SkScalar.h" |
14 #include "SkTypes.h" | 14 #include "SkTypes.h" |
| 15 #include <limits> |
15 #include <math.h> | 16 #include <math.h> |
| 17 #include <type_traits> |
16 | 18 |
17 // The default implementations just fall back on a pair of size N/2. | 19 #define SI static inline |
18 // These support the union of operations we might do to ints and floats, but | 20 |
19 // platform specializations might support fewer (e.g. no float <<, no int /). | 21 // The default SkNx<N,T> just proxies down to a pair of SkNx<N/2, T>. |
20 template <int N, typename T> | 22 template <int N, typename T> |
21 class SkNx { | 23 struct SkNx { |
22 public: | 24 typedef SkNx<N/2, T> Half; |
23 SkNx() {} | |
24 SkNx(T val) : fLo(val), fHi(val) {} | |
25 | 25 |
26 typedef SkNx<N/2, T> Half; | 26 Half fLo, fHi; |
| 27 |
| 28 SkNx() = default; |
27 SkNx(const Half& lo, const Half& hi) : fLo(lo), fHi(hi) {} | 29 SkNx(const Half& lo, const Half& hi) : fLo(lo), fHi(hi) {} |
28 | 30 |
29 SkNx(T a, T b) : fLo(a), fHi(b) {
} | 31 SkNx(T v) : fLo(v), fHi(v) {} |
30 SkNx(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) {
} | 32 |
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) {
} | 33 SkNx(T a, T b) : fLo(a) , fHi(b) { static_assert(N==2, ""); } |
| 34 SkNx(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) { static_assert(N==4, ""); } |
| 35 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) { |
| 36 static_assert(N==8, ""); |
| 37 } |
32 SkNx(T a, T b, T c, T d, T e, T f, T g, T h, | 38 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) {} | 39 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 | 40 static_assert(N==16, ""); |
35 static SkNx Load(const void* ptr) { | |
36 auto vals = (const T*)ptr; | |
37 return SkNx(Half::Load(vals), Half::Load(vals+N/2)); | |
38 } | |
39 | |
40 void store(void* ptr) const { | |
41 auto vals = (T*)ptr; | |
42 fLo.store(vals); | |
43 fHi.store(vals+N/2); | |
44 } | |
45 | |
46 #define OP(op) SkNx operator op(const SkNx& o) const { return {fLo op o.fLo, fHi
op o.fHi}; } | |
47 OP(+) OP(-) OP(*) OP(/) | |
48 OP(&) OP(|) OP(^) | |
49 OP(==) OP(!=) OP(<) OP(>) OP(<=) OP(>=) | |
50 #undef OP | |
51 | |
52 #define OP(op) SkNx op() const { return {fLo.op(), fHi.op()}; } | |
53 OP(abs) OP(floor) | |
54 OP(sqrt) OP(rsqrt0) OP(rsqrt1) OP(rsqrt2) | |
55 OP(invert) OP(approxInvert) | |
56 #undef OP | |
57 | |
58 SkNx operator << (int bits) const { return SkNx(fLo << bits, fHi << bits); } | |
59 SkNx operator >> (int bits) const { return SkNx(fLo >> bits, fHi >> bits); } | |
60 | |
61 SkNx saturatedAdd(const SkNx& o) const { | |
62 return {fLo.saturatedAdd(o.fLo), fHi.saturatedAdd(o.fHi)}; | |
63 } | |
64 | |
65 static SkNx Min(const SkNx& a, const SkNx& b) { | |
66 return {Half::Min(a.fLo, b.fLo), Half::Min(a.fHi, b.fHi)}; | |
67 } | |
68 static SkNx Max(const SkNx& a, const SkNx& b) { | |
69 return {Half::Max(a.fLo, b.fLo), Half::Max(a.fHi, b.fHi)}; | |
70 } | 41 } |
71 | 42 |
72 T operator[](int k) const { | 43 T operator[](int k) const { |
73 SkASSERT(0 <= k && k < N); | 44 SkASSERT(0 <= k && k < N); |
74 return k < N/2 ? fLo[k] : fHi[k-N/2]; | 45 return k < N/2 ? fLo[k] : fHi[k-N/2]; |
75 } | 46 } |
76 | 47 |
| 48 static SkNx Load(const void* vptr) { |
| 49 auto ptr = (const char*)vptr; |
| 50 return { Half::Load(ptr), Half::Load(ptr + N/2*sizeof(T)) }; |
| 51 } |
| 52 void store(void* vptr) const { |
| 53 auto ptr = (char*)vptr; |
| 54 fLo.store(ptr); |
| 55 fHi.store(ptr + N/2*sizeof(T)); |
| 56 } |
| 57 |
| 58 bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } |
77 bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } | 59 bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } |
78 bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } | 60 |
| 61 SkNx abs() const { return { fLo. abs(), fHi. abs() }; } |
| 62 SkNx sqrt() const { return { fLo. sqrt(), fHi. sqrt() }; } |
| 63 SkNx rsqrt() const { return { fLo. rsqrt(), fHi. rsqrt() }; } |
| 64 SkNx floor() const { return { fLo. floor(), fHi. floor() }; } |
| 65 SkNx invert() const { return { fLo.invert(), fHi.invert() }; } |
| 66 |
| 67 SkNx operator!() const { return { !fLo, !fHi }; } |
| 68 SkNx operator-() const { return { -fLo, -fHi }; } |
| 69 SkNx operator~() const { return { ~fLo, ~fHi }; } |
| 70 |
| 71 SkNx operator<<(int bits) const { return { fLo << bits, fHi << bits }; } |
| 72 SkNx operator>>(int bits) const { return { fLo >> bits, fHi >> bits }; } |
| 73 |
| 74 SkNx operator+(const SkNx& y) const { return { fLo + y.fLo, fHi + y.fHi }; } |
| 75 SkNx operator-(const SkNx& y) const { return { fLo - y.fLo, fHi - y.fHi }; } |
| 76 SkNx operator*(const SkNx& y) const { return { fLo * y.fLo, fHi * y.fHi }; } |
| 77 SkNx operator/(const SkNx& y) const { return { fLo / y.fLo, fHi / y.fHi }; } |
| 78 |
| 79 SkNx operator&(const SkNx& y) const { return { fLo & y.fLo, fHi & y.fHi }; } |
| 80 SkNx operator|(const SkNx& y) const { return { fLo | y.fLo, fHi | y.fHi }; } |
| 81 SkNx operator^(const SkNx& y) const { return { fLo ^ y.fLo, fHi ^ y.fHi }; } |
| 82 |
| 83 SkNx operator==(const SkNx& y) const { return { fLo == y.fLo, fHi == y.fHi }
; } |
| 84 SkNx operator!=(const SkNx& y) const { return { fLo != y.fLo, fHi != y.fHi }
; } |
| 85 SkNx operator<=(const SkNx& y) const { return { fLo <= y.fLo, fHi <= y.fHi }
; } |
| 86 SkNx operator>=(const SkNx& y) const { return { fLo >= y.fLo, fHi >= y.fHi }
; } |
| 87 SkNx operator< (const SkNx& y) const { return { fLo < y.fLo, fHi < y.fHi }
; } |
| 88 SkNx operator> (const SkNx& y) const { return { fLo > y.fLo, fHi > y.fHi }
; } |
| 89 |
| 90 SkNx saturatedAdd(const SkNx& y) const { |
| 91 return { fLo.saturatedAdd(y.fLo), fHi.saturatedAdd(y.fHi) }; |
| 92 } |
79 SkNx thenElse(const SkNx& t, const SkNx& e) const { | 93 SkNx thenElse(const SkNx& t, const SkNx& e) const { |
80 return SkNx(fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi)); | 94 return { fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi) }; |
81 } | 95 } |
82 | 96 |
83 protected: | 97 static SkNx Min(const SkNx& x, const SkNx& y) { |
84 static_assert(0 == (N & (N-1)), "N must be a power of 2."); | 98 return { Half::Min(x.fLo, y.fLo), Half::Min(x.fHi, y.fHi) }; |
85 | 99 } |
86 Half fLo, fHi; | 100 static SkNx Max(const SkNx& x, const SkNx& y) { |
| 101 return { Half::Max(x.fLo, y.fLo), Half::Max(x.fHi, y.fHi) }; |
| 102 } |
87 }; | 103 }; |
88 | 104 |
89 // Bottom out the default implementations with scalars when nothing's been speci
alized. | 105 // The N -> N/2 recursion bottoms out at N == 1, a scalar value. |
90 template <typename T> | 106 template <typename T> |
91 class SkNx<1, T> { | 107 struct SkNx<1,T> { |
92 public: | 108 T fVal; |
93 SkNx() {} | 109 |
94 SkNx(T val) : fVal(val) {} | 110 SkNx() = default; |
| 111 SkNx(T v) : fVal(v) {} |
| 112 |
| 113 T operator[](int k) const { |
| 114 SkASSERT(k == 0); |
| 115 return fVal; |
| 116 } |
95 | 117 |
96 static SkNx Load(const void* ptr) { | 118 static SkNx Load(const void* ptr) { |
97 auto vals = (const T*)ptr; | 119 SkNx v; |
98 return SkNx(vals[0]); | 120 memcpy(&v, ptr, sizeof(T)); |
99 } | 121 return v; |
100 | 122 } |
101 void store(void* ptr) const { | 123 void store(void* ptr) const { memcpy(ptr, &fVal, sizeof(T)); } |
102 auto vals = (T*) ptr; | 124 |
103 vals[0] = fVal; | 125 bool anyTrue() const { return fVal != 0; } |
104 } | |
105 | |
106 #define OP(op) SkNx operator op(const SkNx& o) const { return fVal op o.fVal; } | |
107 OP(+) OP(-) OP(*) OP(/) | |
108 OP(&) OP(|) OP(^) | |
109 OP(==) OP(!=) OP(<) OP(>) OP(<=) OP(>=) | |
110 #undef OP | |
111 | |
112 SkNx operator << (int bits) const { return fVal << bits; } | |
113 SkNx operator >> (int bits) const { return fVal >> bits; } | |
114 | |
115 SkNx saturatedAdd(const SkNx& o) const { | |
116 SkASSERT((T)(~0) > 0); // TODO: support signed T? | |
117 T sum = fVal + o.fVal; | |
118 return sum < fVal ? (T)(~0) : sum; | |
119 } | |
120 | |
121 static SkNx Min(const SkNx& a, const SkNx& b) { return SkTMin(a.fVal, b.fVal
); } | |
122 static SkNx Max(const SkNx& a, const SkNx& b) { return SkTMax(a.fVal, b.fVal
); } | |
123 | |
124 SkNx abs() const { return SkTAbs(fVal); } | |
125 SkNx floor() const { return Floor(fVal); } | |
126 | |
127 SkNx sqrt () const { return Sqrt(fVal); } | |
128 SkNx rsqrt0() const { return this->sqrt().invert(); } | |
129 SkNx rsqrt1() const { return this->rsqrt0(); } | |
130 SkNx rsqrt2() const { return this->rsqrt1(); } | |
131 | |
132 SkNx invert() const { return 1 / fVal; } | |
133 SkNx approxInvert() const { return this->invert(); } | |
134 | |
135 T operator[](int k) const { | |
136 SkASSERT(0 == k); | |
137 return fVal; | |
138 } | |
139 | |
140 bool allTrue() const { return fVal != 0; } | 126 bool allTrue() const { return fVal != 0; } |
141 bool anyTrue() const { return fVal != 0; } | 127 |
| 128 SkNx abs() const { return Abs(fVal); } |
| 129 SkNx sqrt() const { return Sqrt(fVal); } |
| 130 SkNx rsqrt() const { return T(1) / this->sqrt(); } |
| 131 SkNx floor() const { return Floor(fVal); } |
| 132 SkNx invert() const { return T(1) / *this; } |
| 133 |
| 134 SkNx operator!() const { return !fVal; } |
| 135 SkNx operator-() const { return -fVal; } |
| 136 SkNx operator~() const { return FromBits(~ToBits(fVal)); } |
| 137 |
| 138 SkNx operator<<(int bits) const { return fVal << bits; } |
| 139 SkNx operator>>(int bits) const { return fVal >> bits; } |
| 140 |
| 141 SkNx operator+(const SkNx& y) const { return fVal + y.fVal; } |
| 142 SkNx operator-(const SkNx& y) const { return fVal - y.fVal; } |
| 143 SkNx operator*(const SkNx& y) const { return fVal * y.fVal; } |
| 144 SkNx operator/(const SkNx& y) const { return fVal / y.fVal; } |
| 145 |
| 146 SkNx operator&(const SkNx& y) const { return FromBits(ToBits(fVal) & ToBits(
y.fVal)); } |
| 147 SkNx operator|(const SkNx& y) const { return FromBits(ToBits(fVal) | ToBits(
y.fVal)); } |
| 148 SkNx operator^(const SkNx& y) const { return FromBits(ToBits(fVal) ^ ToBits(
y.fVal)); } |
| 149 |
| 150 SkNx operator==(const SkNx& y) const { return FromBits(fVal == y.fVal ? ~0 :
0); } |
| 151 SkNx operator!=(const SkNx& y) const { return FromBits(fVal != y.fVal ? ~0 :
0); } |
| 152 SkNx operator<=(const SkNx& y) const { return FromBits(fVal <= y.fVal ? ~0 :
0); } |
| 153 SkNx operator>=(const SkNx& y) const { return FromBits(fVal >= y.fVal ? ~0 :
0); } |
| 154 SkNx operator< (const SkNx& y) const { return FromBits(fVal < y.fVal ? ~0 :
0); } |
| 155 SkNx operator> (const SkNx& y) const { return FromBits(fVal > y.fVal ? ~0 :
0); } |
| 156 |
| 157 static SkNx Min(const SkNx& x, const SkNx& y) { return x.fVal < y.fVal ? x :
y; } |
| 158 static SkNx Max(const SkNx& x, const SkNx& y) { return x.fVal > y.fVal ? x :
y; } |
| 159 |
| 160 SkNx saturatedAdd(const SkNx& y) const { |
| 161 static_assert(std::is_unsigned<T>::value, ""); |
| 162 T sum = fVal + y.fVal; |
| 163 return sum < fVal ? std::numeric_limits<T>::max() : sum; |
| 164 } |
| 165 |
142 SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e
; } | 166 SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e
; } |
143 | 167 |
144 protected: | 168 private: |
145 static double Floor(double val) { return ::floor (val); } | 169 // Helper functions to choose the right float/double methods. (In <cmath> m
adness lies...) |
146 static float Floor(float val) { return ::floorf(val); } | 170 static float Abs(float val) { return ::fabsf(val); } |
147 static double Sqrt(double val) { return ::sqrt (val); } | 171 static float Sqrt(float val) { return ::sqrtf(val); } |
148 static float Sqrt(float val) { return ::sqrtf(val); } | 172 static float Floor(float val) { return ::floorf(val); } |
149 | 173 |
150 T fVal; | 174 static double Abs(double val) { return ::fabs(val); } |
| 175 static double Sqrt(double val) { return ::sqrt(val); } |
| 176 static double Floor(double val) { return ::floor(val); } |
| 177 |
| 178 // Helper functions for working with floats/doubles as bit patterns. |
| 179 template <typename U> static U ToBits(U v) { return v; } |
| 180 static int32_t ToBits(float v) { int32_t bits; memcpy(&bits, &v, sizeof(v))
; return bits; } |
| 181 static int64_t ToBits(double v) { int64_t bits; memcpy(&bits, &v, sizeof(v))
; return bits; } |
| 182 |
| 183 template <typename Bits> static T FromBits(Bits bits) { |
| 184 static_assert(std::is_pod<T >::value && |
| 185 std::is_pod<Bits>::value && |
| 186 sizeof(T) <= sizeof(Bits), ""); |
| 187 T val; |
| 188 memcpy(&val, &bits, sizeof(T)); |
| 189 return val; |
| 190 } |
151 }; | 191 }; |
152 | 192 |
153 // This generic shuffle can be called to create any valid SkNx<N,T>. | 193 // Allow scalars on the left or right of binary operators, and things like +=, &
=, etc. |
154 // Sk4f f(a,b,c,d); | 194 #define V template <int N, typename T> SI SkNx<N,T> |
155 // Sk2f t = SkNx_shuffle<2,1>(f); // ~~~> Sk2f(c,b) | 195 V operator+ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) + y; } |
156 // f = SkNx_shuffle<0,1,1,0>(t); // ~~~> Sk4f(c,b,b,c) | 196 V operator- (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) - y; } |
| 197 V operator* (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) * y; } |
| 198 V operator/ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) / y; } |
| 199 V operator& (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) & y; } |
| 200 V operator| (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) | y; } |
| 201 V operator^ (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) ^ y; } |
| 202 V operator==(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) == y; } |
| 203 V operator!=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) != y; } |
| 204 V operator<=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) <= y; } |
| 205 V operator>=(T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) >= y; } |
| 206 V operator< (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) < y; } |
| 207 V operator> (T x, const SkNx<N,T>& y) { return SkNx<N,T>(x) > y; } |
| 208 |
| 209 V operator+ (const SkNx<N,T>& x, T y) { return x + SkNx<N,T>(y); } |
| 210 V operator- (const SkNx<N,T>& x, T y) { return x - SkNx<N,T>(y); } |
| 211 V operator* (const SkNx<N,T>& x, T y) { return x * SkNx<N,T>(y); } |
| 212 V operator/ (const SkNx<N,T>& x, T y) { return x / SkNx<N,T>(y); } |
| 213 V operator& (const SkNx<N,T>& x, T y) { return x & SkNx<N,T>(y); } |
| 214 V operator| (const SkNx<N,T>& x, T y) { return x | SkNx<N,T>(y); } |
| 215 V operator^ (const SkNx<N,T>& x, T y) { return x ^ SkNx<N,T>(y); } |
| 216 V operator==(const SkNx<N,T>& x, T y) { return x == SkNx<N,T>(y); } |
| 217 V operator!=(const SkNx<N,T>& x, T y) { return x != SkNx<N,T>(y); } |
| 218 V operator<=(const SkNx<N,T>& x, T y) { return x <= SkNx<N,T>(y); } |
| 219 V operator>=(const SkNx<N,T>& x, T y) { return x >= SkNx<N,T>(y); } |
| 220 V operator< (const SkNx<N,T>& x, T y) { return x < SkNx<N,T>(y); } |
| 221 V operator> (const SkNx<N,T>& x, T y) { return x > SkNx<N,T>(y); } |
| 222 |
| 223 V& operator<<=(SkNx<N,T>& x, int bits) { return (x = x << bits); } |
| 224 V& operator>>=(SkNx<N,T>& x, int bits) { return (x = x >> bits); } |
| 225 |
| 226 V& operator +=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x + y); } |
| 227 V& operator -=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x - y); } |
| 228 V& operator *=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x * y); } |
| 229 V& operator /=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x / y); } |
| 230 V& operator &=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x & y); } |
| 231 V& operator |=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x | y); } |
| 232 V& operator ^=(SkNx<N,T>& x, const SkNx<N,T>& y) { return (x = x ^ y); } |
| 233 |
| 234 V& operator +=(SkNx<N,T>& x, T y) { return (x = x + SkNx<N,T>(y)); } |
| 235 V& operator -=(SkNx<N,T>& x, T y) { return (x = x - SkNx<N,T>(y)); } |
| 236 V& operator *=(SkNx<N,T>& x, T y) { return (x = x * SkNx<N,T>(y)); } |
| 237 V& operator /=(SkNx<N,T>& x, T y) { return (x = x / SkNx<N,T>(y)); } |
| 238 V& operator &=(SkNx<N,T>& x, T y) { return (x = x & SkNx<N,T>(y)); } |
| 239 V& operator |=(SkNx<N,T>& x, T y) { return (x = x | SkNx<N,T>(y)); } |
| 240 V& operator ^=(SkNx<N,T>& x, T y) { return (x = x ^ SkNx<N,T>(y)); } |
| 241 #undef V |
| 242 |
| 243 // SkNx<N,T> ~~> SkNx<N/2,T> + SkNx<N/2,T> |
| 244 template <int N, typename T> |
| 245 SI void SkNx_split(const SkNx<N,T>& v, SkNx<N/2,T>* lo, SkNx<N/2,T>* hi) { |
| 246 *lo = v.fLo; |
| 247 *hi = v.fHi; |
| 248 } |
| 249 |
| 250 // SkNx<N/2,T> + SkNx<N/2,T> ~~> SkNx<N,T> |
| 251 template <int N, typename T> |
| 252 SI SkNx<N*2,T> SkNx_join(const SkNx<N,T>& lo, const SkNx<N,T>& hi) { |
| 253 return { lo, hi }; |
| 254 } |
| 255 |
| 256 // A very generic shuffle. Can reorder, duplicate, contract, expand... |
| 257 // Sk4f v = { R,G,B,A }; |
| 258 // SkNx_shuffle<2,1,0,3>(v) ~~> {B,G,R,A} |
| 259 // SkNx_shuffle<2,1>(v) ~~> {B,G} |
| 260 // SkNx_shuffle<2,1,2,1,2,1,2,1>(v) ~~> {B,G,B,G,B,G,B,G} |
| 261 // SkNx_shuffle<3,3,3,3>(v) ~~> {A,A,A,A} |
157 template <int... Ix, int N, typename T> | 262 template <int... Ix, int N, typename T> |
158 static inline SkNx<sizeof...(Ix), T> SkNx_shuffle(const SkNx<N,T>& src) { return
{ src[Ix]... }; } | 263 SI SkNx<sizeof...(Ix),T> SkNx_shuffle(const SkNx<N,T>& v) { |
159 | 264 return { v[Ix]... }; |
160 // This is a generic cast between two SkNx with the same number of elements N.
E.g. | 265 } |
161 // Sk4b bs = ...; // Load 4 bytes. | 266 |
162 // Sk4f fs = SkNx_cast<float>(bs); // Cast each byte to a float. | 267 // Cast from SkNx<N, Src> to SkNx<N, Dst>, as if you called static_cast<Dst>(Src
). |
163 // Sk4h hs = SkNx_cast<uint16_t>(fs); // Cast each float to uint16_t. | 268 template <typename Dst, typename Src, int N> |
164 template <typename D, typename S> | 269 SI SkNx<N,Dst> SkNx_cast(const SkNx<N,Src>& v) { |
165 static inline SkNx<2,D> SkNx_cast(const SkNx<2,S>& src) { | 270 return { SkNx_cast<Dst>(v.fLo), SkNx_cast<Dst>(v.fHi) }; |
166 return { (D)src[0], (D)src[1] }; | 271 } |
167 } | 272 template <typename Dst, typename Src> |
168 | 273 SI SkNx<1,Dst> SkNx_cast(const SkNx<1,Src>& v) { |
169 template <typename D, typename S> | 274 return static_cast<Dst>(v.fVal); |
170 static inline SkNx<4,D> SkNx_cast(const SkNx<4,S>& src) { | |
171 return { (D)src[0], (D)src[1], (D)src[2], (D)src[3] }; | |
172 } | |
173 | |
174 template <typename D, typename S> | |
175 static inline SkNx<8,D> SkNx_cast(const SkNx<8,S>& src) { | |
176 return { (D)src[0], (D)src[1], (D)src[2], (D)src[3], | |
177 (D)src[4], (D)src[5], (D)src[6], (D)src[7] }; | |
178 } | |
179 | |
180 template <typename D, typename S> | |
181 static inline SkNx<16,D> SkNx_cast(const SkNx<16,S>& src) { | |
182 return { (D)src[ 0], (D)src[ 1], (D)src[ 2], (D)src[ 3], | |
183 (D)src[ 4], (D)src[ 5], (D)src[ 6], (D)src[ 7], | |
184 (D)src[ 8], (D)src[ 9], (D)src[10], (D)src[11], | |
185 (D)src[12], (D)src[13], (D)src[14], (D)src[15] }; | |
186 } | 275 } |
187 | 276 |
188 typedef SkNx<2, float> Sk2f; | 277 typedef SkNx<2, float> Sk2f; |
189 typedef SkNx<4, float> Sk4f; | 278 typedef SkNx<4, float> Sk4f; |
| 279 typedef SkNx<8, float> Sk8f; |
| 280 typedef SkNx<16, float> Sk16f; |
| 281 |
190 typedef SkNx<2, SkScalar> Sk2s; | 282 typedef SkNx<2, SkScalar> Sk2s; |
191 typedef SkNx<4, SkScalar> Sk4s; | 283 typedef SkNx<4, SkScalar> Sk4s; |
| 284 typedef SkNx<8, SkScalar> Sk8s; |
| 285 typedef SkNx<16, SkScalar> Sk16s; |
192 | 286 |
193 typedef SkNx<4, uint8_t> Sk4b; | 287 typedef SkNx<4, uint8_t> Sk4b; |
| 288 typedef SkNx<8, uint8_t> Sk8b; |
194 typedef SkNx<16, uint8_t> Sk16b; | 289 typedef SkNx<16, uint8_t> Sk16b; |
| 290 |
195 typedef SkNx<4, uint16_t> Sk4h; | 291 typedef SkNx<4, uint16_t> Sk4h; |
| 292 typedef SkNx<8, uint16_t> Sk8h; |
196 typedef SkNx<16, uint16_t> Sk16h; | 293 typedef SkNx<16, uint16_t> Sk16h; |
| 294 |
197 typedef SkNx<4, int> Sk4i; | 295 typedef SkNx<4, int> Sk4i; |
198 | 296 |
199 typedef SkNx<4, int> Sk4i; | |
200 | |
201 // Include platform specific specializations if available. | 297 // Include platform specific specializations if available. |
202 #if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 | 298 #if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
203 #include "../opts/SkNx_sse.h" | 299 #include "../opts/SkNx_sse.h" |
204 #elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) | 300 #elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) |
205 #include "../opts/SkNx_neon.h" | 301 #include "../opts/SkNx_neon.h" |
206 #else | |
207 static inline | |
208 void Sk4f_ToBytes(uint8_t p[16], const Sk4f& a, const Sk4f& b, const Sk4f& c
, const Sk4f& d) { | |
209 SkNx_cast<uint8_t>(a).store(p+ 0); | |
210 SkNx_cast<uint8_t>(b).store(p+ 4); | |
211 SkNx_cast<uint8_t>(c).store(p+ 8); | |
212 SkNx_cast<uint8_t>(d).store(p+12); | |
213 } | |
214 #endif | 302 #endif |
215 | 303 |
| 304 SI void Sk4f_ToBytes(uint8_t p[16], const Sk4f& a, const Sk4f& b, const Sk4f& c,
const Sk4f& d) { |
| 305 SkNx_cast<uint8_t>(SkNx_join(SkNx_join(a,b), SkNx_join(c,d))).store(p); |
| 306 } |
| 307 |
| 308 #undef SI |
| 309 |
216 #endif//SkNx_DEFINED | 310 #endif//SkNx_DEFINED |
OLD | NEW |