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 Sk4pxXfermode_DEFINED | 8 #ifndef Sk4pxXfermode_DEFINED |
9 #define Sk4pxXfermode_DEFINED | 9 #define Sk4pxXfermode_DEFINED |
10 | 10 |
11 #include "Sk4px.h" | 11 #include "Sk4px.h" |
12 #include "SkNx.h" | 12 #include "SkNx.h" |
13 #include "SkXfermode_proccoeff.h" | 13 #include "SkXfermode_proccoeff.h" |
14 | 14 |
15 namespace { | 15 namespace { |
16 | 16 |
17 // Most xfermodes can be done most efficiently 4 pixels at a time in 8 or 16-bit
fixed point. | 17 // Most xfermodes can be done most efficiently 4 pixels at a time in 8 or 16-bit
fixed point. |
18 #define XFERMODE(Name) static Sk4px SK_VECTORCALL Name(Sk4px s, Sk4px d) | 18 #define XFERMODE(Xfermode) \ |
| 19 struct Xfermode { Sk4px operator()(const Sk4px&, const Sk4px&) const; }; \ |
| 20 inline Sk4px Xfermode::operator()(const Sk4px& s, const Sk4px& d) const |
19 | 21 |
20 XFERMODE(Clear) { return Sk4px::DupPMColor(0); } | 22 XFERMODE(Clear) { return Sk4px::DupPMColor(0); } |
21 XFERMODE(Src) { return s; } | 23 XFERMODE(Src) { return s; } |
22 XFERMODE(Dst) { return d; } | 24 XFERMODE(Dst) { return d; } |
23 XFERMODE(SrcIn) { return s.approxMulDiv255(d.alphas() ); } | 25 XFERMODE(SrcIn) { return s.approxMulDiv255(d.alphas() ); } |
24 XFERMODE(SrcOut) { return s.approxMulDiv255(d.alphas().inv()); } | 26 XFERMODE(SrcOut) { return s.approxMulDiv255(d.alphas().inv()); } |
25 XFERMODE(SrcOver) { return s + d.approxMulDiv255(s.alphas().inv()); } | 27 XFERMODE(SrcOver) { return s + d.approxMulDiv255(s.alphas().inv()); } |
26 XFERMODE(DstIn) { return SrcIn (d,s); } | 28 XFERMODE(DstIn) { return SrcIn ()(d,s); } |
27 XFERMODE(DstOut) { return SrcOut (d,s); } | 29 XFERMODE(DstOut) { return SrcOut ()(d,s); } |
28 XFERMODE(DstOver) { return SrcOver(d,s); } | 30 XFERMODE(DstOver) { return SrcOver()(d,s); } |
29 | 31 |
30 // [ S * Da + (1 - Sa) * D] | 32 // [ S * Da + (1 - Sa) * D] |
31 XFERMODE(SrcATop) { return (s * d.alphas() + d * s.alphas().inv()).div255(); } | 33 XFERMODE(SrcATop) { return (s * d.alphas() + d * s.alphas().inv()).div255(); } |
32 XFERMODE(DstATop) { return SrcATop(d,s); } | 34 XFERMODE(DstATop) { return SrcATop()(d,s); } |
33 //[ S * (1 - Da) + (1 - Sa) * D ] | 35 //[ S * (1 - Da) + (1 - Sa) * D ] |
34 XFERMODE(Xor) { return (s * d.alphas().inv() + d * s.alphas().inv()).div255(); } | 36 XFERMODE(Xor) { return (s * d.alphas().inv() + d * s.alphas().inv()).div255(); } |
35 // [S + D ] | 37 // [S + D ] |
36 XFERMODE(Plus) { return s.saturatedAdd(d); } | 38 XFERMODE(Plus) { return s.saturatedAdd(d); } |
37 // [S * D ] | 39 // [S * D ] |
38 XFERMODE(Modulate) { return s.approxMulDiv255(d); } | 40 XFERMODE(Modulate) { return s.approxMulDiv255(d); } |
39 // [S + D - S * D] | 41 // [S + D - S * D] |
40 XFERMODE(Screen) { | 42 XFERMODE(Screen) { |
41 // Doing the math as S + (1-S)*D or S + (D - S*D) means the add and subtract
can be done | 43 // Doing the math as S + (1-S)*D or S + (D - S*D) means the add and subtract
can be done |
42 // in 8-bit space without overflow. S + (1-S)*D is a touch faster because i
nv() is cheap. | 44 // in 8-bit space without overflow. S + (1-S)*D is a touch faster because i
nv() is cheap. |
(...skipping 29 matching lines...) Expand all Loading... |
72 auto isLite = ((sa-s) < s).widenLoHi(); | 74 auto isLite = ((sa-s) < s).widenLoHi(); |
73 | 75 |
74 auto lite = sa*da - ((da-d)*(sa-s) << 1), | 76 auto lite = sa*da - ((da-d)*(sa-s) << 1), |
75 dark = s*d << 1, | 77 dark = s*d << 1, |
76 both = s*da.inv() + d*sa.inv(); | 78 both = s*da.inv() + d*sa.inv(); |
77 | 79 |
78 auto alphas = srcover; | 80 auto alphas = srcover; |
79 auto colors = (both + isLite.thenElse(lite, dark)).div255(); | 81 auto colors = (both + isLite.thenElse(lite, dark)).div255(); |
80 return alphas.zeroColors() + colors.zeroAlphas(); | 82 return alphas.zeroColors() + colors.zeroAlphas(); |
81 } | 83 } |
82 XFERMODE(Overlay) { return HardLight(d,s); } | 84 XFERMODE(Overlay) { return HardLight()(d,s); } |
83 | 85 |
84 XFERMODE(Darken) { | 86 XFERMODE(Darken) { |
85 auto sa = s.alphas(), | 87 auto sa = s.alphas(), |
86 da = d.alphas(); | 88 da = d.alphas(); |
87 | 89 |
88 auto sda = (s*da).div255(), | 90 auto sda = (s*da).div255(), |
89 dsa = (d*sa).div255(); | 91 dsa = (d*sa).div255(); |
90 | 92 |
91 auto srcover = s + (d * sa.inv()).div255(), | 93 auto srcover = s + (d * sa.inv()).div255(), |
92 dstover = d + (s * da.inv()).div255(); | 94 dstover = d + (s * da.inv()).div255(); |
(...skipping 10 matching lines...) Expand all Loading... |
103 | 105 |
104 auto srcover = s + (d * sa.inv()).div255(), | 106 auto srcover = s + (d * sa.inv()).div255(), |
105 dstover = d + (s * da.inv()).div255(); | 107 dstover = d + (s * da.inv()).div255(); |
106 auto alphas = srcover, | 108 auto alphas = srcover, |
107 colors = (dsa < sda).thenElse(srcover, dstover); | 109 colors = (dsa < sda).thenElse(srcover, dstover); |
108 return alphas.zeroColors() + colors.zeroAlphas(); | 110 return alphas.zeroColors() + colors.zeroAlphas(); |
109 } | 111 } |
110 #undef XFERMODE | 112 #undef XFERMODE |
111 | 113 |
112 // Some xfermodes use math like divide or sqrt that's best done in floats 1 pixe
l at a time. | 114 // Some xfermodes use math like divide or sqrt that's best done in floats 1 pixe
l at a time. |
113 #define XFERMODE(Name) static Sk4f SK_VECTORCALL Name(Sk4f d, Sk4f s) | 115 #define XFERMODE(Xfermode) \ |
| 116 struct Xfermode { Sk4f operator()(const Sk4f&, const Sk4f&) const; }; \ |
| 117 inline Sk4f Xfermode::operator()(const Sk4f& d, const Sk4f& s) const |
114 | 118 |
115 static inline Sk4f a_rgb(const Sk4f& a, const Sk4f& rgb) { | 119 static inline Sk4f a_rgb(const Sk4f& a, const Sk4f& rgb) { |
116 static_assert(SK_A32_SHIFT == 24, ""); | 120 static_assert(SK_A32_SHIFT == 24, ""); |
117 return a * Sk4f(0,0,0,1) + rgb * Sk4f(1,1,1,0); | 121 return a * Sk4f(0,0,0,1) + rgb * Sk4f(1,1,1,0); |
118 } | 122 } |
119 static inline Sk4f alphas(const Sk4f& f) { | 123 static inline Sk4f alphas(const Sk4f& f) { |
120 return SkNx_dup<SK_A32_SHIFT/8>(f); | 124 return SkNx_dup<SK_A32_SHIFT/8>(f); |
121 } | 125 } |
122 | 126 |
123 XFERMODE(ColorDodge) { | 127 XFERMODE(ColorDodge) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 | 178 |
175 auto alpha = s + d*isa; | 179 auto alpha = s + d*isa; |
176 auto colors = s*ida + d*isa + (s2 <= sa).thenElse(darkSrc, liteSrc);
// Case 1 or 2/3? | 180 auto colors = s*ida + d*isa + (s2 <= sa).thenElse(darkSrc, liteSrc);
// Case 1 or 2/3? |
177 | 181 |
178 return a_rgb(alpha, colors); | 182 return a_rgb(alpha, colors); |
179 } | 183 } |
180 #undef XFERMODE | 184 #undef XFERMODE |
181 | 185 |
182 // A reasonable fallback mode for doing AA is to simply apply the transfermode f
irst, | 186 // A reasonable fallback mode for doing AA is to simply apply the transfermode f
irst, |
183 // then linearly interpolate the AA. | 187 // then linearly interpolate the AA. |
184 template <Sk4px (SK_VECTORCALL *Mode)(Sk4px, Sk4px)> | 188 template <typename Xfermode> |
185 static Sk4px SK_VECTORCALL xfer_aa(Sk4px s, Sk4px d, Sk4px aa) { | 189 static Sk4px xfer_aa(const Sk4px& s, const Sk4px& d, const Sk4px& aa) { |
186 Sk4px bw = Mode(s, d); | 190 Sk4px bw = Xfermode()(s, d); |
187 return (bw * aa + d * aa.inv()).div255(); | 191 return (bw * aa + d * aa.inv()).div255(); |
188 } | 192 } |
189 | 193 |
190 // For some transfermodes we specialize AA, either for correctness or performanc
e. | 194 // For some transfermodes we specialize AA, either for correctness or performanc
e. |
191 #define XFERMODE_AA(Name) \ | 195 #define XFERMODE_AA(Xfermode) \ |
192 template <> Sk4px SK_VECTORCALL xfer_aa<Name>(Sk4px s, Sk4px d, Sk4px aa) | 196 template <> Sk4px xfer_aa<Xfermode>(const Sk4px& s, const Sk4px& d, const Sk
4px& aa) |
193 | 197 |
194 // Plus' clamp needs to happen after AA. skia:3852 | 198 // Plus' clamp needs to happen after AA. skia:3852 |
195 XFERMODE_AA(Plus) { // [ clamp( (1-AA)D + (AA)(S+D) ) == clamp(D + AA*S) ] | 199 XFERMODE_AA(Plus) { // [ clamp( (1-AA)D + (AA)(S+D) ) == clamp(D + AA*S) ] |
196 return d.saturatedAdd(s.approxMulDiv255(aa)); | 200 return d.saturatedAdd(s.approxMulDiv255(aa)); |
197 } | 201 } |
198 | 202 |
199 #undef XFERMODE_AA | 203 #undef XFERMODE_AA |
200 | 204 |
| 205 template <typename Xfermode> |
201 class Sk4pxXfermode : public SkProcCoeffXfermode { | 206 class Sk4pxXfermode : public SkProcCoeffXfermode { |
202 public: | 207 public: |
203 typedef Sk4px (SK_VECTORCALL *Proc4)(Sk4px, Sk4px); | 208 Sk4pxXfermode(const ProcCoeff& rec, SkXfermode::Mode mode) |
204 typedef Sk4px (SK_VECTORCALL *AAProc4)(Sk4px, Sk4px, Sk4px); | 209 : INHERITED(rec, mode) {} |
205 | |
206 Sk4pxXfermode(const ProcCoeff& rec, SkXfermode::Mode mode, Proc4 proc4, AAPr
oc4 aaproc4) | |
207 : INHERITED(rec, mode) | |
208 , fProc4(proc4) | |
209 , fAAProc4(aaproc4) {} | |
210 | 210 |
211 void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[
]) const override { | 211 void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[
]) const override { |
212 if (nullptr == aa) { | 212 if (nullptr == aa) { |
213 Sk4px::MapDstSrc(n, dst, src, [&](const Sk4px& dst4, const Sk4px& sr
c4) { | 213 Sk4px::MapDstSrc(n, dst, src, [&](const Sk4px& dst4, const Sk4px& sr
c4) { |
214 return fProc4(src4, dst4); | 214 return Xfermode()(src4, dst4); |
215 }); | 215 }); |
216 } else { | 216 } else { |
217 Sk4px::MapDstSrcAlpha(n, dst, src, aa, | 217 Sk4px::MapDstSrcAlpha(n, dst, src, aa, |
218 [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha
) { | 218 [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha
) { |
219 return fAAProc4(src4, dst4, alpha); | 219 return xfer_aa<Xfermode>(src4, dst4, alpha); |
220 }); | 220 }); |
221 } | 221 } |
222 } | 222 } |
223 | 223 |
224 void xfer16(uint16_t dst[], const SkPMColor src[], int n, const SkAlpha aa[]
) const override { | 224 void xfer16(uint16_t dst[], const SkPMColor src[], int n, const SkAlpha aa[]
) const override { |
225 if (nullptr == aa) { | 225 SkPMColor dst32[4]; |
226 Sk4px::MapDstSrc(n, dst, src, [&](const Sk4px& dst4, const Sk4px& sr
c4) { | 226 while (n >= 4) { |
227 return fProc4(src4, dst4); | 227 dst32[0] = SkPixel16ToPixel32(dst[0]); |
228 }); | 228 dst32[1] = SkPixel16ToPixel32(dst[1]); |
229 } else { | 229 dst32[2] = SkPixel16ToPixel32(dst[2]); |
230 Sk4px::MapDstSrcAlpha(n, dst, src, aa, | 230 dst32[3] = SkPixel16ToPixel32(dst[3]); |
231 [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha
) { | 231 |
232 return fAAProc4(src4, dst4, alpha); | 232 this->xfer32(dst32, src, 4, aa); |
233 }); | 233 |
| 234 dst[0] = SkPixel32ToPixel16(dst32[0]); |
| 235 dst[1] = SkPixel32ToPixel16(dst32[1]); |
| 236 dst[2] = SkPixel32ToPixel16(dst32[2]); |
| 237 dst[3] = SkPixel32ToPixel16(dst32[3]); |
| 238 |
| 239 dst += 4; |
| 240 src += 4; |
| 241 aa += aa ? 4 : 0; |
| 242 n -= 4; |
| 243 } |
| 244 while (n) { |
| 245 SkPMColor dst32 = SkPixel16ToPixel32(*dst); |
| 246 this->xfer32(&dst32, src, 1, aa); |
| 247 *dst = SkPixel32ToPixel16(dst32); |
| 248 |
| 249 dst += 1; |
| 250 src += 1; |
| 251 aa += aa ? 1 : 0; |
| 252 n -= 1; |
234 } | 253 } |
235 } | 254 } |
236 | 255 |
237 private: | 256 private: |
238 Proc4 fProc4; | |
239 AAProc4 fAAProc4; | |
240 typedef SkProcCoeffXfermode INHERITED; | 257 typedef SkProcCoeffXfermode INHERITED; |
241 }; | 258 }; |
242 | 259 |
| 260 template <typename Xfermode> |
243 class Sk4fXfermode : public SkProcCoeffXfermode { | 261 class Sk4fXfermode : public SkProcCoeffXfermode { |
244 public: | 262 public: |
245 typedef Sk4f (SK_VECTORCALL *ProcF)(Sk4f, Sk4f); | 263 Sk4fXfermode(const ProcCoeff& rec, SkXfermode::Mode mode) |
246 Sk4fXfermode(const ProcCoeff& rec, SkXfermode::Mode mode, ProcF procf) | 264 : INHERITED(rec, mode) {} |
247 : INHERITED(rec, mode) | |
248 , fProcF(procf) {} | |
249 | 265 |
250 void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[
]) const override { | 266 void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[
]) const override { |
251 for (int i = 0; i < n; i++) { | 267 for (int i = 0; i < n; i++) { |
252 dst[i] = aa ? this->xfer32(dst[i], src[i], aa[i]) | 268 dst[i] = Xfer32_1(dst[i], src[i], aa ? aa+i : nullptr); |
253 : this->xfer32(dst[i], src[i]); | |
254 } | 269 } |
255 } | 270 } |
256 | 271 |
257 void xfer16(uint16_t dst[], const SkPMColor src[], int n, const SkAlpha aa[]
) const override { | 272 void xfer16(uint16_t dst[], const SkPMColor src[], int n, const SkAlpha aa[]
) const override { |
258 for (int i = 0; i < n; i++) { | 273 for (int i = 0; i < n; i++) { |
259 SkPMColor dst32 = SkPixel16ToPixel32(dst[i]); | 274 SkPMColor dst32 = SkPixel16ToPixel32(dst[i]); |
260 dst32 = aa ? this->xfer32(dst32, src[i], aa[i]) | 275 dst32 = Xfer32_1(dst32, src[i], aa ? aa+i : nullptr); |
261 : this->xfer32(dst32, src[i]); | |
262 dst[i] = SkPixel32ToPixel16(dst32); | 276 dst[i] = SkPixel32ToPixel16(dst32); |
263 } | 277 } |
264 } | 278 } |
265 | 279 |
266 private: | 280 private: |
| 281 static SkPMColor Xfer32_1(SkPMColor dst, const SkPMColor src, const SkAlpha*
aa) { |
| 282 Sk4f d = Load(dst), |
| 283 s = Load(src), |
| 284 b = Xfermode()(d, s); |
| 285 if (aa) { |
| 286 Sk4f a = Sk4f(*aa) * Sk4f(1.0f/255); |
| 287 b = b*a + d*(Sk4f(1)-a); |
| 288 } |
| 289 return Round(b); |
| 290 } |
| 291 |
267 static Sk4f Load(SkPMColor c) { | 292 static Sk4f Load(SkPMColor c) { |
268 return SkNx_cast<float>(Sk4b::Load((uint8_t*)&c)) * Sk4f(1.0f/255); | 293 return SkNx_cast<float>(Sk4b::Load((uint8_t*)&c)) * Sk4f(1.0f/255); |
269 } | 294 } |
| 295 |
270 static SkPMColor Round(const Sk4f& f) { | 296 static SkPMColor Round(const Sk4f& f) { |
271 SkPMColor c; | 297 SkPMColor c; |
272 SkNx_cast<uint8_t>(f * Sk4f(255) + Sk4f(0.5f)).store((uint8_t*)&c); | 298 SkNx_cast<uint8_t>(f * Sk4f(255) + Sk4f(0.5f)).store((uint8_t*)&c); |
273 return c; | 299 return c; |
274 } | 300 } |
275 inline SkPMColor xfer32(SkPMColor dst, SkPMColor src) const { | |
276 return Round(fProcF(Load(dst), Load(src))); | |
277 } | |
278 | 301 |
279 inline SkPMColor xfer32(SkPMColor dst, SkPMColor src, SkAlpha aa) const { | |
280 Sk4f s(Load(src)), | |
281 d(Load(dst)), | |
282 b(fProcF(d,s)); | |
283 // We do aa in full float precision before going back down to bytes, bec
ause we can! | |
284 Sk4f a = Sk4f(aa) * Sk4f(1.0f/255); | |
285 b = b*a + d*(Sk4f(1)-a); | |
286 return Round(b); | |
287 } | |
288 | |
289 ProcF fProcF; | |
290 typedef SkProcCoeffXfermode INHERITED; | 302 typedef SkProcCoeffXfermode INHERITED; |
291 }; | 303 }; |
292 | 304 |
293 } // namespace | 305 } // namespace |
294 | 306 |
295 namespace SK_OPTS_NS { | 307 namespace SK_OPTS_NS { |
296 | 308 |
297 static SkXfermode* create_xfermode(const ProcCoeff& rec, SkXfermode::Mode mode)
{ | 309 static SkXfermode* create_xfermode(const ProcCoeff& rec, SkXfermode::Mode mode)
{ |
298 switch (mode) { | 310 switch (mode) { |
299 #define CASE(Mode) \ | 311 #define CASE(Xfermode) \ |
300 case SkXfermode::k##Mode##_Mode: return new Sk4pxXfermode(rec, mode, &Mode,
&xfer_aa<Mode>) | 312 case SkXfermode::k##Xfermode##_Mode: return new Sk4pxXfermode<Xfermode>(rec,
mode) |
301 CASE(Clear); | 313 CASE(Clear); |
302 CASE(Src); | 314 CASE(Src); |
303 CASE(Dst); | 315 CASE(Dst); |
304 CASE(SrcOver); | 316 CASE(SrcOver); |
305 CASE(DstOver); | 317 CASE(DstOver); |
306 CASE(SrcIn); | 318 CASE(SrcIn); |
307 CASE(DstIn); | 319 CASE(DstIn); |
308 CASE(SrcOut); | 320 CASE(SrcOut); |
309 CASE(DstOut); | 321 CASE(DstOut); |
310 CASE(SrcATop); | 322 CASE(SrcATop); |
311 CASE(DstATop); | 323 CASE(DstATop); |
312 CASE(Xor); | 324 CASE(Xor); |
313 CASE(Plus); | 325 CASE(Plus); |
314 CASE(Modulate); | 326 CASE(Modulate); |
315 CASE(Screen); | 327 CASE(Screen); |
316 CASE(Multiply); | 328 CASE(Multiply); |
317 CASE(Difference); | 329 CASE(Difference); |
318 CASE(Exclusion); | 330 CASE(Exclusion); |
319 CASE(HardLight); | 331 CASE(HardLight); |
320 CASE(Overlay); | 332 CASE(Overlay); |
321 CASE(Darken); | 333 CASE(Darken); |
322 CASE(Lighten); | 334 CASE(Lighten); |
323 #undef CASE | 335 #undef CASE |
324 | 336 |
325 #define CASE(Mode) \ | 337 #define CASE(Xfermode) \ |
326 case SkXfermode::k##Mode##_Mode: return new Sk4fXfermode(rec, mode, &Mode) | 338 case SkXfermode::k##Xfermode##_Mode: return new Sk4fXfermode<Xfermode>(rec,
mode) |
327 CASE(ColorDodge); | 339 CASE(ColorDodge); |
328 CASE(ColorBurn); | 340 CASE(ColorBurn); |
329 CASE(SoftLight); | 341 CASE(SoftLight); |
330 #undef CASE | 342 #undef CASE |
331 | 343 |
332 default: break; | 344 default: break; |
333 } | 345 } |
334 return nullptr; | 346 return nullptr; |
335 } | 347 } |
336 | 348 |
337 } // namespace SK_OPTS_NS | 349 } // namespace SK_OPTS_NS |
338 | 350 |
339 #endif//Sk4pxXfermode_DEFINED | 351 #endif//Sk4pxXfermode_DEFINED |
OLD | NEW |