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 |