Merge pull request #51 from google/chrome/m56
[platform/upstream/libSkiaSharp.git] / src / opts / SkRasterPipeline_opts.h
1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #ifndef SkRasterPipeline_opts_DEFINED
9 #define SkRasterPipeline_opts_DEFINED
10
11 #include "SkColorPriv.h"
12 #include "SkColorLookUpTable.h"
13 #include "SkColorSpaceXform_A2B.h"
14 #include "SkColorSpaceXformPriv.h"
15 #include "SkHalf.h"
16 #include "SkPM4f.h"
17 #include "SkPM4fPriv.h"
18 #include "SkRasterPipeline.h"
19 #include "SkSRGB.h"
20 #include "SkUtils.h"
21 #include <utility>
22
23 namespace {
24
25 #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2
26     static constexpr int N = 8;
27 #else
28     static constexpr int N = 4;
29 #endif
30
31     using SkNf = SkNx<N, float>;
32     using SkNi = SkNx<N, int>;
33     using SkNh = SkNx<N, uint16_t>;
34
35     struct BodyStage;
36     struct TailStage;
37
38     using Body = void(SK_VECTORCALL *)(BodyStage*, size_t,         SkNf,SkNf,SkNf,SkNf,
39                                                                    SkNf,SkNf,SkNf,SkNf);
40     using Tail = void(SK_VECTORCALL *)(TailStage*, size_t, size_t, SkNf,SkNf,SkNf,SkNf,
41                                                                    SkNf,SkNf,SkNf,SkNf);
42     struct BodyStage { Body next; void* ctx; };
43     struct TailStage { Tail next; void* ctx; };
44
45 }  // namespace
46
47 #define SI static inline
48
49 // Stages are logically a pipeline, and physically are contiguous in an array.
50 // To get to the next stage, we just increment our pointer to the next array element.
51 SI void SK_VECTORCALL next(BodyStage* st, size_t x,
52                            SkNf  r, SkNf  g, SkNf  b, SkNf  a,
53                            SkNf dr, SkNf dg, SkNf db, SkNf da) {
54     st->next(st+1, x, r,g,b,a, dr,dg,db,da);
55 }
56 SI void SK_VECTORCALL next(TailStage* st, size_t x, size_t tail,
57                            SkNf  r, SkNf  g, SkNf  b, SkNf  a,
58                            SkNf dr, SkNf dg, SkNf db, SkNf da) {
59     st->next(st+1, x,tail, r,g,b,a, dr,dg,db,da);
60 }
61
62
63 #define STAGE(name, kCallNext)                                                           \
64     template <bool kIsTail>                                                              \
65     static SK_ALWAYS_INLINE void name##_kernel(void* ctx, size_t x, size_t tail,         \
66                                                SkNf&  r, SkNf&  g, SkNf&  b, SkNf&  a,   \
67                                                SkNf& dr, SkNf& dg, SkNf& db, SkNf& da);  \
68     SI void SK_VECTORCALL name(BodyStage* st, size_t x,                                  \
69                                SkNf  r, SkNf  g, SkNf  b, SkNf  a,                       \
70                                SkNf dr, SkNf dg, SkNf db, SkNf da) {                     \
71         name##_kernel<false>(st->ctx, x,0, r,g,b,a, dr,dg,db,da);                        \
72         if (kCallNext) {                                                                 \
73             next(st, x, r,g,b,a, dr,dg,db,da);                                           \
74         }                                                                                \
75     }                                                                                    \
76     SI void SK_VECTORCALL name(TailStage* st, size_t x, size_t tail,                     \
77                                SkNf  r, SkNf  g, SkNf  b, SkNf  a,                       \
78                                SkNf dr, SkNf dg, SkNf db, SkNf da) {                     \
79         name##_kernel<true>(st->ctx, x,tail, r,g,b,a, dr,dg,db,da);                      \
80         if (kCallNext) {                                                                 \
81             next(st, x,tail, r,g,b,a, dr,dg,db,da);                                      \
82         }                                                                                \
83     }                                                                                    \
84     template <bool kIsTail>                                                              \
85     static SK_ALWAYS_INLINE void name##_kernel(void* ctx, size_t x, size_t tail,         \
86                                                SkNf&  r, SkNf&  g, SkNf&  b, SkNf&  a,   \
87                                                SkNf& dr, SkNf& dg, SkNf& db, SkNf& da)
88
89
90 // Many xfermodes apply the same logic to each channel.
91 #define RGBA_XFERMODE(name)                                                     \
92     static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa,   \
93                                                const SkNf& d, const SkNf& da);  \
94     SI void SK_VECTORCALL name(BodyStage* st, size_t x,                         \
95                                SkNf  r, SkNf  g, SkNf  b, SkNf  a,              \
96                                SkNf dr, SkNf dg, SkNf db, SkNf da) {            \
97         r = name##_kernel(r,a,dr,da);                                           \
98         g = name##_kernel(g,a,dg,da);                                           \
99         b = name##_kernel(b,a,db,da);                                           \
100         a = name##_kernel(a,a,da,da);                                           \
101         next(st, x, r,g,b,a, dr,dg,db,da);                                      \
102     }                                                                           \
103     SI void SK_VECTORCALL name(TailStage* st, size_t x, size_t tail,            \
104                                SkNf  r, SkNf  g, SkNf  b, SkNf  a,              \
105                                SkNf dr, SkNf dg, SkNf db, SkNf da) {            \
106         r = name##_kernel(r,a,dr,da);                                           \
107         g = name##_kernel(g,a,dg,da);                                           \
108         b = name##_kernel(b,a,db,da);                                           \
109         a = name##_kernel(a,a,da,da);                                           \
110         next(st, x,tail, r,g,b,a, dr,dg,db,da);                                 \
111     }                                                                           \
112     static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa,   \
113                                                const SkNf& d, const SkNf& da)
114
115 // Most of the rest apply the same logic to color channels and use srcover's alpha logic.
116 #define RGB_XFERMODE(name)                                                      \
117     static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa,   \
118                                                const SkNf& d, const SkNf& da);  \
119     SI void SK_VECTORCALL name(BodyStage* st, size_t x,                         \
120                                SkNf  r, SkNf  g, SkNf  b, SkNf  a,              \
121                                SkNf dr, SkNf dg, SkNf db, SkNf da) {            \
122         r = name##_kernel(r,a,dr,da);                                           \
123         g = name##_kernel(g,a,dg,da);                                           \
124         b = name##_kernel(b,a,db,da);                                           \
125         a = a + (da * (1.0f-a));                                                \
126         next(st, x, r,g,b,a, dr,dg,db,da);                                      \
127     }                                                                           \
128     SI void SK_VECTORCALL name(TailStage* st, size_t x, size_t tail,            \
129                                SkNf  r, SkNf  g, SkNf  b, SkNf  a,              \
130                                SkNf dr, SkNf dg, SkNf db, SkNf da) {            \
131         r = name##_kernel(r,a,dr,da);                                           \
132         g = name##_kernel(g,a,dg,da);                                           \
133         b = name##_kernel(b,a,db,da);                                           \
134         a = a + (da * (1.0f-a));                                                \
135         next(st, x,tail, r,g,b,a, dr,dg,db,da);                                 \
136     }                                                                           \
137     static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa,   \
138                                                const SkNf& d, const SkNf& da)
139
140 SI SkNf inv(const SkNf& x) { return 1.0f - x; }
141
142 SI SkNf lerp(const SkNf& from, const SkNf& to, const SkNf& cov) {
143     return SkNx_fma(to-from, cov, from);
144 }
145
146 template <bool kIsTail, typename T>
147 SI SkNx<N,T> load(size_t tail, const T* src) {
148     SkASSERT(kIsTail == (tail > 0));
149     // TODO: maskload for 32- and 64-bit T
150     if (kIsTail) {
151         T buf[8] = {0};
152         switch (tail & (N-1)) {
153             case 7: buf[6] = src[6];
154             case 6: buf[5] = src[5];
155             case 5: buf[4] = src[4];
156             case 4: buf[3] = src[3];
157             case 3: buf[2] = src[2];
158             case 2: buf[1] = src[1];
159         }
160         buf[0] = src[0];
161         return SkNx<N,T>::Load(buf);
162     }
163     return SkNx<N,T>::Load(src);
164 }
165
166 template <bool kIsTail, typename T>
167 SI void store(size_t tail, const SkNx<N,T>& v, T* dst) {
168     SkASSERT(kIsTail == (tail > 0));
169     // TODO: maskstore for 32- and 64-bit T
170     if (kIsTail) {
171         switch (tail & (N-1)) {
172             case 7: dst[6] = v[6];
173             case 6: dst[5] = v[5];
174             case 5: dst[4] = v[4];
175             case 4: dst[3] = v[3];
176             case 3: dst[2] = v[2];
177             case 2: dst[1] = v[1];
178         }
179         dst[0] = v[0];
180         return;
181     }
182     v.store(dst);
183 }
184
185 SI void from_565(const SkNh& _565, SkNf* r, SkNf* g, SkNf* b) {
186     auto _32_bit = SkNx_cast<int>(_565);
187
188     *r = SkNx_cast<float>(_32_bit & SK_R16_MASK_IN_PLACE) * (1.0f / SK_R16_MASK_IN_PLACE);
189     *g = SkNx_cast<float>(_32_bit & SK_G16_MASK_IN_PLACE) * (1.0f / SK_G16_MASK_IN_PLACE);
190     *b = SkNx_cast<float>(_32_bit & SK_B16_MASK_IN_PLACE) * (1.0f / SK_B16_MASK_IN_PLACE);
191 }
192
193 SI SkNh to_565(const SkNf& r, const SkNf& g, const SkNf& b) {
194     return SkNx_cast<uint16_t>( SkNx_cast<int>(r * SK_R16_MASK + 0.5f) << SK_R16_SHIFT
195                               | SkNx_cast<int>(g * SK_G16_MASK + 0.5f) << SK_G16_SHIFT
196                               | SkNx_cast<int>(b * SK_B16_MASK + 0.5f) << SK_B16_SHIFT);
197 }
198
199 STAGE(just_return, false) { }
200
201 STAGE(trace, true) {
202     SkDebugf("%s\n", (const char*)ctx);
203 }
204
205 STAGE(registers, true) {
206     auto print = [](const char* name, const SkNf& v) {
207         SkDebugf("%s:", name);
208         for (int i = 0; i < N; i++) {
209             SkDebugf(" %g", v[i]);
210         }
211         SkDebugf("\n");
212     };
213     print(" r",  r);
214     print(" g",  g);
215     print(" b",  b);
216     print(" a",  a);
217     print("dr", dr);
218     print("dg", dg);
219     print("db", db);
220     print("da", da);
221 }
222
223 STAGE(clamp_0, true) {
224     a = SkNf::Max(a, 0.0f);
225     r = SkNf::Max(r, 0.0f);
226     g = SkNf::Max(g, 0.0f);
227     b = SkNf::Max(b, 0.0f);
228 }
229
230 STAGE(clamp_a, true) {
231     a = SkNf::Min(a, 1.0f);
232     r = SkNf::Min(r, a);
233     g = SkNf::Min(g, a);
234     b = SkNf::Min(b, a);
235 }
236
237 STAGE(clamp_1, true) {
238     a = SkNf::Min(a, 1.0f);
239     r = SkNf::Min(r, 1.0f);
240     g = SkNf::Min(g, 1.0f);
241     b = SkNf::Min(b, 1.0f);
242 }
243
244 STAGE(unpremul, true) {
245     r *= a.invert();
246     g *= a.invert();
247     b *= a.invert();
248 }
249
250 STAGE(premul, true) {
251     r *= a;
252     g *= a;
253     b *= a;
254 }
255
256 STAGE(move_src_dst, true) {
257     dr = r;
258     dg = g;
259     db = b;
260     da = a;
261 }
262
263 STAGE(swap_src_dst, true) {
264     SkTSwap(r, dr);
265     SkTSwap(g, dg);
266     SkTSwap(b, db);
267     SkTSwap(a, da);
268 }
269
270 // The default shader produces a constant color (from the SkPaint).
271 STAGE(constant_color, true) {
272     auto color = (const SkPM4f*)ctx;
273     r = color->r();
274     g = color->g();
275     b = color->b();
276     a = color->a();
277 }
278
279 // s' = sc for a constant c.
280 STAGE(scale_constant_float, true) {
281     SkNf c = *(const float*)ctx;
282
283     r *= c;
284     g *= c;
285     b *= c;
286     a *= c;
287 }
288
289 // s' = d(1-c) + sc, for a constant c.
290 STAGE(lerp_constant_float, true) {
291     SkNf c = *(const float*)ctx;
292
293     r = lerp(dr, r, c);
294     g = lerp(dg, g, c);
295     b = lerp(db, b, c);
296     a = lerp(da, a, c);
297 }
298
299 // s' = sc for 8-bit c.
300 STAGE(scale_u8, true) {
301     auto ptr = *(const uint8_t**)ctx + x;
302
303     SkNf c = SkNx_cast<float>(load<kIsTail>(tail, ptr)) * (1/255.0f);
304     r = r*c;
305     g = g*c;
306     b = b*c;
307     a = a*c;
308 }
309
310 // s' = d(1-c) + sc for 8-bit c.
311 STAGE(lerp_u8, true) {
312     auto ptr = *(const uint8_t**)ctx + x;
313
314     SkNf c = SkNx_cast<float>(load<kIsTail>(tail, ptr)) * (1/255.0f);
315     r = lerp(dr, r, c);
316     g = lerp(dg, g, c);
317     b = lerp(db, b, c);
318     a = lerp(da, a, c);
319 }
320
321 // s' = d(1-c) + sc for 565 c.
322 STAGE(lerp_565, true) {
323     auto ptr = *(const uint16_t**)ctx + x;
324     SkNf cr, cg, cb;
325     from_565(load<kIsTail>(tail, ptr), &cr, &cg, &cb);
326
327     r = lerp(dr, r, cr);
328     g = lerp(dg, g, cg);
329     b = lerp(db, b, cb);
330     a = 1.0f;
331 }
332
333 STAGE(load_d_565, true) {
334     auto ptr = *(const uint16_t**)ctx + x;
335     from_565(load<kIsTail>(tail, ptr), &dr,&dg,&db);
336     da = 1.0f;
337 }
338
339 STAGE(load_s_565, true) {
340     auto ptr = *(const uint16_t**)ctx + x;
341     from_565(load<kIsTail>(tail, ptr), &r,&g,&b);
342     a = 1.0f;
343 }
344
345 STAGE(store_565, false) {
346     auto ptr = *(uint16_t**)ctx + x;
347     store<kIsTail>(tail, to_565(r,g,b), ptr);
348 }
349
350 STAGE(load_d_f16, true) {
351     auto ptr = *(const uint64_t**)ctx + x;
352
353     SkNh rh, gh, bh, ah;
354     if (kIsTail) {
355         uint64_t buf[8] = {0};
356         switch (tail & (N-1)) {
357             case 7: buf[6] = ptr[6];
358             case 6: buf[5] = ptr[5];
359             case 5: buf[4] = ptr[4];
360             case 4: buf[3] = ptr[3];
361             case 3: buf[2] = ptr[2];
362             case 2: buf[1] = ptr[1];
363         }
364         buf[0] = ptr[0];
365         SkNh::Load4(buf, &rh, &gh, &bh, &ah);
366     } else {
367         SkNh::Load4(ptr, &rh, &gh, &bh, &ah);
368     }
369
370     dr = SkHalfToFloat_finite_ftz(rh);
371     dg = SkHalfToFloat_finite_ftz(gh);
372     db = SkHalfToFloat_finite_ftz(bh);
373     da = SkHalfToFloat_finite_ftz(ah);
374 }
375
376 STAGE(load_s_f16, true) {
377     auto ptr = *(const uint64_t**)ctx + x;
378
379     SkNh rh, gh, bh, ah;
380     if (kIsTail) {
381         uint64_t buf[8] = {0};
382         switch (tail & (N-1)) {
383             case 7: buf[6] = ptr[6];
384             case 6: buf[5] = ptr[5];
385             case 5: buf[4] = ptr[4];
386             case 4: buf[3] = ptr[3];
387             case 3: buf[2] = ptr[2];
388             case 2: buf[1] = ptr[1];
389         }
390         buf[0] = ptr[0];
391         SkNh::Load4(buf, &rh, &gh, &bh, &ah);
392     } else {
393         SkNh::Load4(ptr, &rh, &gh, &bh, &ah);
394     }
395
396     r = SkHalfToFloat_finite_ftz(rh);
397     g = SkHalfToFloat_finite_ftz(gh);
398     b = SkHalfToFloat_finite_ftz(bh);
399     a = SkHalfToFloat_finite_ftz(ah);
400 }
401
402 STAGE(store_f16, false) {
403     auto ptr = *(uint64_t**)ctx + x;
404
405     uint64_t buf[8];
406     SkNh::Store4(kIsTail ? buf : ptr, SkFloatToHalf_finite_ftz(r),
407                                       SkFloatToHalf_finite_ftz(g),
408                                       SkFloatToHalf_finite_ftz(b),
409                                       SkFloatToHalf_finite_ftz(a));
410     if (kIsTail) {
411         switch (tail & (N-1)) {
412             case 7: ptr[6] = buf[6];
413             case 6: ptr[5] = buf[5];
414             case 5: ptr[4] = buf[4];
415             case 4: ptr[3] = buf[3];
416             case 3: ptr[2] = buf[2];
417             case 2: ptr[1] = buf[1];
418         }
419         ptr[0] = buf[0];
420     }
421 }
422
423 STAGE(store_f32, false) {
424     auto ptr = *(SkPM4f**)ctx + x;
425
426     SkPM4f buf[8];
427     SkNf::Store4(kIsTail ? buf : ptr, r,g,b,a);
428     if (kIsTail) {
429         switch (tail & (N-1)) {
430             case 7: ptr[6] = buf[6];
431             case 6: ptr[5] = buf[5];
432             case 5: ptr[4] = buf[4];
433             case 4: ptr[3] = buf[3];
434             case 3: ptr[2] = buf[2];
435             case 2: ptr[1] = buf[1];
436         }
437         ptr[0] = buf[0];
438     }
439 }
440
441
442 // Load 8-bit SkPMColor-order sRGB.
443 STAGE(load_d_srgb, true) {
444     auto ptr = *(const uint32_t**)ctx + x;
445
446     auto px = load<kIsTail>(tail, ptr);
447     auto to_int = [](const SkNx<N, uint32_t>& v) { return SkNi::Load(&v); };
448     dr =    sk_linear_from_srgb_math(to_int((px >> SK_R32_SHIFT) & 0xff));
449     dg =    sk_linear_from_srgb_math(to_int((px >> SK_G32_SHIFT) & 0xff));
450     db =    sk_linear_from_srgb_math(to_int((px >> SK_B32_SHIFT) & 0xff));
451     da = (1/255.0f)*SkNx_cast<float>(to_int( px >> SK_A32_SHIFT        ));
452 }
453
454 STAGE(load_s_srgb, true) {
455     auto ptr = *(const uint32_t**)ctx + x;
456
457     auto px = load<kIsTail>(tail, ptr);
458     auto to_int = [](const SkNx<N, uint32_t>& v) { return SkNi::Load(&v); };
459     r =    sk_linear_from_srgb_math(to_int((px >> SK_R32_SHIFT) & 0xff));
460     g =    sk_linear_from_srgb_math(to_int((px >> SK_G32_SHIFT) & 0xff));
461     b =    sk_linear_from_srgb_math(to_int((px >> SK_B32_SHIFT) & 0xff));
462     a = (1/255.0f)*SkNx_cast<float>(to_int( px >> SK_A32_SHIFT        ));
463 }
464
465 STAGE(store_srgb, false) {
466     auto ptr = *(uint32_t**)ctx + x;
467     store<kIsTail>(tail, (              sk_linear_to_srgb(r) << SK_R32_SHIFT
468                          |              sk_linear_to_srgb(g) << SK_G32_SHIFT
469                          |              sk_linear_to_srgb(b) << SK_B32_SHIFT
470                          | SkNx_cast<int>(0.5f + 255.0f * a) << SK_A32_SHIFT), (int*)ptr);
471 }
472
473 STAGE(load_s_8888, true) {
474     auto ptr = *(const uint32_t**)ctx + x;
475
476     auto px = load<kIsTail>(tail, ptr);
477     auto to_int = [](const SkNx<N, uint32_t>& v) { return SkNi::Load(&v); };
478     r = (1/255.0f)*SkNx_cast<float>(to_int((px >> 0) & 0xff));
479     g = (1/255.0f)*SkNx_cast<float>(to_int((px >> 8) & 0xff));
480     b = (1/255.0f)*SkNx_cast<float>(to_int((px >> 16) & 0xff));
481     a = (1/255.0f)*SkNx_cast<float>(to_int(px >> 24));
482 }
483
484 STAGE(store_8888, false) {
485     auto ptr = *(uint32_t**)ctx + x;
486     store<kIsTail>(tail, ( SkNx_cast<int>(255.0f * r + 0.5f) << 0
487                          | SkNx_cast<int>(255.0f * g + 0.5f) << 8
488                          | SkNx_cast<int>(255.0f * b + 0.5f) << 16
489                          | SkNx_cast<int>(255.0f * a + 0.5f) << 24 ), (int*)ptr);
490 }
491
492 RGBA_XFERMODE(clear)    { return 0.0f; }
493 //RGBA_XFERMODE(src)      { return s; }   // This would be a no-op stage, so we just omit it.
494 RGBA_XFERMODE(dst)      { return d; }
495
496 RGBA_XFERMODE(srcatop)  { return s*da + d*inv(sa); }
497 RGBA_XFERMODE(srcin)    { return s * da; }
498 RGBA_XFERMODE(srcout)   { return s * inv(da); }
499 RGBA_XFERMODE(srcover)  { return SkNx_fma(d, inv(sa), s); }
500 RGBA_XFERMODE(dstatop)  { return srcatop_kernel(d,da,s,sa); }
501 RGBA_XFERMODE(dstin)    { return srcin_kernel  (d,da,s,sa); }
502 RGBA_XFERMODE(dstout)   { return srcout_kernel (d,da,s,sa); }
503 RGBA_XFERMODE(dstover)  { return srcover_kernel(d,da,s,sa); }
504
505 RGBA_XFERMODE(modulate) { return s*d; }
506 RGBA_XFERMODE(multiply) { return s*inv(da) + d*inv(sa) + s*d; }
507 RGBA_XFERMODE(plus_)    { return s + d; }
508 RGBA_XFERMODE(screen)   { return s + d - s*d; }
509 RGBA_XFERMODE(xor_)     { return s*inv(da) + d*inv(sa); }
510
511 RGB_XFERMODE(colorburn) {
512     return (d == da  ).thenElse(d + s*inv(da),
513            (s == 0.0f).thenElse(s + d*inv(sa),
514                                 sa*(da - SkNf::Min(da, (da-d)*sa/s)) + s*inv(da) + d*inv(sa)));
515 }
516 RGB_XFERMODE(colordodge) {
517     return (d == 0.0f).thenElse(d + s*inv(da),
518            (s == sa  ).thenElse(s + d*inv(sa),
519                                 sa*SkNf::Min(da, (d*sa)/(sa - s)) + s*inv(da) + d*inv(sa)));
520 }
521 RGB_XFERMODE(darken)     { return s + d - SkNf::Max(s*da, d*sa); }
522 RGB_XFERMODE(difference) { return s + d - 2.0f*SkNf::Min(s*da,d*sa); }
523 RGB_XFERMODE(exclusion)  { return s + d - 2.0f*s*d; }
524 RGB_XFERMODE(hardlight) {
525     return s*inv(da) + d*inv(sa)
526          + (2.0f*s <= sa).thenElse(2.0f*s*d, sa*da - 2.0f*(da-d)*(sa-s));
527 }
528 RGB_XFERMODE(lighten) { return s + d - SkNf::Min(s*da, d*sa); }
529 RGB_XFERMODE(overlay) { return hardlight_kernel(d,da,s,sa); }
530 RGB_XFERMODE(softlight) {
531     SkNf m  = (da > 0.0f).thenElse(d / da, 0.0f),
532          s2 = 2.0f*s,
533          m4 = 4.0f*m;
534
535     // The logic forks three ways:
536     //    1. dark src?
537     //    2. light src, dark dst?
538     //    3. light src, light dst?
539     SkNf darkSrc = d*(sa + (s2 - sa)*(1.0f - m)),     // Used in case 1.
540          darkDst = (m4*m4 + m4)*(m - 1.0f) + 7.0f*m,  // Used in case 2.
541          liteDst = m.rsqrt().invert() - m,            // Used in case 3.
542          liteSrc = d*sa + da*(s2 - sa) * (4.0f*d <= da).thenElse(darkDst, liteDst);  // 2 or 3?
543     return s*inv(da) + d*inv(sa) + (s2 <= sa).thenElse(darkSrc, liteSrc);  // 1 or (2 or 3)?
544 }
545
546 STAGE(luminance_to_alpha, true) {
547     a = SK_LUM_COEFF_R*r + SK_LUM_COEFF_G*g + SK_LUM_COEFF_B*b;
548     r = g = b = 0;
549 }
550
551 STAGE(matrix_3x4, true) {
552     auto m = (const float*)ctx;
553
554     auto fma = [](const SkNf& f, const SkNf& m, const SkNf& a) { return SkNx_fma(f,m,a); };
555     auto R = fma(r,m[0], fma(g,m[3], fma(b,m[6], m[ 9]))),
556          G = fma(r,m[1], fma(g,m[4], fma(b,m[7], m[10]))),
557          B = fma(r,m[2], fma(g,m[5], fma(b,m[8], m[11])));
558     r = R;
559     g = G;
560     b = B;
561 }
562
563 STAGE(matrix_4x5, true) {
564     auto m = (const float*)ctx;
565
566     auto fma = [](const SkNf& f, const SkNf& m, const SkNf& a) { return SkNx_fma(f,m,a); };
567     auto R = fma(r,m[0], fma(g,m[4], fma(b,m[ 8], fma(a,m[12], m[16])))),
568          G = fma(r,m[1], fma(g,m[5], fma(b,m[ 9], fma(a,m[13], m[17])))),
569          B = fma(r,m[2], fma(g,m[6], fma(b,m[10], fma(a,m[14], m[18])))),
570          A = fma(r,m[3], fma(g,m[7], fma(b,m[11], fma(a,m[15], m[19]))));
571     r = R;
572     g = G;
573     b = B;
574     a = A;
575 }
576
577 SI SkNf parametric(const SkNf& v, const SkColorSpaceTransferFn& p) {
578     float result[N];   // Unconstrained powf() doesn't vectorize well...
579     for (int i = 0; i < N; i++) {
580         float s = v[i];
581         result[i] = (s <= p.fD) ? p.fC * s + p.fF
582                                 : powf(s * p.fA + p.fB, p.fG) + p.fE;
583     }
584     return SkNf::Load(result);
585 }
586
587 STAGE(parametric_r, true) {
588     r = parametric(r, *(const SkColorSpaceTransferFn*)ctx);
589 }
590 STAGE(parametric_g, true) {
591     g = parametric(g, *(const SkColorSpaceTransferFn*)ctx);
592 }
593 STAGE(parametric_b, true) {
594     b = parametric(b, *(const SkColorSpaceTransferFn*)ctx);
595 }
596
597 SI SkNf table(const SkNf& v, const SkTableTransferFn& table) {
598     float result[N];
599     for (int i = 0; i < N; i++) {
600         result[i] = interp_lut(v[i], table.fData, table.fSize);
601     }
602     return SkNf::Load(result);
603 }
604
605 STAGE(table_r, true) {
606     r = table(r, *(const SkTableTransferFn*)ctx);
607 }
608 STAGE(table_g, true) {
609     g = table(g, *(const SkTableTransferFn*)ctx);
610 }
611 STAGE(table_b, true) {
612     b = table(b, *(const SkTableTransferFn*)ctx);
613 }
614
615 STAGE(color_lookup_table, true) {
616     const SkColorLookUpTable* colorLUT = (const SkColorLookUpTable*)ctx;
617     float rgb[3];
618     float result[3][N];
619     for (int i = 0; i < N; ++i) {
620         rgb[0] = r[i];
621         rgb[1] = g[i];
622         rgb[2] = b[i];
623         colorLUT->interp3D(rgb, rgb);
624         result[0][i] = rgb[0];
625         result[1][i] = rgb[1];
626         result[2][i] = rgb[2];
627     }
628     r = SkNf::Load(result[0]);
629     g = SkNf::Load(result[1]);
630     b = SkNf::Load(result[2]);
631 }
632
633 STAGE(lab_to_xyz, true) {
634     const auto lab_l = r * 100.0f;
635     const auto lab_a = g * 255.0f - 128.0f;
636     const auto lab_b = b * 255.0f - 128.0f;
637     auto Y = (lab_l + 16.0f) * (1/116.0f);
638     auto X = lab_a * (1/500.0f) + Y;
639     auto Z = Y - (lab_b * (1/200.0f));
640
641     const auto X3 = X*X*X;
642     X = (X3 > 0.008856f).thenElse(X3, (X - (16/116.0f)) * (1/7.787f));
643     const auto Y3 = Y*Y*Y;
644     Y = (Y3 > 0.008856f).thenElse(Y3, (Y - (16/116.0f)) * (1/7.787f));
645     const auto Z3 = Z*Z*Z;
646     Z = (Z3 > 0.008856f).thenElse(Z3, (Z - (16/116.0f)) * (1/7.787f));
647
648     // adjust to D50 illuminant
649     X *= 0.96422f;
650     Y *= 1.00000f;
651     Z *= 0.82521f;
652
653     r = X;
654     g = Y;
655     b = Z;
656 }
657
658 STAGE(swap_rb, true) {
659     SkTSwap(r, b);
660 }
661
662 template <typename Fn>
663 SI Fn enum_to_Fn(SkRasterPipeline::StockStage st) {
664     switch (st) {
665     #define M(stage) case SkRasterPipeline::stage: return stage;
666         SK_RASTER_PIPELINE_STAGES(M)
667     #undef M
668     }
669     SkASSERT(false);
670     return just_return;
671 }
672
673 namespace SK_OPTS_NS {
674
675     struct Memset16 {
676         uint16_t** dst;
677         uint16_t val;
678         void operator()(size_t x, size_t, size_t n) { sk_memset16(*dst + x, val, n); }
679     };
680
681     struct Memset32 {
682         uint32_t** dst;
683         uint32_t val;
684         void operator()(size_t x, size_t, size_t n) { sk_memset32(*dst + x, val, n); }
685     };
686
687     struct Memset64 {
688         uint64_t** dst;
689         uint64_t val;
690         void operator()(size_t x, size_t, size_t n) { sk_memset64(*dst + x, val, n); }
691     };
692
693     SI std::function<void(size_t, size_t, size_t)>
694     compile_pipeline(const SkRasterPipeline::Stage* stages, int nstages) {
695         if (nstages == 2 && stages[0].stage == SkRasterPipeline::constant_color) {
696             SkPM4f src = *(const SkPM4f*)stages[0].ctx;
697             void* dst = stages[1].ctx;
698             switch (stages[1].stage) {
699                 case SkRasterPipeline::store_565:
700                     return Memset16{(uint16_t**)dst, SkPackRGB16(src.r() * SK_R16_MASK + 0.5f,
701                                                                  src.g() * SK_G16_MASK + 0.5f,
702                                                                  src.b() * SK_B16_MASK + 0.5f)};
703                 case SkRasterPipeline::store_srgb:
704                     return Memset32{(uint32_t**)dst, Sk4f_toS32(src.to4f_pmorder())};
705
706                 case SkRasterPipeline::store_f16:
707                     return Memset64{(uint64_t**)dst, src.toF16()};
708
709                 default: break;
710             }
711         }
712
713         struct Compiled {
714             Compiled(const SkRasterPipeline::Stage* stages, int nstages) {
715                 if (nstages == 0) {
716                     return;
717                 }
718
719                 fBodyStart = enum_to_Fn<Body>(stages[0].stage);
720                 fTailStart = enum_to_Fn<Tail>(stages[0].stage);
721                 for (int i = 0; i < nstages-1; i++) {
722                     fBody[i].next = enum_to_Fn<Body>(stages[i+1].stage);
723                     fTail[i].next = enum_to_Fn<Tail>(stages[i+1].stage);
724                     fBody[i].ctx = fTail[i].ctx = stages[i].ctx;
725                 }
726                 fBody[nstages-1].next = just_return;
727                 fTail[nstages-1].next = just_return;
728                 fBody[nstages-1].ctx = fTail[nstages-1].ctx = stages[nstages-1].ctx;
729             }
730
731             void operator()(size_t x, size_t y, size_t n) {
732 #ifdef SK_BUILD_FOR_WINRT
733                 SkNf v = SkNf();  // gives uninitialized variable 'v' on ARM
734 #else
735                 SkNf v;  // Fastest to start uninitialized.
736 #endif
737
738                 float dx[] = { 0,1,2,3,4,5,6,7 };
739                 SkNf X = SkNf(x) + SkNf::Load(dx) + 0.5f,
740                      Y = SkNf(y) + 0.5f;
741
742                 while (n >= N) {
743                     fBodyStart(fBody, x, v,v,v,v, X,Y,v,v);
744                     X += (float)N;
745                     x += N;
746                     n -= N;
747                 }
748                 if (n) {
749                     fTailStart(fTail, x,n, v,v,v,v, X,Y,v,v);
750                 }
751             }
752
753             Body fBodyStart = just_return;
754             Tail fTailStart = just_return;
755
756             BodyStage fBody[SkRasterPipeline::kMaxStages];
757             TailStage fTail[SkRasterPipeline::kMaxStages];
758
759         } fn { stages, nstages };
760         return fn;
761     }
762
763 }  // namespace SK_OPTS_NS
764
765 #undef SI
766 #undef STAGE
767 #undef RGBA_XFERMODE
768 #undef RGB_XFERMODE
769
770 #endif//SkRasterPipeline_opts_DEFINED