blob: f17d7ac3d91636761c2a80ad3b039f207abed6e7 [file] [log] [blame]
Mike Kleinbaaf8ad2016-09-29 09:04:15 -04001/*
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
Mike Klein1f49f262016-10-31 19:49:27 -040011#include "SkColorPriv.h"
raftias25636012016-11-11 15:27:39 -080012#include "SkColorLookUpTable.h"
Matt Sarettdb4d4062016-11-16 16:07:15 -050013#include "SkColorSpaceXform_A2B.h"
14#include "SkColorSpaceXformPriv.h"
Mike Kleinbaaf8ad2016-09-29 09:04:15 -040015#include "SkHalf.h"
Mike Klein46e66a22016-11-21 16:19:34 -050016#include "SkImageShaderContext.h"
Mike Kleinbaaf8ad2016-09-29 09:04:15 -040017#include "SkPM4f.h"
mtklein125b2aa2016-11-04 13:41:34 -070018#include "SkPM4fPriv.h"
Mike Kleinbaaf8ad2016-09-29 09:04:15 -040019#include "SkRasterPipeline.h"
20#include "SkSRGB.h"
mtklein125b2aa2016-11-04 13:41:34 -070021#include "SkUtils.h"
Mike Klein2878e762016-10-19 21:05:17 -040022#include <utility>
Mike Kleinbaaf8ad2016-09-29 09:04:15 -040023
Mike Kleinaebfb452016-10-25 10:27:33 -040024namespace {
25
Mike Klein2878e762016-10-19 21:05:17 -040026#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2
27 static constexpr int N = 8;
28#else
29 static constexpr int N = 4;
30#endif
31
mtkleina4a44882016-11-04 13:20:07 -070032 using SkNf = SkNx<N, float>;
33 using SkNi = SkNx<N, int>;
34 using SkNh = SkNx<N, uint16_t>;
Mike Klein06a65e22016-11-17 12:39:09 -050035 using SkNb = SkNx<N, uint8_t>;
Mike Kleinbaaf8ad2016-09-29 09:04:15 -040036
Mike Kleinaebfb452016-10-25 10:27:33 -040037 struct BodyStage;
38 struct TailStage;
39
40 using Body = void(SK_VECTORCALL *)(BodyStage*, size_t, SkNf,SkNf,SkNf,SkNf,
41 SkNf,SkNf,SkNf,SkNf);
42 using Tail = void(SK_VECTORCALL *)(TailStage*, size_t, size_t, SkNf,SkNf,SkNf,SkNf,
43 SkNf,SkNf,SkNf,SkNf);
44 struct BodyStage { Body next; void* ctx; };
45 struct TailStage { Tail next; void* ctx; };
46
47} // namespace
Mike Klein2878e762016-10-19 21:05:17 -040048
Mike Klein04adfda2016-10-12 09:52:55 -040049#define SI static inline
Mike Kleinbaaf8ad2016-09-29 09:04:15 -040050
Mike Klein49372e62016-10-20 18:05:23 -040051// Stages are logically a pipeline, and physically are contiguous in an array.
52// To get to the next stage, we just increment our pointer to the next array element.
Mike Kleinaebfb452016-10-25 10:27:33 -040053SI void SK_VECTORCALL next(BodyStage* st, size_t x,
54 SkNf r, SkNf g, SkNf b, SkNf a,
55 SkNf dr, SkNf dg, SkNf db, SkNf da) {
56 st->next(st+1, x, r,g,b,a, dr,dg,db,da);
Mike Klein2878e762016-10-19 21:05:17 -040057}
Mike Kleinaebfb452016-10-25 10:27:33 -040058SI void SK_VECTORCALL next(TailStage* st, size_t x, size_t tail,
59 SkNf r, SkNf g, SkNf b, SkNf a,
60 SkNf dr, SkNf dg, SkNf db, SkNf da) {
61 st->next(st+1, x,tail, r,g,b,a, dr,dg,db,da);
Mike Klein49372e62016-10-20 18:05:23 -040062}
63
Mike Klein2878e762016-10-19 21:05:17 -040064
Mike Kleinaebfb452016-10-25 10:27:33 -040065#define STAGE(name, kCallNext) \
66 template <bool kIsTail> \
67 static SK_ALWAYS_INLINE void name##_kernel(void* ctx, size_t x, size_t tail, \
68 SkNf& r, SkNf& g, SkNf& b, SkNf& a, \
69 SkNf& dr, SkNf& dg, SkNf& db, SkNf& da); \
70 SI void SK_VECTORCALL name(BodyStage* st, size_t x, \
71 SkNf r, SkNf g, SkNf b, SkNf a, \
72 SkNf dr, SkNf dg, SkNf db, SkNf da) { \
73 name##_kernel<false>(st->ctx, x,0, r,g,b,a, dr,dg,db,da); \
74 if (kCallNext) { \
75 next(st, x, r,g,b,a, dr,dg,db,da); \
76 } \
77 } \
78 SI void SK_VECTORCALL name(TailStage* st, size_t x, size_t tail, \
79 SkNf r, SkNf g, SkNf b, SkNf a, \
80 SkNf dr, SkNf dg, SkNf db, SkNf da) { \
81 name##_kernel<true>(st->ctx, x,tail, r,g,b,a, dr,dg,db,da); \
82 if (kCallNext) { \
83 next(st, x,tail, r,g,b,a, dr,dg,db,da); \
84 } \
85 } \
86 template <bool kIsTail> \
87 static SK_ALWAYS_INLINE void name##_kernel(void* ctx, size_t x, size_t tail, \
88 SkNf& r, SkNf& g, SkNf& b, SkNf& a, \
Mike Klein04adfda2016-10-12 09:52:55 -040089 SkNf& dr, SkNf& dg, SkNf& db, SkNf& da)
Mike Kleinbaaf8ad2016-09-29 09:04:15 -040090
Mike Kleinbaaf8ad2016-09-29 09:04:15 -040091
Mike Klein9161ef02016-10-04 14:03:27 -040092// Many xfermodes apply the same logic to each channel.
Mike Kleinaebfb452016-10-25 10:27:33 -040093#define RGBA_XFERMODE(name) \
94 static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa, \
95 const SkNf& d, const SkNf& da); \
96 SI void SK_VECTORCALL name(BodyStage* st, size_t x, \
97 SkNf r, SkNf g, SkNf b, SkNf a, \
98 SkNf dr, SkNf dg, SkNf db, SkNf da) { \
99 r = name##_kernel(r,a,dr,da); \
100 g = name##_kernel(g,a,dg,da); \
101 b = name##_kernel(b,a,db,da); \
102 a = name##_kernel(a,a,da,da); \
103 next(st, x, r,g,b,a, dr,dg,db,da); \
104 } \
105 SI void SK_VECTORCALL name(TailStage* st, size_t x, size_t tail, \
106 SkNf r, SkNf g, SkNf b, SkNf a, \
107 SkNf dr, SkNf dg, SkNf db, SkNf da) { \
108 r = name##_kernel(r,a,dr,da); \
109 g = name##_kernel(g,a,dg,da); \
110 b = name##_kernel(b,a,db,da); \
111 a = name##_kernel(a,a,da,da); \
112 next(st, x,tail, r,g,b,a, dr,dg,db,da); \
113 } \
114 static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa, \
Mike Klein04adfda2016-10-12 09:52:55 -0400115 const SkNf& d, const SkNf& da)
Mike Klein9161ef02016-10-04 14:03:27 -0400116
117// Most of the rest apply the same logic to color channels and use srcover's alpha logic.
Mike Kleinaebfb452016-10-25 10:27:33 -0400118#define RGB_XFERMODE(name) \
119 static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa, \
120 const SkNf& d, const SkNf& da); \
121 SI void SK_VECTORCALL name(BodyStage* st, size_t x, \
122 SkNf r, SkNf g, SkNf b, SkNf a, \
123 SkNf dr, SkNf dg, SkNf db, SkNf da) { \
124 r = name##_kernel(r,a,dr,da); \
125 g = name##_kernel(g,a,dg,da); \
126 b = name##_kernel(b,a,db,da); \
127 a = a + (da * (1.0f-a)); \
128 next(st, x, r,g,b,a, dr,dg,db,da); \
129 } \
130 SI void SK_VECTORCALL name(TailStage* st, size_t x, size_t tail, \
131 SkNf r, SkNf g, SkNf b, SkNf a, \
132 SkNf dr, SkNf dg, SkNf db, SkNf da) { \
133 r = name##_kernel(r,a,dr,da); \
134 g = name##_kernel(g,a,dg,da); \
135 b = name##_kernel(b,a,db,da); \
136 a = a + (da * (1.0f-a)); \
137 next(st, x,tail, r,g,b,a, dr,dg,db,da); \
138 } \
139 static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa, \
Mike Klein04adfda2016-10-12 09:52:55 -0400140 const SkNf& d, const SkNf& da)
141
Mike Kleinaebfb452016-10-25 10:27:33 -0400142SI SkNf inv(const SkNf& x) { return 1.0f - x; }
143
144SI SkNf lerp(const SkNf& from, const SkNf& to, const SkNf& cov) {
145 return SkNx_fma(to-from, cov, from);
146}
147
148template <bool kIsTail, typename T>
149SI SkNx<N,T> load(size_t tail, const T* src) {
150 SkASSERT(kIsTail == (tail > 0));
151 // TODO: maskload for 32- and 64-bit T
152 if (kIsTail) {
153 T buf[8] = {0};
154 switch (tail & (N-1)) {
155 case 7: buf[6] = src[6];
156 case 6: buf[5] = src[5];
157 case 5: buf[4] = src[4];
158 case 4: buf[3] = src[3];
159 case 3: buf[2] = src[2];
160 case 2: buf[1] = src[1];
161 }
162 buf[0] = src[0];
163 return SkNx<N,T>::Load(buf);
164 }
165 return SkNx<N,T>::Load(src);
166}
167
168template <bool kIsTail, typename T>
169SI void store(size_t tail, const SkNx<N,T>& v, T* dst) {
170 SkASSERT(kIsTail == (tail > 0));
171 // TODO: maskstore for 32- and 64-bit T
172 if (kIsTail) {
173 switch (tail & (N-1)) {
174 case 7: dst[6] = v[6];
175 case 6: dst[5] = v[5];
176 case 5: dst[4] = v[4];
177 case 4: dst[3] = v[3];
178 case 3: dst[2] = v[2];
179 case 2: dst[1] = v[1];
180 }
181 dst[0] = v[0];
182 return;
183 }
184 v.store(dst);
185}
186
187SI void from_565(const SkNh& _565, SkNf* r, SkNf* g, SkNf* b) {
188 auto _32_bit = SkNx_cast<int>(_565);
189
190 *r = SkNx_cast<float>(_32_bit & SK_R16_MASK_IN_PLACE) * (1.0f / SK_R16_MASK_IN_PLACE);
191 *g = SkNx_cast<float>(_32_bit & SK_G16_MASK_IN_PLACE) * (1.0f / SK_G16_MASK_IN_PLACE);
192 *b = SkNx_cast<float>(_32_bit & SK_B16_MASK_IN_PLACE) * (1.0f / SK_B16_MASK_IN_PLACE);
193}
194
195SI SkNh to_565(const SkNf& r, const SkNf& g, const SkNf& b) {
196 return SkNx_cast<uint16_t>( SkNx_cast<int>(r * SK_R16_MASK + 0.5f) << SK_R16_SHIFT
197 | SkNx_cast<int>(g * SK_G16_MASK + 0.5f) << SK_G16_SHIFT
198 | SkNx_cast<int>(b * SK_B16_MASK + 0.5f) << SK_B16_SHIFT);
199}
200
201STAGE(just_return, false) { }
202
Mike Kleina9312fd2016-11-16 13:38:15 -0500203STAGE(trace, true) {
204 SkDebugf("%s\n", (const char*)ctx);
205}
206
207STAGE(registers, true) {
208 auto print = [](const char* name, const SkNf& v) {
209 SkDebugf("%s:", name);
210 for (int i = 0; i < N; i++) {
211 SkDebugf(" %g", v[i]);
212 }
213 SkDebugf("\n");
214 };
215 print(" r", r);
216 print(" g", g);
217 print(" b", b);
218 print(" a", a);
219 print("dr", dr);
220 print("dg", dg);
221 print("db", db);
222 print("da", da);
223}
224
Mike Klein130863e2016-10-27 11:29:36 -0400225STAGE(clamp_0, true) {
226 a = SkNf::Max(a, 0.0f);
227 r = SkNf::Max(r, 0.0f);
228 g = SkNf::Max(g, 0.0f);
229 b = SkNf::Max(b, 0.0f);
230}
Mike Klein130863e2016-10-27 11:29:36 -0400231
Mike Kleineea7c162016-11-03 10:20:35 -0400232STAGE(clamp_a, true) {
Mike Klein130863e2016-10-27 11:29:36 -0400233 a = SkNf::Min(a, 1.0f);
234 r = SkNf::Min(r, a);
235 g = SkNf::Min(g, a);
236 b = SkNf::Min(b, a);
237}
238
Matt Sarettdb4d4062016-11-16 16:07:15 -0500239STAGE(clamp_1, true) {
240 a = SkNf::Min(a, 1.0f);
241 r = SkNf::Min(r, 1.0f);
242 g = SkNf::Min(g, 1.0f);
243 b = SkNf::Min(b, 1.0f);
244}
245
Mike Kleineea7c162016-11-03 10:20:35 -0400246STAGE(unpremul, true) {
247 r *= a.invert();
248 g *= a.invert();
249 b *= a.invert();
250}
251
252STAGE(premul, true) {
253 r *= a;
254 g *= a;
255 b *= a;
256}
257
Mike Kleinc5093412016-11-04 16:36:39 -0400258STAGE(move_src_dst, true) {
259 dr = r;
260 dg = g;
261 db = b;
262 da = a;
Mike Kleinaebfb452016-10-25 10:27:33 -0400263}
264
Mike Kleinfb191da2016-11-15 13:20:33 -0500265STAGE(swap_src_dst, true) {
266 SkTSwap(r, dr);
267 SkTSwap(g, dg);
268 SkTSwap(b, db);
269 SkTSwap(a, da);
270}
271
Mike Kleinaebfb452016-10-25 10:27:33 -0400272// The default shader produces a constant color (from the SkPaint).
273STAGE(constant_color, true) {
274 auto color = (const SkPM4f*)ctx;
275 r = color->r();
276 g = color->g();
277 b = color->b();
278 a = color->a();
279}
280
Mike Klein66866172016-11-03 12:22:01 -0400281// s' = sc for a constant c.
282STAGE(scale_constant_float, true) {
283 SkNf c = *(const float*)ctx;
284
285 r *= c;
286 g *= c;
287 b *= c;
288 a *= c;
289}
290
Mike Kleinaebfb452016-10-25 10:27:33 -0400291// s' = d(1-c) + sc, for a constant c.
292STAGE(lerp_constant_float, true) {
293 SkNf c = *(const float*)ctx;
294
295 r = lerp(dr, r, c);
296 g = lerp(dg, g, c);
297 b = lerp(db, b, c);
298 a = lerp(da, a, c);
299}
300
301// s' = sc for 8-bit c.
302STAGE(scale_u8, true) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400303 auto ptr = *(const uint8_t**)ctx + x;
Mike Kleinaebfb452016-10-25 10:27:33 -0400304
305 SkNf c = SkNx_cast<float>(load<kIsTail>(tail, ptr)) * (1/255.0f);
306 r = r*c;
307 g = g*c;
308 b = b*c;
309 a = a*c;
310}
311
312// s' = d(1-c) + sc for 8-bit c.
313STAGE(lerp_u8, true) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400314 auto ptr = *(const uint8_t**)ctx + x;
Mike Kleinaebfb452016-10-25 10:27:33 -0400315
316 SkNf c = SkNx_cast<float>(load<kIsTail>(tail, ptr)) * (1/255.0f);
317 r = lerp(dr, r, c);
318 g = lerp(dg, g, c);
319 b = lerp(db, b, c);
320 a = lerp(da, a, c);
321}
322
323// s' = d(1-c) + sc for 565 c.
324STAGE(lerp_565, true) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400325 auto ptr = *(const uint16_t**)ctx + x;
Mike Kleinaebfb452016-10-25 10:27:33 -0400326 SkNf cr, cg, cb;
327 from_565(load<kIsTail>(tail, ptr), &cr, &cg, &cb);
328
329 r = lerp(dr, r, cr);
330 g = lerp(dg, g, cg);
331 b = lerp(db, b, cb);
332 a = 1.0f;
333}
334
335STAGE(load_d_565, true) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400336 auto ptr = *(const uint16_t**)ctx + x;
Mike Kleinaebfb452016-10-25 10:27:33 -0400337 from_565(load<kIsTail>(tail, ptr), &dr,&dg,&db);
338 da = 1.0f;
339}
340
341STAGE(load_s_565, true) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400342 auto ptr = *(const uint16_t**)ctx + x;
Mike Kleinaebfb452016-10-25 10:27:33 -0400343 from_565(load<kIsTail>(tail, ptr), &r,&g,&b);
344 a = 1.0f;
345}
346
347STAGE(store_565, false) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400348 auto ptr = *(uint16_t**)ctx + x;
Mike Kleinaebfb452016-10-25 10:27:33 -0400349 store<kIsTail>(tail, to_565(r,g,b), ptr);
350}
351
352STAGE(load_d_f16, true) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400353 auto ptr = *(const uint64_t**)ctx + x;
Mike Kleinaebfb452016-10-25 10:27:33 -0400354
355 SkNh rh, gh, bh, ah;
356 if (kIsTail) {
357 uint64_t buf[8] = {0};
358 switch (tail & (N-1)) {
359 case 7: buf[6] = ptr[6];
360 case 6: buf[5] = ptr[5];
361 case 5: buf[4] = ptr[4];
362 case 4: buf[3] = ptr[3];
363 case 3: buf[2] = ptr[2];
364 case 2: buf[1] = ptr[1];
365 }
366 buf[0] = ptr[0];
367 SkNh::Load4(buf, &rh, &gh, &bh, &ah);
368 } else {
369 SkNh::Load4(ptr, &rh, &gh, &bh, &ah);
370 }
371
372 dr = SkHalfToFloat_finite_ftz(rh);
373 dg = SkHalfToFloat_finite_ftz(gh);
374 db = SkHalfToFloat_finite_ftz(bh);
375 da = SkHalfToFloat_finite_ftz(ah);
376}
377
378STAGE(load_s_f16, true) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400379 auto ptr = *(const uint64_t**)ctx + x;
Mike Kleinaebfb452016-10-25 10:27:33 -0400380
381 SkNh rh, gh, bh, ah;
382 if (kIsTail) {
383 uint64_t buf[8] = {0};
384 switch (tail & (N-1)) {
385 case 7: buf[6] = ptr[6];
386 case 6: buf[5] = ptr[5];
387 case 5: buf[4] = ptr[4];
388 case 4: buf[3] = ptr[3];
389 case 3: buf[2] = ptr[2];
390 case 2: buf[1] = ptr[1];
391 }
392 buf[0] = ptr[0];
393 SkNh::Load4(buf, &rh, &gh, &bh, &ah);
394 } else {
395 SkNh::Load4(ptr, &rh, &gh, &bh, &ah);
396 }
397
398 r = SkHalfToFloat_finite_ftz(rh);
399 g = SkHalfToFloat_finite_ftz(gh);
400 b = SkHalfToFloat_finite_ftz(bh);
401 a = SkHalfToFloat_finite_ftz(ah);
402}
403
404STAGE(store_f16, false) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400405 auto ptr = *(uint64_t**)ctx + x;
Mike Kleinaebfb452016-10-25 10:27:33 -0400406
407 uint64_t buf[8];
408 SkNh::Store4(kIsTail ? buf : ptr, SkFloatToHalf_finite_ftz(r),
409 SkFloatToHalf_finite_ftz(g),
410 SkFloatToHalf_finite_ftz(b),
411 SkFloatToHalf_finite_ftz(a));
412 if (kIsTail) {
413 switch (tail & (N-1)) {
414 case 7: ptr[6] = buf[6];
415 case 6: ptr[5] = buf[5];
416 case 5: ptr[4] = buf[4];
417 case 4: ptr[3] = buf[3];
418 case 3: ptr[2] = buf[2];
419 case 2: ptr[1] = buf[1];
420 }
421 ptr[0] = buf[0];
422 }
423}
424
mtkleina4a44882016-11-04 13:20:07 -0700425STAGE(store_f32, false) {
426 auto ptr = *(SkPM4f**)ctx + x;
427
428 SkPM4f buf[8];
429 SkNf::Store4(kIsTail ? buf : ptr, r,g,b,a);
430 if (kIsTail) {
431 switch (tail & (N-1)) {
432 case 7: ptr[6] = buf[6];
433 case 6: ptr[5] = buf[5];
434 case 5: ptr[4] = buf[4];
435 case 4: ptr[3] = buf[3];
436 case 3: ptr[2] = buf[2];
437 case 2: ptr[1] = buf[1];
438 }
439 ptr[0] = buf[0];
440 }
441}
442
Mike Kleinaebfb452016-10-25 10:27:33 -0400443
444// Load 8-bit SkPMColor-order sRGB.
445STAGE(load_d_srgb, true) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400446 auto ptr = *(const uint32_t**)ctx + x;
Mike Kleinaebfb452016-10-25 10:27:33 -0400447
448 auto px = load<kIsTail>(tail, ptr);
449 auto to_int = [](const SkNx<N, uint32_t>& v) { return SkNi::Load(&v); };
450 dr = sk_linear_from_srgb_math(to_int((px >> SK_R32_SHIFT) & 0xff));
451 dg = sk_linear_from_srgb_math(to_int((px >> SK_G32_SHIFT) & 0xff));
452 db = sk_linear_from_srgb_math(to_int((px >> SK_B32_SHIFT) & 0xff));
453 da = (1/255.0f)*SkNx_cast<float>(to_int( px >> SK_A32_SHIFT ));
454}
455
456STAGE(load_s_srgb, true) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400457 auto ptr = *(const uint32_t**)ctx + x;
Mike Kleinaebfb452016-10-25 10:27:33 -0400458
459 auto px = load<kIsTail>(tail, ptr);
460 auto to_int = [](const SkNx<N, uint32_t>& v) { return SkNi::Load(&v); };
461 r = sk_linear_from_srgb_math(to_int((px >> SK_R32_SHIFT) & 0xff));
462 g = sk_linear_from_srgb_math(to_int((px >> SK_G32_SHIFT) & 0xff));
463 b = sk_linear_from_srgb_math(to_int((px >> SK_B32_SHIFT) & 0xff));
464 a = (1/255.0f)*SkNx_cast<float>(to_int( px >> SK_A32_SHIFT ));
465}
466
467STAGE(store_srgb, false) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400468 auto ptr = *(uint32_t**)ctx + x;
Mike Klein6b059bd2016-11-02 14:47:07 -0400469 store<kIsTail>(tail, ( sk_linear_to_srgb(r) << SK_R32_SHIFT
470 | sk_linear_to_srgb(g) << SK_G32_SHIFT
471 | sk_linear_to_srgb(b) << SK_B32_SHIFT
472 | SkNx_cast<int>(0.5f + 255.0f * a) << SK_A32_SHIFT), (int*)ptr);
Mike Kleinaebfb452016-10-25 10:27:33 -0400473}
474
raftias25636012016-11-11 15:27:39 -0800475STAGE(load_s_8888, true) {
476 auto ptr = *(const uint32_t**)ctx + x;
477
478 auto px = load<kIsTail>(tail, ptr);
479 auto to_int = [](const SkNx<N, uint32_t>& v) { return SkNi::Load(&v); };
480 r = (1/255.0f)*SkNx_cast<float>(to_int((px >> 0) & 0xff));
481 g = (1/255.0f)*SkNx_cast<float>(to_int((px >> 8) & 0xff));
482 b = (1/255.0f)*SkNx_cast<float>(to_int((px >> 16) & 0xff));
483 a = (1/255.0f)*SkNx_cast<float>(to_int(px >> 24));
484}
485
486STAGE(store_8888, false) {
487 auto ptr = *(uint32_t**)ctx + x;
488 store<kIsTail>(tail, ( SkNx_cast<int>(255.0f * r + 0.5f) << 0
489 | SkNx_cast<int>(255.0f * g + 0.5f) << 8
490 | SkNx_cast<int>(255.0f * b + 0.5f) << 16
491 | SkNx_cast<int>(255.0f * a + 0.5f) << 24 ), (int*)ptr);
492}
493
Mike Kleinaebfb452016-10-25 10:27:33 -0400494RGBA_XFERMODE(clear) { return 0.0f; }
495//RGBA_XFERMODE(src) { return s; } // This would be a no-op stage, so we just omit it.
496RGBA_XFERMODE(dst) { return d; }
497
498RGBA_XFERMODE(srcatop) { return s*da + d*inv(sa); }
499RGBA_XFERMODE(srcin) { return s * da; }
500RGBA_XFERMODE(srcout) { return s * inv(da); }
501RGBA_XFERMODE(srcover) { return SkNx_fma(d, inv(sa), s); }
502RGBA_XFERMODE(dstatop) { return srcatop_kernel(d,da,s,sa); }
503RGBA_XFERMODE(dstin) { return srcin_kernel (d,da,s,sa); }
504RGBA_XFERMODE(dstout) { return srcout_kernel (d,da,s,sa); }
505RGBA_XFERMODE(dstover) { return srcover_kernel(d,da,s,sa); }
506
507RGBA_XFERMODE(modulate) { return s*d; }
508RGBA_XFERMODE(multiply) { return s*inv(da) + d*inv(sa) + s*d; }
509RGBA_XFERMODE(plus_) { return s + d; }
510RGBA_XFERMODE(screen) { return s + d - s*d; }
511RGBA_XFERMODE(xor_) { return s*inv(da) + d*inv(sa); }
512
513RGB_XFERMODE(colorburn) {
514 return (d == da ).thenElse(d + s*inv(da),
515 (s == 0.0f).thenElse(s + d*inv(sa),
516 sa*(da - SkNf::Min(da, (da-d)*sa/s)) + s*inv(da) + d*inv(sa)));
517}
518RGB_XFERMODE(colordodge) {
519 return (d == 0.0f).thenElse(d + s*inv(da),
520 (s == sa ).thenElse(s + d*inv(sa),
521 sa*SkNf::Min(da, (d*sa)/(sa - s)) + s*inv(da) + d*inv(sa)));
522}
523RGB_XFERMODE(darken) { return s + d - SkNf::Max(s*da, d*sa); }
524RGB_XFERMODE(difference) { return s + d - 2.0f*SkNf::Min(s*da,d*sa); }
525RGB_XFERMODE(exclusion) { return s + d - 2.0f*s*d; }
526RGB_XFERMODE(hardlight) {
527 return s*inv(da) + d*inv(sa)
528 + (2.0f*s <= sa).thenElse(2.0f*s*d, sa*da - 2.0f*(da-d)*(sa-s));
529}
530RGB_XFERMODE(lighten) { return s + d - SkNf::Min(s*da, d*sa); }
531RGB_XFERMODE(overlay) { return hardlight_kernel(d,da,s,sa); }
532RGB_XFERMODE(softlight) {
533 SkNf m = (da > 0.0f).thenElse(d / da, 0.0f),
534 s2 = 2.0f*s,
535 m4 = 4.0f*m;
536
537 // The logic forks three ways:
538 // 1. dark src?
539 // 2. light src, dark dst?
540 // 3. light src, light dst?
541 SkNf darkSrc = d*(sa + (s2 - sa)*(1.0f - m)), // Used in case 1.
542 darkDst = (m4*m4 + m4)*(m - 1.0f) + 7.0f*m, // Used in case 2.
543 liteDst = m.rsqrt().invert() - m, // Used in case 3.
544 liteSrc = d*sa + da*(s2 - sa) * (4.0f*d <= da).thenElse(darkDst, liteDst); // 2 or 3?
545 return s*inv(da) + d*inv(sa) + (s2 <= sa).thenElse(darkSrc, liteSrc); // 1 or (2 or 3)?
546}
547
Mike Klein1f49f262016-10-31 19:49:27 -0400548STAGE(luminance_to_alpha, true) {
549 a = SK_LUM_COEFF_R*r + SK_LUM_COEFF_G*g + SK_LUM_COEFF_B*b;
550 r = g = b = 0;
551}
552
Mike Klein06a65e22016-11-17 12:39:09 -0500553STAGE(matrix_2x3, true) {
554 auto m = (const float*)ctx;
555
556 auto fma = [](const SkNf& f, const SkNf& m, const SkNf& a) { return SkNx_fma(f,m,a); };
557 auto R = fma(r,m[0], fma(g,m[2], m[4])),
558 G = fma(r,m[1], fma(g,m[3], m[5]));
559 r = R;
560 g = G;
561}
562
raftias25636012016-11-11 15:27:39 -0800563STAGE(matrix_3x4, 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[3], fma(b,m[6], m[ 9]))),
568 G = fma(r,m[1], fma(g,m[4], fma(b,m[7], m[10]))),
569 B = fma(r,m[2], fma(g,m[5], fma(b,m[8], m[11])));
570 r = R;
571 g = G;
572 b = B;
573}
574
Mike Kleineea7c162016-11-03 10:20:35 -0400575STAGE(matrix_4x5, true) {
576 auto m = (const float*)ctx;
577
578 auto fma = [](const SkNf& f, const SkNf& m, const SkNf& a) { return SkNx_fma(f,m,a); };
579 auto R = fma(r,m[0], fma(g,m[4], fma(b,m[ 8], fma(a,m[12], m[16])))),
580 G = fma(r,m[1], fma(g,m[5], fma(b,m[ 9], fma(a,m[13], m[17])))),
581 B = fma(r,m[2], fma(g,m[6], fma(b,m[10], fma(a,m[14], m[18])))),
582 A = fma(r,m[3], fma(g,m[7], fma(b,m[11], fma(a,m[15], m[19]))));
583 r = R;
584 g = G;
585 b = B;
586 a = A;
587}
Mike Kleinaebfb452016-10-25 10:27:33 -0400588
Mike Kleinc01e7df2016-11-17 16:27:10 -0500589STAGE(matrix_perspective, true) {
590 // N.B. unlike the matrix_NxM stages, this takes a row-major matrix.
591 auto m = (const float*)ctx;
592
593 auto fma = [](const SkNf& f, const SkNf& m, const SkNf& a) { return SkNx_fma(f,m,a); };
594 auto R = fma(r,m[0], fma(g,m[1], m[2])),
595 G = fma(r,m[3], fma(g,m[4], m[5])),
596 Z = fma(r,m[6], fma(g,m[7], m[8]));
597 r = R * Z.invert();
598 g = G * Z.invert();
599}
600
601
Mike Kleincfcf6242016-11-16 09:01:30 -0500602SI SkNf parametric(const SkNf& v, const SkColorSpaceTransferFn& p) {
603 float result[N]; // Unconstrained powf() doesn't vectorize well...
604 for (int i = 0; i < N; i++) {
605 float s = v[i];
606 result[i] = (s <= p.fD) ? p.fE * s + p.fF
607 : powf(s * p.fA + p.fB, p.fG) + p.fC;
608 }
609 return SkNf::Load(result);
610}
611
612STAGE(parametric_r, true) {
613 r = parametric(r, *(const SkColorSpaceTransferFn*)ctx);
614}
615STAGE(parametric_g, true) {
616 g = parametric(g, *(const SkColorSpaceTransferFn*)ctx);
617}
618STAGE(parametric_b, true) {
619 b = parametric(b, *(const SkColorSpaceTransferFn*)ctx);
620}
621
Matt Sarettdb4d4062016-11-16 16:07:15 -0500622SI SkNf table(const SkNf& v, const SkTableTransferFn& table) {
623 float result[N];
Mike Kleincfcf6242016-11-16 09:01:30 -0500624 for (int i = 0; i < N; i++) {
Matt Sarettdb4d4062016-11-16 16:07:15 -0500625 result[i] = interp_lut(v[i], table.fData, table.fSize);
Mike Kleincfcf6242016-11-16 09:01:30 -0500626 }
627 return SkNf::Load(result);
628}
629
630STAGE(table_r, true) {
Matt Sarettdb4d4062016-11-16 16:07:15 -0500631 r = table(r, *(const SkTableTransferFn*)ctx);
Mike Kleincfcf6242016-11-16 09:01:30 -0500632}
633STAGE(table_g, true) {
Matt Sarettdb4d4062016-11-16 16:07:15 -0500634 g = table(g, *(const SkTableTransferFn*)ctx);
Mike Kleincfcf6242016-11-16 09:01:30 -0500635}
636STAGE(table_b, true) {
Matt Sarettdb4d4062016-11-16 16:07:15 -0500637 b = table(b, *(const SkTableTransferFn*)ctx);
raftias25636012016-11-11 15:27:39 -0800638}
639
640STAGE(color_lookup_table, true) {
641 const SkColorLookUpTable* colorLUT = (const SkColorLookUpTable*)ctx;
642 float rgb[3];
643 float result[3][N];
644 for (int i = 0; i < N; ++i) {
645 rgb[0] = r[i];
646 rgb[1] = g[i];
647 rgb[2] = b[i];
648 colorLUT->interp3D(rgb, rgb);
649 result[0][i] = rgb[0];
650 result[1][i] = rgb[1];
651 result[2][i] = rgb[2];
652 }
653 r = SkNf::Load(result[0]);
654 g = SkNf::Load(result[1]);
655 b = SkNf::Load(result[2]);
656}
657
658STAGE(lab_to_xyz, true) {
659 const auto lab_l = r * 100.0f;
660 const auto lab_a = g * 255.0f - 128.0f;
661 const auto lab_b = b * 255.0f - 128.0f;
662 auto Y = (lab_l + 16.0f) * (1/116.0f);
663 auto X = lab_a * (1/500.0f) + Y;
664 auto Z = Y - (lab_b * (1/200.0f));
665
666 const auto X3 = X*X*X;
667 X = (X3 > 0.008856f).thenElse(X3, (X - (16/116.0f)) * (1/7.787f));
668 const auto Y3 = Y*Y*Y;
669 Y = (Y3 > 0.008856f).thenElse(Y3, (Y - (16/116.0f)) * (1/7.787f));
670 const auto Z3 = Z*Z*Z;
671 Z = (Z3 > 0.008856f).thenElse(Z3, (Z - (16/116.0f)) * (1/7.787f));
672
673 // adjust to D50 illuminant
674 X *= 0.96422f;
675 Y *= 1.00000f;
676 Z *= 0.82521f;
677
678 r = X;
679 g = Y;
680 b = Z;
681}
682
683STAGE(swap_rb, true) {
684 SkTSwap(r, b);
685}
686
Mike Kleinb273fc42016-11-17 15:42:22 -0500687SI SkNf assert_in_tile(const SkNf& v, float limit) {
688 for (int i = 0; i < N; i++) {
689 SkASSERT(0 <= v[i] && v[i] < limit);
690 }
691 return v;
Mike Klein06a65e22016-11-17 12:39:09 -0500692}
Mike Kleinb273fc42016-11-17 15:42:22 -0500693
694SI SkNf clamp(const SkNf& v, float limit) {
695 SkNf result = SkNf::Max(0, SkNf::Min(v, limit - 0.5f));
696 return assert_in_tile(result, limit);
Mike Klein06a65e22016-11-17 12:39:09 -0500697}
698
Mike Kleinb273fc42016-11-17 15:42:22 -0500699SI SkNf repeat(const SkNf& v, float limit) {
700 SkNf result = v - (v/limit).floor()*limit;
Mike Kleinb273fc42016-11-17 15:42:22 -0500701 // For small negative v, (v/limit).floor()*limit can dominate v in the subtraction,
702 // which leaves result == limit. We want result < limit, so clamp it one ULP.
703 result = SkNf::Min(result, nextafterf(limit, 0));
Mike Kleinb273fc42016-11-17 15:42:22 -0500704 return assert_in_tile(result, limit);
705}
706
Mike Klein2e35e8a2016-11-18 15:47:22 -0500707SI SkNf mirror(const SkNf& v, float l/*imit*/) {
708 SkNf result = ((v - l) - ((v - l) / (2*l)).floor()*(2*l) - l).abs();
709 // Same deal as repeat.
710 result = SkNf::Min(result, nextafterf(l, 0));
711 return assert_in_tile(result, l);
712}
713
Mike Kleinb273fc42016-11-17 15:42:22 -0500714STAGE(clamp_x, true) { r = clamp (r, *(const int*)ctx); }
715STAGE(clamp_y, true) { g = clamp (g, *(const int*)ctx); }
716STAGE(repeat_x, true) { r = repeat(r, *(const int*)ctx); }
717STAGE(repeat_y, true) { g = repeat(g, *(const int*)ctx); }
Mike Klein2e35e8a2016-11-18 15:47:22 -0500718STAGE(mirror_x, true) { r = mirror(r, *(const int*)ctx); }
719STAGE(mirror_y, true) { g = mirror(g, *(const int*)ctx); }
Mike Klein06a65e22016-11-17 12:39:09 -0500720
Mike Klein46e66a22016-11-21 16:19:34 -0500721STAGE(top_left, true) {
722 auto sc = (SkImageShaderContext*)ctx;
Mike Klein06a65e22016-11-17 12:39:09 -0500723
Mike Klein46e66a22016-11-21 16:19:34 -0500724 r.store(sc->x);
725 g.store(sc->y);
726
727 r -= 0.5f;
728 g -= 0.5f;
729
730 auto fx = r - r.floor(),
731 fy = g - g.floor();
732 b = (1.0f - fx) * (1.0f - fy);
733};
734
735STAGE(top_right, true) {
736 auto sc = (const SkImageShaderContext*)ctx;
737
738 r = SkNf::Load(sc->x) + 0.5f;
739 g = SkNf::Load(sc->y) - 0.5f;
740
741 auto fx = r - r.floor(),
742 fy = g - g.floor();
743 b = fx * (1.0f - fy);
744};
745
746STAGE(bottom_left, true) {
747 auto sc = (const SkImageShaderContext*)ctx;
748
749 r = SkNf::Load(sc->x) - 0.5f;
750 g = SkNf::Load(sc->y) + 0.5f;
751
752 auto fx = r - r.floor(),
753 fy = g - g.floor();
754 b = (1.0f - fx) * fy;
755};
756
757STAGE(bottom_right, true) {
758 auto sc = (const SkImageShaderContext*)ctx;
759
760 r = SkNf::Load(sc->x) + 0.5f;
761 g = SkNf::Load(sc->y) + 0.5f;
762
763 auto fx = r - r.floor(),
764 fy = g - g.floor();
765 b = fx * fy;
Mike Klein06a65e22016-11-17 12:39:09 -0500766};
767
Mike Kleincb2c12b2016-11-22 13:22:48 -0500768template <typename T>
769SI SkNi offset_and_ptr(T** ptr, const void* ctx, const SkNf& x, const SkNf& y) {
Mike Klein46e66a22016-11-21 16:19:34 -0500770 auto sc = (const SkImageShaderContext*)ctx;
Mike Klein06a65e22016-11-17 12:39:09 -0500771
Mike Kleincb2c12b2016-11-22 13:22:48 -0500772 SkNi ix = SkNx_cast<int>(x),
773 iy = SkNx_cast<int>(y);
Mike Klein46e66a22016-11-21 16:19:34 -0500774 SkNi offset = iy*sc->stride + ix;
Mike Klein06a65e22016-11-17 12:39:09 -0500775
Mike Kleincb2c12b2016-11-22 13:22:48 -0500776 *ptr = (const T*)sc->pixels;
777 return offset;
778}
779
780STAGE(accum_565, true) {
781 const uint16_t* p;
782 SkNi offset = offset_and_ptr(&p, ctx, r, g);
783
784 uint16_t px[N];
785 for (size_t i = 0; i < N; i++) {
786 if (kIsTail && i >= tail) {
787 px[i] = 0;
788 continue;
789 }
790 px[i] = p[offset[i]];
791 }
792 SkNf R,G,B;
793 from_565(SkNh::Load(px), &R, &G, &B);
794
795 SkNf scale = b;
796 dr += scale * R;
797 dg += scale * G;
798 db += scale * B;
799 da += scale;
800}
801
802STAGE(accum_f16, true) {
803 const uint64_t* p;
804 SkNi offset = offset_and_ptr(&p, ctx, r, g);
805
806 uint16_t R[N], G[N], B[N], A[N];
807 for (size_t i = 0; i < N; i++) {
808 if (kIsTail && i >= tail) {
809 R[i] = G[i] = B[i] = A[i] = 0;
810 continue;
811 }
812 uint64_t rgba = p[offset[i]];
813 R[i] = rgba >> 0;
814 G[i] = rgba >> 16;
815 B[i] = rgba >> 32;
816 A[i] = rgba >> 48;
817 }
818 SkNf scale = b;
819 dr += scale * SkHalfToFloat_finite_ftz(SkNh::Load(R));
820 dg += scale * SkHalfToFloat_finite_ftz(SkNh::Load(G));
821 db += scale * SkHalfToFloat_finite_ftz(SkNh::Load(B));
822 da += scale * SkHalfToFloat_finite_ftz(SkNh::Load(A));
823}
824
825STAGE(accum_8888, true) {
826 const uint32_t* p;
827 SkNi offset = offset_and_ptr(&p, ctx, r, g);
828
Mike Klein06a65e22016-11-17 12:39:09 -0500829 uint8_t R[N], G[N], B[N], A[N];
Mike Klein4e9bb742016-11-17 14:28:11 -0500830 for (size_t i = 0; i < N; i++) {
831 if (kIsTail && i >= tail) {
832 R[i] = G[i] = B[i] = A[i] = 0;
833 continue;
834 }
Mike Klein06a65e22016-11-17 12:39:09 -0500835 uint32_t rgba = p[offset[i]];
836 R[i] = rgba >> 0;
837 G[i] = rgba >> 8;
838 B[i] = rgba >> 16;
839 A[i] = rgba >> 24;
840 }
841
Mike Kleinf7f883b2016-11-21 15:09:45 -0500842 SkNf scale = b;
843 dr += scale * SkNx_cast<float>(SkNb::Load(R)) * (1/255.0f);
844 dg += scale * SkNx_cast<float>(SkNb::Load(G)) * (1/255.0f);
845 db += scale * SkNx_cast<float>(SkNb::Load(B)) * (1/255.0f);
846 da += scale * SkNx_cast<float>(SkNb::Load(A)) * (1/255.0f);
Mike Klein06a65e22016-11-17 12:39:09 -0500847}
848
Mike Kleinf7f883b2016-11-21 15:09:45 -0500849STAGE(accum_srgb, true) {
Mike Kleincb2c12b2016-11-22 13:22:48 -0500850 const uint32_t* p;
851 SkNi offset = offset_and_ptr(&p, ctx, r, g);
Mike Klein06a65e22016-11-17 12:39:09 -0500852
Mike Klein06a65e22016-11-17 12:39:09 -0500853 uint8_t R[N], G[N], B[N], A[N];
Mike Klein4e9bb742016-11-17 14:28:11 -0500854 for (size_t i = 0; i < N; i++) {
855 if (kIsTail && i >= tail) {
856 R[i] = G[i] = B[i] = A[i] = 0;
857 continue;
858 }
Mike Klein06a65e22016-11-17 12:39:09 -0500859 uint32_t rgba = p[offset[i]];
860 R[i] = rgba >> 0;
861 G[i] = rgba >> 8;
862 B[i] = rgba >> 16;
863 A[i] = rgba >> 24;
864 }
865
Mike Kleinf7f883b2016-11-21 15:09:45 -0500866 SkNf scale = b;
867 dr += scale * sk_linear_from_srgb_math(SkNx_cast<int>(SkNb::Load(R)));
868 dg += scale * sk_linear_from_srgb_math(SkNx_cast<int>(SkNb::Load(G)));
869 db += scale * sk_linear_from_srgb_math(SkNx_cast<int>(SkNb::Load(B)));
870 da += scale * SkNx_cast<float>(SkNb::Load(A)) * (1/255.0f);
Mike Klein06a65e22016-11-17 12:39:09 -0500871}
872
Mike Kleinaebfb452016-10-25 10:27:33 -0400873template <typename Fn>
874SI Fn enum_to_Fn(SkRasterPipeline::StockStage st) {
875 switch (st) {
876 #define M(stage) case SkRasterPipeline::stage: return stage;
877 SK_RASTER_PIPELINE_STAGES(M)
878 #undef M
879 }
880 SkASSERT(false);
881 return just_return;
882}
Mike Klein9161ef02016-10-04 14:03:27 -0400883
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400884namespace SK_OPTS_NS {
885
Mike Kleinad48a702016-11-07 17:16:21 -0500886 struct Memset16 {
887 uint16_t** dst;
888 uint16_t val;
Mike Kleinaf49b192016-11-15 08:52:04 -0500889 void operator()(size_t x, size_t, size_t n) { sk_memset16(*dst + x, val, n); }
Mike Kleinad48a702016-11-07 17:16:21 -0500890 };
891
892 struct Memset32 {
893 uint32_t** dst;
894 uint32_t val;
Mike Kleinaf49b192016-11-15 08:52:04 -0500895 void operator()(size_t x, size_t, size_t n) { sk_memset32(*dst + x, val, n); }
Mike Kleinad48a702016-11-07 17:16:21 -0500896 };
897
898 struct Memset64 {
899 uint64_t** dst;
900 uint64_t val;
Mike Kleinaf49b192016-11-15 08:52:04 -0500901 void operator()(size_t x, size_t, size_t n) { sk_memset64(*dst + x, val, n); }
Mike Kleinad48a702016-11-07 17:16:21 -0500902 };
903
Mike Kleinaf49b192016-11-15 08:52:04 -0500904 SI std::function<void(size_t, size_t, size_t)>
905 compile_pipeline(const SkRasterPipeline::Stage* stages, int nstages) {
mtklein125b2aa2016-11-04 13:41:34 -0700906 if (nstages == 2 && stages[0].stage == SkRasterPipeline::constant_color) {
907 SkPM4f src = *(const SkPM4f*)stages[0].ctx;
908 void* dst = stages[1].ctx;
909 switch (stages[1].stage) {
Mike Kleinad48a702016-11-07 17:16:21 -0500910 case SkRasterPipeline::store_565:
911 return Memset16{(uint16_t**)dst, SkPackRGB16(src.r() * SK_R16_MASK + 0.5f,
912 src.g() * SK_G16_MASK + 0.5f,
913 src.b() * SK_B16_MASK + 0.5f)};
914 case SkRasterPipeline::store_srgb:
915 return Memset32{(uint32_t**)dst, Sk4f_toS32(src.to4f_pmorder())};
mtklein125b2aa2016-11-04 13:41:34 -0700916
Mike Kleinad48a702016-11-07 17:16:21 -0500917 case SkRasterPipeline::store_f16:
918 return Memset64{(uint64_t**)dst, src.toF16()};
mtklein125b2aa2016-11-04 13:41:34 -0700919
920 default: break;
921 }
922 }
923
Mike Kleine9f74b82016-10-25 13:31:21 -0400924 struct Compiled {
925 Compiled(const SkRasterPipeline::Stage* stages, int nstages) {
926 if (nstages == 0) {
927 return;
928 }
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400929
Mike Kleine9f74b82016-10-25 13:31:21 -0400930 fBodyStart = enum_to_Fn<Body>(stages[0].stage);
931 fTailStart = enum_to_Fn<Tail>(stages[0].stage);
932 for (int i = 0; i < nstages-1; i++) {
933 fBody[i].next = enum_to_Fn<Body>(stages[i+1].stage);
934 fTail[i].next = enum_to_Fn<Tail>(stages[i+1].stage);
935 fBody[i].ctx = fTail[i].ctx = stages[i].ctx;
936 }
937 fBody[nstages-1].next = just_return;
938 fTail[nstages-1].next = just_return;
939 fBody[nstages-1].ctx = fTail[nstages-1].ctx = stages[nstages-1].ctx;
Mike Klein050ffa92016-10-20 16:20:46 -0400940 }
Mike Kleinaebfb452016-10-25 10:27:33 -0400941
Mike Kleinaf49b192016-11-15 08:52:04 -0500942 void operator()(size_t x, size_t y, size_t n) {
Mike Kleinaf49b192016-11-15 08:52:04 -0500943 float dx[] = { 0,1,2,3,4,5,6,7 };
Mike Klein0f91ea42016-11-15 10:31:38 -0500944 SkNf X = SkNf(x) + SkNf::Load(dx) + 0.5f,
Mike Kleinf7f883b2016-11-21 15:09:45 -0500945 Y = SkNf(y) + 0.5f,
946 _0 = SkNf(0),
947 _1 = SkNf(1);
Mike Kleinaf49b192016-11-15 08:52:04 -0500948
Mike Kleine9f74b82016-10-25 13:31:21 -0400949 while (n >= N) {
Mike Kleinf7f883b2016-11-21 15:09:45 -0500950 fBodyStart(fBody, x, X,Y,_1,_0, _0,_0,_0,_0);
Mike Klein0f91ea42016-11-15 10:31:38 -0500951 X += (float)N;
Mike Kleine9f74b82016-10-25 13:31:21 -0400952 x += N;
953 n -= N;
954 }
955 if (n) {
Mike Kleinf7f883b2016-11-21 15:09:45 -0500956 fTailStart(fTail, x,n, X,Y,_1,_0, _0,_0,_0,_0);
Mike Kleine9f74b82016-10-25 13:31:21 -0400957 }
Mike Klein050ffa92016-10-20 16:20:46 -0400958 }
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400959
Mike Kleine9f74b82016-10-25 13:31:21 -0400960 Body fBodyStart = just_return;
961 Tail fTailStart = just_return;
962
963 BodyStage fBody[SkRasterPipeline::kMaxStages];
964 TailStage fTail[SkRasterPipeline::kMaxStages];
965
966 } fn { stages, nstages };
967 return fn;
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400968 }
969
Mike Kleinaebfb452016-10-25 10:27:33 -0400970} // namespace SK_OPTS_NS
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400971
Mike Klein04adfda2016-10-12 09:52:55 -0400972#undef SI
973#undef STAGE
974#undef RGBA_XFERMODE
975#undef RGB_XFERMODE
Mike Klein9161ef02016-10-04 14:03:27 -0400976
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400977#endif//SkRasterPipeline_opts_DEFINED