Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: src/core/SkNx.h

Issue 1683543002: sknx refactoring (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: typos Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkColorMatrixFilterRowMajor255.cpp ('k') | src/opts/SkNx_neon.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
OLDNEW
« no previous file with comments | « src/core/SkColorMatrixFilterRowMajor255.cpp ('k') | src/opts/SkNx_neon.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698