OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 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 SkRasterPipeline_opts_DEFINED | 8 #ifndef SkRasterPipeline_opts_DEFINED |
9 #define SkRasterPipeline_opts_DEFINED | 9 #define SkRasterPipeline_opts_DEFINED |
10 | 10 |
11 #include "SkColorPriv.h" | 11 #include "SkColorPriv.h" |
12 #include "SkColorSpace_Base.h" | |
12 #include "SkHalf.h" | 13 #include "SkHalf.h" |
14 #include "SkMatrix44.h" | |
13 #include "SkPM4f.h" | 15 #include "SkPM4f.h" |
14 #include "SkPM4fPriv.h" | 16 #include "SkPM4fPriv.h" |
15 #include "SkRasterPipeline.h" | 17 #include "SkRasterPipeline.h" |
16 #include "SkSRGB.h" | 18 #include "SkSRGB.h" |
17 #include "SkUtils.h" | 19 #include "SkUtils.h" |
18 #include <utility> | 20 #include <utility> |
19 | 21 |
20 namespace { | 22 namespace { |
21 | 23 |
22 #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2 | 24 #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2 |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
127 SkNf dr, SkNf dg, SkNf db, SkNf da) { \ | 129 SkNf dr, SkNf dg, SkNf db, SkNf da) { \ |
128 r = name##_kernel(r,a,dr,da); \ | 130 r = name##_kernel(r,a,dr,da); \ |
129 g = name##_kernel(g,a,dg,da); \ | 131 g = name##_kernel(g,a,dg,da); \ |
130 b = name##_kernel(b,a,db,da); \ | 132 b = name##_kernel(b,a,db,da); \ |
131 a = a + (da * (1.0f-a)); \ | 133 a = a + (da * (1.0f-a)); \ |
132 next(st, x,tail, r,g,b,a, dr,dg,db,da); \ | 134 next(st, x,tail, r,g,b,a, dr,dg,db,da); \ |
133 } \ | 135 } \ |
134 static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa, \ | 136 static SK_ALWAYS_INLINE SkNf name##_kernel(const SkNf& s, const SkNf& sa, \ |
135 const SkNf& d, const SkNf& da) | 137 const SkNf& d, const SkNf& da) |
136 | 138 |
139 | |
140 #define GAMMA_STAGE(name) \ | |
msarett1
2016/11/09 00:01:05
Instead of this, I think I would prefer 6 normal s
mtklein_C
2016/11/09 11:04:36
I think you mean 3 normal stages? Each STAGE invo
raftias
2016/11/10 21:36:06
I did this with fn_1_r/g/b. If we add in specific
| |
141 static SK_ALWAYS_INLINE SkNf name##_kernel(void* ctx, SkNf& s); \ | |
142 SI void SK_VECTORCALL name##_r(BodyStage* st, size_t x, \ | |
143 SkNf r, SkNf g, SkNf b, SkNf a, \ | |
144 SkNf dr, SkNf dg, SkNf db, SkNf da) { \ | |
145 r = name##_kernel(st->ctx, r); \ | |
146 next(st, x, r,g,b,a, dr,dg,db,da); \ | |
147 } \ | |
148 SI void SK_VECTORCALL name##_r(TailStage* st, size_t x, size_t tail, \ | |
149 SkNf r, SkNf g, SkNf b, SkNf a, \ | |
150 SkNf dr, SkNf dg, SkNf db, SkNf da) { \ | |
151 r = name##_kernel(st->ctx, r); \ | |
152 next(st, x,tail, r,g,b,a, dr,dg,db,da); \ | |
153 } \ | |
154 SI void SK_VECTORCALL name##_g(BodyStage* st, size_t x, \ | |
155 SkNf r, SkNf g, SkNf b, SkNf a, \ | |
156 SkNf dr, SkNf dg, SkNf db, SkNf da) { \ | |
157 g = name##_kernel(st->ctx, g); \ | |
158 next(st, x, r,g,b,a, dr,dg,db,da); \ | |
159 } \ | |
160 SI void SK_VECTORCALL name##_g(TailStage* st, size_t x, size_t tail, \ | |
161 SkNf r, SkNf g, SkNf b, SkNf a, \ | |
162 SkNf dr, SkNf dg, SkNf db, SkNf da) { \ | |
163 g = name##_kernel(st->ctx, g); \ | |
164 next(st, x,tail, r,g,b,a, dr,dg,db,da); \ | |
165 } \ | |
166 SI void SK_VECTORCALL name##_b(BodyStage* st, size_t x, \ | |
167 SkNf r, SkNf g, SkNf b, SkNf a, \ | |
168 SkNf dr, SkNf dg, SkNf db, SkNf da) { \ | |
169 b = name##_kernel(st->ctx, b); \ | |
170 next(st, x, r,g,b,a, dr,dg,db,da); \ | |
171 } \ | |
172 SI void SK_VECTORCALL name##_b(TailStage* st, size_t x, size_t tail, \ | |
173 SkNf r, SkNf g, SkNf b, SkNf a, \ | |
174 SkNf dr, SkNf dg, SkNf db, SkNf da) { \ | |
175 b = name##_kernel(st->ctx, b); \ | |
176 next(st, x,tail, r,g,b,a, dr,dg,db,da); \ | |
177 } \ | |
178 SI void SK_VECTORCALL name##_a(BodyStage* st, size_t x, \ | |
msarett1
2016/11/09 00:01:05
All we need to do with "a" is load it and store.
raftias
2016/11/10 21:36:07
It was indeed for CMYK/etc support.
| |
179 SkNf r, SkNf g, SkNf b, SkNf a, \ | |
180 SkNf dr, SkNf dg, SkNf db, SkNf da) { \ | |
181 a = name##_kernel(st->ctx, a); \ | |
182 next(st, x, r,g,b,a, dr,dg,db,da); \ | |
183 } \ | |
184 SI void SK_VECTORCALL name##_a(TailStage* st, size_t x, size_t tail, \ | |
185 SkNf r, SkNf g, SkNf b, SkNf a, \ | |
186 SkNf dr, SkNf dg, SkNf db, SkNf da) { \ | |
187 a = name##_kernel(st->ctx, a); \ | |
188 next(st, x,tail, r,g,b,a, dr,dg,db,da); \ | |
189 } \ | |
190 static SK_ALWAYS_INLINE SkNf name##_kernel(void* ctx, SkNf& s) | |
191 | |
137 SI SkNf inv(const SkNf& x) { return 1.0f - x; } | 192 SI SkNf inv(const SkNf& x) { return 1.0f - x; } |
138 | 193 |
139 SI SkNf lerp(const SkNf& from, const SkNf& to, const SkNf& cov) { | 194 SI SkNf lerp(const SkNf& from, const SkNf& to, const SkNf& cov) { |
140 return SkNx_fma(to-from, cov, from); | 195 return SkNx_fma(to-from, cov, from); |
141 } | 196 } |
142 | 197 |
143 template <bool kIsTail, typename T> | 198 template <bool kIsTail, typename T> |
144 SI SkNx<N,T> load(size_t tail, const T* src) { | 199 SI SkNx<N,T> load(size_t tail, const T* src) { |
145 SkASSERT(kIsTail == (tail > 0)); | 200 SkASSERT(kIsTail == (tail > 0)); |
146 // TODO: maskload for 32- and 64-bit T | 201 // TODO: maskload for 32- and 64-bit T |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
424 } | 479 } |
425 | 480 |
426 STAGE(store_srgb, false) { | 481 STAGE(store_srgb, false) { |
427 auto ptr = *(uint32_t**)ctx + x; | 482 auto ptr = *(uint32_t**)ctx + x; |
428 store<kIsTail>(tail, ( sk_linear_to_srgb(r) << SK_R32_SHIFT | 483 store<kIsTail>(tail, ( sk_linear_to_srgb(r) << SK_R32_SHIFT |
429 | sk_linear_to_srgb(g) << SK_G32_SHIFT | 484 | sk_linear_to_srgb(g) << SK_G32_SHIFT |
430 | sk_linear_to_srgb(b) << SK_B32_SHIFT | 485 | sk_linear_to_srgb(b) << SK_B32_SHIFT |
431 | SkNx_cast<int>(0.5f + 255.0f * a) << SK_A32_SHIFT), ( int*)ptr); | 486 | SkNx_cast<int>(0.5f + 255.0f * a) << SK_A32_SHIFT), ( int*)ptr); |
432 } | 487 } |
433 | 488 |
489 STAGE(load_s_linear_rgba, true) { | |
msarett1
2016/11/09 00:01:05
nit: Follow style conventions from above
Use whit
mtklein_C
2016/11/09 11:04:36
Let's call these _8888. That's our common shortha
| |
490 auto ptr = *(const uint32_t**)ctx + x; | |
491 | |
492 auto px = load<kIsTail>(tail, ptr); | |
493 auto to_int = [](const SkNx<N, uint32_t>& v) { return SkNi::Load(&v); }; | |
494 r = (1/255.0f)*SkNx_cast<float>(to_int((px >> 0) & 0xFF)); | |
495 g = (1/255.0f)*SkNx_cast<float>(to_int((px >> 8) & 0xFF)); | |
496 b = (1/255.0f)*SkNx_cast<float>(to_int((px >> 16) & 0xFF)); | |
497 a = (1/255.0f)*SkNx_cast<float>(to_int(px >> 24)); | |
498 } | |
499 | |
500 STAGE(load_s_linear_bgra, true) { | |
mtklein_C
2016/11/09 11:04:36
How about we write everything in terms of rgba, an
raftias
2016/11/10 21:36:07
I that before (with that exact name, even), then t
msarett1
2016/11/11 14:36:51
Let's defer to Mike on this one. lgtm, as is.
| |
501 auto ptr = *(const uint32_t**)ctx + x; | |
502 | |
503 auto px = load<kIsTail>(tail, ptr); | |
504 auto to_int = [](const SkNx<N, uint32_t>& v) { return SkNi::Load(&v); }; | |
505 r = (1/255.0f)*SkNx_cast<float>(to_int((px >> 16) & 0xFF)); | |
506 g = (1/255.0f)*SkNx_cast<float>(to_int((px >> 8) & 0xFF)); | |
507 b = (1/255.0f)*SkNx_cast<float>(to_int((px >> 0) & 0xFF)); | |
508 a = (1/255.0f)*SkNx_cast<float>(to_int((px >> 24))); | |
509 } | |
510 | |
511 // Clamp colors into [0,1] premul (e.g. just before storing back to memory). | |
raftias
2016/11/08 21:19:58
I noticed when I pulled before uploading that this
msarett1
2016/11/09 00:01:05
I believe the idea is to not waste time clamping w
mtklein_C
2016/11/09 11:04:36
This has now been split into two stages, clamp_0 a
| |
512 SI void clamp_01_premul(SkNf& r, SkNf& g, SkNf& b, SkNf& a) { | |
513 a = SkNf::Max(a, 0.0f); | |
514 r = SkNf::Max(r, 0.0f); | |
515 g = SkNf::Max(g, 0.0f); | |
516 b = SkNf::Max(b, 0.0f); | |
517 | |
518 a = SkNf::Min(a, 1.0f); | |
519 r = SkNf::Min(r, a); | |
520 g = SkNf::Min(g, a); | |
521 b = SkNf::Min(b, a); | |
522 } | |
523 | |
524 STAGE(store_linear_rgba, false) { | |
525 clamp_01_premul(r,g,b,a); | |
526 auto ptr = *(uint32_t**)ctx + x; | |
527 store<kIsTail>(tail, ( SkNx_cast<int>(255.0f * r + 0.5f) << 0 | |
msarett1
2016/11/09 00:01:05
I don't think you need the "+ 0.5f" terms. I thin
mtklein_C
2016/11/09 11:04:36
No, we're doing that to round to the nearest byte
| |
528 | SkNx_cast<int>(255.0f * g + 0.5f) << 8 | |
529 | SkNx_cast<int>(255.0f * b + 0.5f) << 16 | |
530 | SkNx_cast<int>(255.0f * a + 0.5f) << 24 ), (int*)ptr) ; | |
531 } | |
532 | |
533 STAGE(store_linear_bgra, false) { | |
534 clamp_01_premul(r,g,b,a); | |
535 auto ptr = *(uint32_t**)ctx + x; | |
536 store<kIsTail>(tail, ( SkNx_cast<int>(255.0f * r + 0.5f) << 16 | |
537 | SkNx_cast<int>(255.0f * g + 0.5f) << 8 | |
538 | SkNx_cast<int>(255.0f * b + 0.5f) << 0 | |
539 | SkNx_cast<int>(255.0f * a + 0.5f) << 24 ), (int*)ptr) ; | |
540 } | |
541 | |
434 RGBA_XFERMODE(clear) { return 0.0f; } | 542 RGBA_XFERMODE(clear) { return 0.0f; } |
435 //RGBA_XFERMODE(src) { return s; } // This would be a no-op stage, so we just omit it. | 543 //RGBA_XFERMODE(src) { return s; } // This would be a no-op stage, so we just omit it. |
436 RGBA_XFERMODE(dst) { return d; } | 544 RGBA_XFERMODE(dst) { return d; } |
437 | 545 |
438 RGBA_XFERMODE(srcatop) { return s*da + d*inv(sa); } | 546 RGBA_XFERMODE(srcatop) { return s*da + d*inv(sa); } |
439 RGBA_XFERMODE(srcin) { return s * da; } | 547 RGBA_XFERMODE(srcin) { return s * da; } |
440 RGBA_XFERMODE(srcout) { return s * inv(da); } | 548 RGBA_XFERMODE(srcout) { return s * inv(da); } |
441 RGBA_XFERMODE(srcover) { return SkNx_fma(d, inv(sa), s); } | 549 RGBA_XFERMODE(srcover) { return SkNx_fma(d, inv(sa), s); } |
442 RGBA_XFERMODE(dstatop) { return srcatop_kernel(d,da,s,sa); } | 550 RGBA_XFERMODE(dstatop) { return srcatop_kernel(d,da,s,sa); } |
443 RGBA_XFERMODE(dstin) { return srcin_kernel (d,da,s,sa); } | 551 RGBA_XFERMODE(dstin) { return srcin_kernel (d,da,s,sa); } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
483 liteDst = m.rsqrt().invert() - m, // Used in case 3. | 591 liteDst = m.rsqrt().invert() - m, // Used in case 3. |
484 liteSrc = d*sa + da*(s2 - sa) * (4.0f*d <= da).thenElse(darkDst, liteDs t); // 2 or 3? | 592 liteSrc = d*sa + da*(s2 - sa) * (4.0f*d <= da).thenElse(darkDst, liteDs t); // 2 or 3? |
485 return s*inv(da) + d*inv(sa) + (s2 <= sa).thenElse(darkSrc, liteSrc); // 1 or (2 or 3)? | 593 return s*inv(da) + d*inv(sa) + (s2 <= sa).thenElse(darkSrc, liteSrc); // 1 or (2 or 3)? |
486 } | 594 } |
487 | 595 |
488 STAGE(luminance_to_alpha, true) { | 596 STAGE(luminance_to_alpha, true) { |
489 a = SK_LUM_COEFF_R*r + SK_LUM_COEFF_G*g + SK_LUM_COEFF_B*b; | 597 a = SK_LUM_COEFF_R*r + SK_LUM_COEFF_G*g + SK_LUM_COEFF_B*b; |
490 r = g = b = 0; | 598 r = g = b = 0; |
491 } | 599 } |
492 | 600 |
601 STAGE(matrix_4x4, true) { | |
602 const SkMatrix44& mat = *(const SkMatrix44*)ctx; | |
mtklein_C
2016/11/09 11:04:36
I'd like matrix_4x4 and matrix_4x5 to look and beh
raftias
2016/11/10 21:36:06
They were just different since I had written it an
| |
603 auto fma = [](const SkNf& f, const SkNf& m, const SkNf& a) { return SkNx_fma (f,m,a); }; | |
604 dr = fma(mat.get(0, 0),r, fma(mat.get(0, 1),g, fma(mat.get(0, 2),b, mat.get( 0, 3)*a))); | |
msarett1
2016/11/09 00:01:05
No need for "*a". Actually I think we don't want
mtklein_C
2016/11/09 11:04:36
If we don't *a here, we can't really call this sta
raftias
2016/11/10 21:36:06
It's 3x4 now.
| |
605 dg = fma(mat.get(1, 0),r, fma(mat.get(1, 1),g, fma(mat.get(1, 2),b, mat.get( 1, 3)*a))); | |
606 db = fma(mat.get(2, 0),r, fma(mat.get(2, 1),g, fma(mat.get(2, 2),b, mat.get( 2, 3)*a))); | |
msarett1
2016/11/09 00:01:05
Mike, is it ok that we're destructive to dr, dg, d
mtklein_C
2016/11/09 11:04:36
The pedantic answer is that that depends what you'
raftias
2016/11/10 21:36:06
I'll remove these and put them in temporaries. I j
| |
607 da = fma(mat.get(3, 0),r, fma(mat.get(3, 1),g, fma(mat.get(3, 2),b, mat.get( 3, 3)*a))); | |
608 r = dr; | |
609 g = dg; | |
610 b = db; | |
611 a = da; | |
612 } | |
613 | |
493 STAGE(matrix_4x5, true) { | 614 STAGE(matrix_4x5, true) { |
494 auto m = (const float*)ctx; | 615 auto m = (const float*)ctx; |
495 | 616 |
496 auto fma = [](const SkNf& f, const SkNf& m, const SkNf& a) { return SkNx_fma (f,m,a); }; | 617 auto fma = [](const SkNf& f, const SkNf& m, const SkNf& a) { return SkNx_fma (f,m,a); }; |
497 auto R = fma(r,m[0], fma(g,m[4], fma(b,m[ 8], fma(a,m[12], m[16])))), | 618 auto R = fma(r,m[0], fma(g,m[4], fma(b,m[ 8], fma(a,m[12], m[16])))), |
498 G = fma(r,m[1], fma(g,m[5], fma(b,m[ 9], fma(a,m[13], m[17])))), | 619 G = fma(r,m[1], fma(g,m[5], fma(b,m[ 9], fma(a,m[13], m[17])))), |
499 B = fma(r,m[2], fma(g,m[6], fma(b,m[10], fma(a,m[14], m[18])))), | 620 B = fma(r,m[2], fma(g,m[6], fma(b,m[10], fma(a,m[14], m[18])))), |
500 A = fma(r,m[3], fma(g,m[7], fma(b,m[11], fma(a,m[15], m[19])))); | 621 A = fma(r,m[3], fma(g,m[7], fma(b,m[11], fma(a,m[15], m[19])))); |
501 r = R; | 622 r = R; |
502 g = G; | 623 g = G; |
503 b = B; | 624 b = B; |
504 a = A; | 625 a = A; |
505 } | 626 } |
506 | 627 |
628 static inline Sk4f powNf(const Sk4f& x, float exp) { | |
mtklein_C
2016/11/09 11:04:36
Generally this file writes static inline as SI. I
raftias
2016/11/10 21:36:06
Acknowledged.
| |
629 return Sk4f{::powf(x[0], exp), ::powf(x[1], exp), ::powf(x[2], exp), ::powf( x[3], exp)}; | |
630 } | |
631 | |
632 static inline Sk8f powNf(const Sk8f& x, float exp) { | |
633 return Sk8f{::powf(x[0], exp), ::powf(x[1], exp), ::powf(x[2], exp), ::powf( x[3], exp), | |
634 ::powf(x[4], exp), ::powf(x[5], exp), ::powf(x[6], exp), ::powf( x[7], exp)}; | |
635 } | |
636 | |
637 GAMMA_STAGE(param_gamma) { | |
638 const SkColorSpaceTransferFn& gamma = *(const SkColorSpaceTransferFn*)ctx; | |
639 return (s <= gamma.fD).thenElse(gamma.fE * s + gamma.fF, | |
msarett1
2016/11/09 00:01:05
nit: < instead of <=
raftias
2016/11/10 21:36:06
Done.
| |
640 powNf(s * gamma.fA + gamma.fB, gamma.fG) + g amma.fC); | |
641 } | |
642 | |
643 static constexpr float kGammaTableSize = 1024; | |
644 | |
645 GAMMA_STAGE(table_gamma) { | |
646 constexpr float maxIndex = kGammaTableSize - 1; | |
647 const float* gammaTables = (const float*)ctx; | |
mtklein_C
2016/11/09 11:04:36
This name makes it seem like we're going to be usi
raftias
2016/11/10 21:36:06
Acknowledged.
| |
648 s = SkNf::Min(SkNf::Max(maxIndex * s, 0.f), maxIndex); | |
mtklein_C
2016/11/09 11:04:36
If we're not going to source the 1024 constant fro
raftias
2016/11/10 21:36:06
ApplyTable stores it now.
| |
649 float result[N]; | |
650 for (int i = 0; i < N; ++i) { | |
651 result[i] = gammaTables[lrintf(s[i])]; | |
652 } | |
653 return SkNf::Load(result); | |
654 } | |
655 | |
656 static inline void interp_3d_clut(float dst[3], float src[3], const SkColorLookU pTable* colorLUT) { | |
msarett1
2016/11/09 00:01:05
This maybe does not need to belong in this file.
mtklein_C
2016/11/09 11:04:36
Why don't we make this a normal, separately-compil
raftias
2016/11/10 21:36:06
Done.
| |
657 // Call the src components x, y, and z. | |
658 uint8_t maxX = colorLUT->fGridPoints[0] - 1; | |
659 uint8_t maxY = colorLUT->fGridPoints[1] - 1; | |
660 uint8_t maxZ = colorLUT->fGridPoints[2] - 1; | |
661 | |
662 // An approximate index into each of the three dimensions of the table. | |
663 float x = src[0] * maxX; | |
664 float y = src[1] * maxY; | |
665 float z = src[2] * maxZ; | |
666 | |
667 // This gives us the low index for our interpolation. | |
668 int ix = sk_float_floor2int(x); | |
669 int iy = sk_float_floor2int(y); | |
670 int iz = sk_float_floor2int(z); | |
671 | |
672 // Make sure the low index is not also the max index. | |
673 ix = (maxX == ix) ? ix - 1 : ix; | |
674 iy = (maxY == iy) ? iy - 1 : iy; | |
675 iz = (maxZ == iz) ? iz - 1 : iz; | |
676 | |
677 // Weighting factors for the interpolation. | |
678 float diffX = x - ix; | |
679 float diffY = y - iy; | |
680 float diffZ = z - iz; | |
681 | |
682 // Constants to help us navigate the 3D table. | |
683 // Ex: Assume x = a, y = b, z = c. | |
684 // table[a * n001 + b * n010 + c * n100] logically equals table[a][b][c] . | |
685 const int n000 = 0; | |
686 const int n001 = 3 * colorLUT->fGridPoints[1] * colorLUT->fGridPoints[2]; | |
687 const int n010 = 3 * colorLUT->fGridPoints[2]; | |
688 const int n011 = n001 + n010; | |
689 const int n100 = 3; | |
690 const int n101 = n100 + n001; | |
691 const int n110 = n100 + n010; | |
692 const int n111 = n110 + n001; | |
693 | |
694 // Base ptr into the table. | |
695 const float* ptr = &(colorLUT->table()[ix*n001 + iy*n010 + iz*n100]); | |
696 | |
697 // The code below performs a tetrahedral interpolation for each of the three | |
698 // dst components. Once the tetrahedron containing the interpolation point is | |
699 // identified, the interpolation is a weighted sum of grid values at the | |
700 // vertices of the tetrahedron. The claim is that tetrahedral interpolation | |
701 // provides a more accurate color conversion. | |
702 // blogs.mathworks.com/steve/2006/11/24/tetrahedral-interpolation-for-colors pace-conversion/ | |
703 // | |
704 // I have one test image, and visually I can't tell the difference between | |
705 // tetrahedral and trilinear interpolation. In terms of computation, the | |
706 // tetrahedral code requires more branches but less computation. The | |
707 // SampleICC library provides an option for the client to choose either | |
708 // tetrahedral or trilinear. | |
709 for (int i = 0; i < 3; i++) { | |
710 if (diffZ < diffY) { | |
711 if (diffZ < diffX) { | |
712 dst[i] = (ptr[n000] + diffZ * (ptr[n110] - ptr[n010]) + | |
713 diffY * (ptr[n010] - ptr[n000]) + | |
714 diffX * (ptr[n111] - ptr[n110])); | |
715 } else if (diffY < diffX) { | |
716 dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + | |
717 diffY * (ptr[n011] - ptr[n001]) + | |
718 diffX * (ptr[n001] - ptr[n000])); | |
719 } else { | |
720 dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + | |
721 diffY * (ptr[n010] - ptr[n000]) + | |
722 diffX * (ptr[n011] - ptr[n010])); | |
723 } | |
724 } else { | |
725 if (diffZ < diffX) { | |
726 dst[i] = (ptr[n000] + diffZ * (ptr[n101] - ptr[n001]) + | |
727 diffY * (ptr[n111] - ptr[n101]) + | |
728 diffX * (ptr[n001] - ptr[n000])); | |
729 } else if (diffY < diffX) { | |
730 dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + | |
731 diffY * (ptr[n111] - ptr[n101]) + | |
732 diffX * (ptr[n101] - ptr[n100])); | |
733 } else { | |
734 dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + | |
735 diffY * (ptr[n110] - ptr[n100]) + | |
736 diffX * (ptr[n111] - ptr[n110])); | |
737 } | |
738 } | |
739 | |
740 // Increment the table ptr in order to handle the next component. | |
741 // Note that this is the how table is designed: all of nXXX | |
742 // variables are multiples of 3 because there are 3 output | |
743 // components. | |
744 ptr++; | |
745 } | |
746 } | |
747 | |
748 STAGE(clut, true) { | |
mtklein_C
2016/11/09 11:04:36
how about color_lookup_table?
raftias
2016/11/10 21:36:06
Done.
| |
749 const SkColorLookUpTable* colorLUT = (const SkColorLookUpTable*)ctx; | |
mtklein_C
2016/11/09 11:04:36
Side note: it's going to drive me nuts that we cap
raftias
2016/11/10 21:36:06
I didn't name it, but my guess is that it's becaus
msarett1
2016/11/11 14:36:51
I don't feel strongly about the name. Feel free t
| |
750 float rgb[3]; | |
751 alignas(alignof(SkNf)) float result[3][N]; | |
mtklein_C
2016/11/09 11:04:36
Let's drop the alignment business. SkNf::Load() s
raftias
2016/11/10 21:36:06
Done.
| |
752 for (int i = 0; i < N; ++i) { | |
753 rgb[0] = r[i]; | |
754 rgb[1] = g[i]; | |
755 rgb[2] = b[i]; | |
756 interp_3d_clut(rgb, rgb, colorLUT); | |
757 result[0][i] = rgb[0]; | |
758 result[1][i] = rgb[1]; | |
759 result[2][i] = rgb[2]; | |
760 } | |
761 r = SkNf::Load(result[0]); | |
762 g = SkNf::Load(result[1]); | |
763 b = SkNf::Load(result[2]); | |
764 } | |
765 | |
766 STAGE(labtoxyz, true) { | |
raftias
2016/11/08 21:19:58
I think this can be expressed as a matrix_4x4 foll
mtklein_C
2016/11/09 11:04:36
I think this is clearer as its own stage.
It's pr
raftias
2016/11/10 21:36:06
Done.
| |
767 const auto lab_l = r * 100.f; | |
768 const auto lab_a = g * 255.f - 128.f; | |
769 const auto lab_b = b * 255.f - 128.f; | |
770 auto Y = (lab_l + 16.f) * (1.f/116.f); | |
771 auto X = lab_a * (1.f/500.f) + Y; | |
mtklein_C
2016/11/09 11:04:36
One .f is plenty to get these solidly as float con
raftias
2016/11/10 21:36:06
Acknowledged.
| |
772 auto Z = Y - (lab_b * (1.f/200.f)); | |
773 | |
774 auto cubed = X*X*X; | |
775 X = (cubed > 0.008856f).thenElse(cubed, (X - (16.f/116.f)) * (1.f/7.787f)); | |
776 cubed = Y*Y*Y; | |
mtklein_C
2016/11/09 11:04:36
At a glance it looks like cubed must be accumulati
raftias
2016/11/10 21:36:06
Done.
| |
777 Y = (cubed > 0.008856f).thenElse(cubed, (Y - (16.f/116.f)) * (1.f/7.787f)); | |
778 cubed = Z*Z*Z; | |
779 Z = (cubed > 0.008856f).thenElse(cubed, (Z - (16.f/116.f)) * (1.f/7.787f)); | |
780 | |
781 // adjust to D50 illuminant | |
782 X *= 0.96422f; | |
783 Y *= 1.00000f; | |
784 Z *= 0.82521f; | |
785 | |
786 r = X; | |
787 g = Y; | |
788 b = Z; | |
789 } | |
790 | |
507 template <typename Fn> | 791 template <typename Fn> |
508 SI Fn enum_to_Fn(SkRasterPipeline::StockStage st) { | 792 SI Fn enum_to_Fn(SkRasterPipeline::StockStage st) { |
509 switch (st) { | 793 switch (st) { |
510 #define M(stage) case SkRasterPipeline::stage: return stage; | 794 #define M(stage) case SkRasterPipeline::stage: return stage; |
511 SK_RASTER_PIPELINE_STAGES(M) | 795 SK_RASTER_PIPELINE_STAGES(M) |
512 #undef M | 796 #undef M |
513 } | 797 } |
514 SkASSERT(false); | 798 SkASSERT(false); |
515 return just_return; | 799 return just_return; |
516 } | 800 } |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
597 } | 881 } |
598 | 882 |
599 } // namespace SK_OPTS_NS | 883 } // namespace SK_OPTS_NS |
600 | 884 |
601 #undef SI | 885 #undef SI |
602 #undef STAGE | 886 #undef STAGE |
603 #undef RGBA_XFERMODE | 887 #undef RGBA_XFERMODE |
604 #undef RGB_XFERMODE | 888 #undef RGB_XFERMODE |
605 | 889 |
606 #endif//SkRasterPipeline_opts_DEFINED | 890 #endif//SkRasterPipeline_opts_DEFINED |
OLD | NEW |