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 #include "SkColorPriv.h" | 8 #include "SkColorPriv.h" |
9 #include "SkColorSpace_Base.h" | 9 #include "SkColorSpace_Base.h" |
| 10 #include "SkColorSpacePriv.h" |
10 #include "SkColorSpaceXform.h" | 11 #include "SkColorSpaceXform.h" |
11 #include "SkColorSpaceXformOpts.h" | 12 #include "SkHalf.h" |
| 13 #include "SkOpts.h" |
12 #include "SkSRGB.h" | 14 #include "SkSRGB.h" |
13 | 15 |
14 static constexpr float sk_linear_from_2dot2[256] = { | 16 static constexpr float sk_linear_from_2dot2[256] = { |
15 0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.0
00056921765712193f, | 17 0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.0
00056921765712193f, |
16 0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.0
00367136269815943f, | 18 0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.0
00367136269815943f, |
17 0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.0
00992374304074325f, | 19 0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.0
00992374304074325f, |
18 0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.0
01963416213396470f, | 20 0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.0
01963416213396470f, |
19 0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.0
03302703032003640f, | 21 0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.0
03302703032003640f, |
20 0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.0
05028203456855540f, | 22 0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.0
05028203456855540f, |
21 0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.0
07155037004573030f, | 23 0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.0
07155037004573030f, |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 if (v >= 254.5f) { | 254 if (v >= 254.5f) { |
253 return 255; | 255 return 255; |
254 } else if (v >= 0.5f) { | 256 } else if (v >= 0.5f) { |
255 return (uint8_t) (v + 0.5f); | 257 return (uint8_t) (v + 0.5f); |
256 } else { | 258 } else { |
257 return 0; | 259 return 0; |
258 } | 260 } |
259 } | 261 } |
260 | 262 |
261 static const int kDstGammaTableSize = | 263 static const int kDstGammaTableSize = |
262 SkColorSpaceXform_Base<SkColorSpace::kNonStandard_GammaNamed>::kDstGamma
TableSize; | 264 SkColorSpaceXform_Base<SkColorSpace::kNonStandard_GammaNamed, kNone_Colo
rSpaceMatch> |
| 265 ::kDstGammaTableSize; |
263 | 266 |
264 static void build_table_linear_to_gamma(uint8_t* outTable, float exponent) { | 267 static void build_table_linear_to_gamma(uint8_t* outTable, float exponent) { |
265 float toGammaExp = 1.0f / exponent; | 268 float toGammaExp = 1.0f / exponent; |
266 | 269 |
267 for (int i = 0; i < kDstGammaTableSize; i++) { | 270 for (int i = 0; i < kDstGammaTableSize; i++) { |
268 float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1))); | 271 float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1))); |
269 outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp)); | 272 outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp)); |
270 } | 273 } |
271 } | 274 } |
272 | 275 |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
446 static inline bool compute_gamut_xform(SkMatrix44* srcToDst, const SkMatrix44& s
rcToXYZ, | 449 static inline bool compute_gamut_xform(SkMatrix44* srcToDst, const SkMatrix44& s
rcToXYZ, |
447 const SkMatrix44& dstToXYZ) { | 450 const SkMatrix44& dstToXYZ) { |
448 if (!dstToXYZ.invert(srcToDst)) { | 451 if (!dstToXYZ.invert(srcToDst)) { |
449 return false; | 452 return false; |
450 } | 453 } |
451 | 454 |
452 srcToDst->postConcat(srcToXYZ); | 455 srcToDst->postConcat(srcToXYZ); |
453 return true; | 456 return true; |
454 } | 457 } |
455 | 458 |
| 459 static inline bool is_almost_identity(const SkMatrix44& srcToDst) { |
| 460 for (int i = 0; i < 4; i++) { |
| 461 for (int j = 0; j < 4; j++) { |
| 462 float expected = (i == j) ? 1.0f : 0.0f; |
| 463 if (!color_space_almost_equal(srcToDst.getFloat(i,j), expected)) { |
| 464 return false; |
| 465 } |
| 466 } |
| 467 } |
| 468 return true; |
| 469 } |
| 470 |
456 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 471 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
457 | 472 |
458 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, | 473 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, |
459 const sk_sp<SkColorSpa
ce>& dstSpace) { | 474 const sk_sp<SkColorSpa
ce>& dstSpace) { |
460 if (!srcSpace || !dstSpace) { | 475 if (!srcSpace || !dstSpace) { |
461 // Invalid input | 476 // Invalid input |
462 return nullptr; | 477 return nullptr; |
463 } | 478 } |
464 | 479 |
465 if (as_CSB(dstSpace)->colorLUT()) { | 480 ColorSpaceMatch csm = kNone_ColorSpaceMatch; |
466 // It would be really weird for a dst profile to have a color LUT. I do
n't think | 481 SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); |
467 // we need to support this. | 482 if (SkColorSpace::Equals(srcSpace.get(), dstSpace.get())) { |
| 483 srcToDst.setIdentity(); |
| 484 csm = kFull_ColorSpaceMatch; |
| 485 } else if (!compute_gamut_xform(&srcToDst, srcSpace->xyz(), dstSpace->xyz())
) { |
468 return nullptr; | 486 return nullptr; |
| 487 } else if (is_almost_identity(srcToDst)) { |
| 488 srcToDst.setIdentity(); |
| 489 csm = kGamut_ColorSpaceMatch; |
469 } | 490 } |
470 | 491 |
471 SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); | 492 switch (csm) { |
472 if (!compute_gamut_xform(&srcToDst, srcSpace->xyz(), dstSpace->xyz())) { | 493 case kNone_ColorSpaceMatch: |
473 return nullptr; | 494 switch (dstSpace->gammaNamed()) { |
474 } | 495 case SkColorSpace::kSRGB_GammaNamed: |
475 | 496 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_Base |
476 switch (dstSpace->gammaNamed()) { | 497 <SkColorSpace::kSRGB_GammaNamed, kNone_ColorSpaceMat
ch> |
477 case SkColorSpace::kSRGB_GammaNamed: | 498 (srcSpace, srcToDst, dstSpace)); |
478 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base | 499 case SkColorSpace::k2Dot2Curve_GammaNamed: |
479 <SkColorSpace::kSRGB_GammaNamed>(srcSpace, srcToDst, dstSpac
e)); | 500 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_Base |
480 case SkColorSpace::k2Dot2Curve_GammaNamed: | 501 <SkColorSpace::k2Dot2Curve_GammaNamed, kNone_ColorSp
aceMatch> |
481 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base | 502 (srcSpace, srcToDst, dstSpace)); |
482 <SkColorSpace::k2Dot2Curve_GammaNamed>(srcSpace, srcToDst, d
stSpace)); | 503 default: |
| 504 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_Base |
| 505 <SkColorSpace::kNonStandard_GammaNamed, kNone_ColorS
paceMatch> |
| 506 (srcSpace, srcToDst, dstSpace)); |
| 507 } |
| 508 case kGamut_ColorSpaceMatch: |
| 509 switch (dstSpace->gammaNamed()) { |
| 510 case SkColorSpace::kSRGB_GammaNamed: |
| 511 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_Base |
| 512 <SkColorSpace::kSRGB_GammaNamed, kGamut_ColorSpaceMa
tch> |
| 513 (srcSpace, srcToDst, dstSpace)); |
| 514 case SkColorSpace::k2Dot2Curve_GammaNamed: |
| 515 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_Base |
| 516 <SkColorSpace::k2Dot2Curve_GammaNamed, kGamut_ColorS
paceMatch> |
| 517 (srcSpace, srcToDst, dstSpace)); |
| 518 default: |
| 519 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_Base |
| 520 <SkColorSpace::kNonStandard_GammaNamed, kGamut_Color
SpaceMatch> |
| 521 (srcSpace, srcToDst, dstSpace)); |
| 522 } |
| 523 case kFull_ColorSpaceMatch: |
| 524 switch (dstSpace->gammaNamed()) { |
| 525 case SkColorSpace::kSRGB_GammaNamed: |
| 526 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_Base |
| 527 <SkColorSpace::kSRGB_GammaNamed, kFull_ColorSpaceMat
ch> |
| 528 (srcSpace, srcToDst, dstSpace)); |
| 529 case SkColorSpace::k2Dot2Curve_GammaNamed: |
| 530 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_Base |
| 531 <SkColorSpace::k2Dot2Curve_GammaNamed, kFull_ColorSp
aceMatch> |
| 532 (srcSpace, srcToDst, dstSpace)); |
| 533 default: |
| 534 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXf
orm_Base |
| 535 <SkColorSpace::kNonStandard_GammaNamed, kFull_ColorS
paceMatch> |
| 536 (srcSpace, srcToDst, dstSpace)); |
| 537 } |
483 default: | 538 default: |
484 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Base | 539 SkASSERT(false); |
485 <SkColorSpace::kNonStandard_GammaNamed>(srcSpace, srcToDst,
dstSpace)); | 540 return nullptr; |
486 } | 541 } |
487 } | 542 } |
488 | 543 |
489 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 544 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
490 | 545 |
491 static float byte_to_float(uint8_t byte) { | 546 static float byte_to_float(uint8_t byte) { |
492 return ((float) byte) * (1.0f / 255.0f); | 547 return ((float) byte) * (1.0f / 255.0f); |
493 } | 548 } |
494 | 549 |
495 // Clamp to the 0-1 range. | 550 // Clamp to the 0-1 range. |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
612 r = sk_float_round2int(255.0f * clamp_normalized_float(out[0])); | 667 r = sk_float_round2int(255.0f * clamp_normalized_float(out[0])); |
613 g = sk_float_round2int(255.0f * clamp_normalized_float(out[1])); | 668 g = sk_float_round2int(255.0f * clamp_normalized_float(out[1])); |
614 b = sk_float_round2int(255.0f * clamp_normalized_float(out[2])); | 669 b = sk_float_round2int(255.0f * clamp_normalized_float(out[2])); |
615 *dst = SkPackARGB_as_RGBA(0xFF, r, g, b); | 670 *dst = SkPackARGB_as_RGBA(0xFF, r, g, b); |
616 | 671 |
617 src++; | 672 src++; |
618 dst++; | 673 dst++; |
619 } | 674 } |
620 } | 675 } |
621 | 676 |
| 677 enum SwapRB { |
| 678 kNo_SwapRB, |
| 679 kYes_SwapRB, |
| 680 }; |
| 681 |
| 682 static inline void load_matrix(const float matrix[16], |
| 683 Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& r
TgTbT) { |
| 684 rXgXbX = Sk4f::Load(matrix + 0); |
| 685 rYgYbY = Sk4f::Load(matrix + 4); |
| 686 rZgZbZ = Sk4f::Load(matrix + 8); |
| 687 rTgTbT = Sk4f::Load(matrix + 12); |
| 688 } |
| 689 |
| 690 static inline void load_rgb_from_tables(const uint32_t* src, |
| 691 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, |
| 692 const float* const srcTables[3]) { |
| 693 r = { srcTables[0][(src[0] >> 0) & 0xFF], |
| 694 srcTables[0][(src[1] >> 0) & 0xFF], |
| 695 srcTables[0][(src[2] >> 0) & 0xFF], |
| 696 srcTables[0][(src[3] >> 0) & 0xFF], }; |
| 697 g = { srcTables[1][(src[0] >> 8) & 0xFF], |
| 698 srcTables[1][(src[1] >> 8) & 0xFF], |
| 699 srcTables[1][(src[2] >> 8) & 0xFF], |
| 700 srcTables[1][(src[3] >> 8) & 0xFF], }; |
| 701 b = { srcTables[2][(src[0] >> 16) & 0xFF], |
| 702 srcTables[2][(src[1] >> 16) & 0xFF], |
| 703 srcTables[2][(src[2] >> 16) & 0xFF], |
| 704 srcTables[2][(src[3] >> 16) & 0xFF], }; |
| 705 a = 0.0f; // Don't let the compiler complain that |a| is uninitialized. |
| 706 } |
| 707 |
| 708 static inline void load_rgba_from_tables(const uint32_t* src, |
| 709 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, |
| 710 const float* const srcTables[3]) { |
| 711 r = { srcTables[0][(src[0] >> 0) & 0xFF], |
| 712 srcTables[0][(src[1] >> 0) & 0xFF], |
| 713 srcTables[0][(src[2] >> 0) & 0xFF], |
| 714 srcTables[0][(src[3] >> 0) & 0xFF], }; |
| 715 g = { srcTables[1][(src[0] >> 8) & 0xFF], |
| 716 srcTables[1][(src[1] >> 8) & 0xFF], |
| 717 srcTables[1][(src[2] >> 8) & 0xFF], |
| 718 srcTables[1][(src[3] >> 8) & 0xFF], }; |
| 719 b = { srcTables[2][(src[0] >> 16) & 0xFF], |
| 720 srcTables[2][(src[1] >> 16) & 0xFF], |
| 721 srcTables[2][(src[2] >> 16) & 0xFF], |
| 722 srcTables[2][(src[3] >> 16) & 0xFF], }; |
| 723 a = (1.0f / 255.0f) * SkNx_cast<float>(Sk4u::Load(src) >> 24); |
| 724 } |
| 725 |
| 726 static inline void load_rgb_from_tables_1(const uint32_t* src, |
| 727 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&, |
| 728 const float* const srcTables[3]) { |
| 729 // Splat r,g,b across a register each. |
| 730 r = Sk4f(srcTables[0][(*src >> 0) & 0xFF]); |
| 731 g = Sk4f(srcTables[1][(*src >> 8) & 0xFF]); |
| 732 b = Sk4f(srcTables[2][(*src >> 16) & 0xFF]); |
| 733 } |
| 734 |
| 735 static inline void load_rgba_from_tables_1(const uint32_t* src, |
| 736 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, |
| 737 const float* const srcTables[3]) { |
| 738 // Splat r,g,b across a register each. |
| 739 r = Sk4f(srcTables[0][(*src >> 0) & 0xFF]); |
| 740 g = Sk4f(srcTables[1][(*src >> 8) & 0xFF]); |
| 741 b = Sk4f(srcTables[2][(*src >> 16) & 0xFF]); |
| 742 a = (1.0f / 255.0f) * Sk4f(*src >> 24); |
| 743 } |
| 744 |
| 745 static inline void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b,
const Sk4f& a, |
| 746 const Sk4f& rXgXbX, const Sk4f& rYgYbY, const
Sk4f& rZgZbZ, |
| 747 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) { |
| 748 dr = rXgXbX[0]*r + rYgYbY[0]*g + rZgZbZ[0]*b; |
| 749 dg = rXgXbX[1]*r + rYgYbY[1]*g + rZgZbZ[1]*b; |
| 750 db = rXgXbX[2]*r + rYgYbY[2]*g + rZgZbZ[2]*b; |
| 751 da = a; |
| 752 } |
| 753 |
| 754 static inline void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b
, |
| 755 const Sk4f& rXgXbX, const Sk4f& rYgYbY, con
st Sk4f& rZgZbZ, |
| 756 Sk4f& rgba) { |
| 757 rgba = rXgXbX*r + rYgYbY*g + rZgZbZ*b; |
| 758 } |
| 759 |
| 760 static inline void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f&
db) { |
| 761 dr = dr + rTgTbT[0]; |
| 762 dg = dg + rTgTbT[1]; |
| 763 db = db + rTgTbT[2]; |
| 764 } |
| 765 |
| 766 static inline void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) { |
| 767 rgba = rgba + rTgTbT; |
| 768 } |
| 769 |
| 770 static inline void premultiply(Sk4f& dr, Sk4f& dg, Sk4f& db, const Sk4f& da) { |
| 771 dr = da * dr; |
| 772 dg = da * dg; |
| 773 db = da * db; |
| 774 } |
| 775 |
| 776 static inline void premultiply_1(const Sk4f& a, Sk4f& rgba) { |
| 777 rgba = a * rgba; |
| 778 } |
| 779 |
| 780 static inline void store_srgb(void* dst, const uint32_t* src, |
| 781 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, |
| 782 const uint8_t* const[3], SwapRB kSwapRB) { |
| 783 int kRShift = 0; |
| 784 int kGShift = 8; |
| 785 int kBShift = 16; |
| 786 if (kYes_SwapRB == kSwapRB) { |
| 787 kBShift = 0; |
| 788 kRShift = 16; |
| 789 } |
| 790 |
| 791 dr = sk_linear_to_srgb_needs_trunc(dr); |
| 792 dg = sk_linear_to_srgb_needs_trunc(dg); |
| 793 db = sk_linear_to_srgb_needs_trunc(db); |
| 794 |
| 795 dr = sk_clamp_0_255(dr); |
| 796 dg = sk_clamp_0_255(dg); |
| 797 db = sk_clamp_0_255(db); |
| 798 |
| 799 Sk4i da = Sk4i::Load(src) & 0xFF000000; |
| 800 |
| 801 Sk4i rgba = (SkNx_cast<int>(dr) << kRShift) |
| 802 | (SkNx_cast<int>(dg) << kGShift) |
| 803 | (SkNx_cast<int>(db) << kBShift) |
| 804 | (da ); |
| 805 rgba.store(dst); |
| 806 } |
| 807 |
| 808 static inline void store_srgb_1(void* dst, const uint32_t* src, |
| 809 Sk4f& rgba, const Sk4f&, |
| 810 const uint8_t* const[3], SwapRB kSwapRB) { |
| 811 rgba = sk_clamp_0_255(sk_linear_to_srgb_needs_trunc(rgba)); |
| 812 |
| 813 uint32_t tmp; |
| 814 SkNx_cast<uint8_t>(SkNx_cast<int32_t>(rgba)).store(&tmp); |
| 815 tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF); |
| 816 if (kYes_SwapRB == kSwapRB) { |
| 817 tmp = SkSwizzle_RB(tmp); |
| 818 } |
| 819 |
| 820 *(uint32_t*)dst = tmp; |
| 821 } |
| 822 |
| 823 static inline Sk4f linear_to_2dot2(const Sk4f& x) { |
| 824 // x^(29/64) is a very good approximation of the true value, x^(1/2.2). |
| 825 auto x2 = x.rsqrt(), // x^(-1/2) |
| 826 x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(), // x^(-1/32) |
| 827 x64 = x32.rsqrt(); // x^(+1/64) |
| 828 |
| 829 // 29 = 32 - 2 - 1 |
| 830 return 255.0f * x2.invert() * x32 * x64.invert(); |
| 831 } |
| 832 |
| 833 static inline void store_2dot2(void* dst, const uint32_t* src, |
| 834 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, |
| 835 const uint8_t* const[3], SwapRB kSwapRB) { |
| 836 int kRShift = 0; |
| 837 int kGShift = 8; |
| 838 int kBShift = 16; |
| 839 if (kYes_SwapRB == kSwapRB) { |
| 840 kBShift = 0; |
| 841 kRShift = 16; |
| 842 } |
| 843 |
| 844 dr = linear_to_2dot2(dr); |
| 845 dg = linear_to_2dot2(dg); |
| 846 db = linear_to_2dot2(db); |
| 847 |
| 848 dr = sk_clamp_0_255(dr); |
| 849 dg = sk_clamp_0_255(dg); |
| 850 db = sk_clamp_0_255(db); |
| 851 |
| 852 Sk4i da = Sk4i::Load(src) & 0xFF000000; |
| 853 |
| 854 Sk4i rgba = (Sk4f_round(dr) << kRShift) |
| 855 | (Sk4f_round(dg) << kGShift) |
| 856 | (Sk4f_round(db) << kBShift) |
| 857 | (da ); |
| 858 rgba.store(dst); |
| 859 } |
| 860 |
| 861 static inline void store_2dot2_1(void* dst, const uint32_t* src, |
| 862 Sk4f& rgba, const Sk4f&, |
| 863 const uint8_t* const[3], SwapRB kSwapRB) { |
| 864 rgba = sk_clamp_0_255(linear_to_2dot2(rgba)); |
| 865 |
| 866 uint32_t tmp; |
| 867 SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp); |
| 868 tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF); |
| 869 if (kYes_SwapRB == kSwapRB) { |
| 870 tmp = SkSwizzle_RB(tmp); |
| 871 } |
| 872 |
| 873 *(uint32_t*)dst = tmp; |
| 874 } |
| 875 |
| 876 static inline void store_f16(void* dst, const uint32_t* src, |
| 877 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da, |
| 878 const uint8_t* const[3], SwapRB) { |
| 879 Sk4h_store4(dst, SkFloatToHalf_finite(dr), |
| 880 SkFloatToHalf_finite(dg), |
| 881 SkFloatToHalf_finite(db), |
| 882 SkFloatToHalf_finite(da)); |
| 883 } |
| 884 |
| 885 static inline void store_f16_1(void* dst, const uint32_t* src, |
| 886 Sk4f& rgba, const Sk4f& a, |
| 887 const uint8_t* const[3], SwapRB kSwapRB) { |
| 888 rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]); |
| 889 SkFloatToHalf_finite(rgba).store((uint64_t*) dst); |
| 890 } |
| 891 |
| 892 static inline void store_f16_opaque(void* dst, const uint32_t* src, |
| 893 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da, |
| 894 const uint8_t* const[3], SwapRB) { |
| 895 Sk4h_store4(dst, SkFloatToHalf_finite(dr), |
| 896 SkFloatToHalf_finite(dg), |
| 897 SkFloatToHalf_finite(db), |
| 898 SK_Half1); |
| 899 } |
| 900 |
| 901 static inline void store_f16_1_opaque(void* dst, const uint32_t* src, |
| 902 Sk4f& rgba, const Sk4f& a, |
| 903 const uint8_t* const[3], SwapRB kSwapRB) { |
| 904 uint64_t tmp; |
| 905 SkFloatToHalf_finite(rgba).store(&tmp); |
| 906 tmp |= static_cast<uint64_t>(SK_Half1) << 48; |
| 907 *((uint64_t*) dst) = tmp; |
| 908 } |
| 909 |
| 910 static inline void store_generic(void* dst, const uint32_t* src, |
| 911 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, |
| 912 const uint8_t* const dstTables[3], SwapRB kSwap
RB) { |
| 913 int kRShift = 0; |
| 914 int kGShift = 8; |
| 915 int kBShift = 16; |
| 916 if (kYes_SwapRB == kSwapRB) { |
| 917 kBShift = 0; |
| 918 kRShift = 16; |
| 919 } |
| 920 |
| 921 dr = Sk4f::Min(Sk4f::Max(1023.0f * dr, 0.0f), 1023.0f); |
| 922 dg = Sk4f::Min(Sk4f::Max(1023.0f * dg, 0.0f), 1023.0f); |
| 923 db = Sk4f::Min(Sk4f::Max(1023.0f * db, 0.0f), 1023.0f); |
| 924 |
| 925 Sk4i ir = Sk4f_round(dr); |
| 926 Sk4i ig = Sk4f_round(dg); |
| 927 Sk4i ib = Sk4f_round(db); |
| 928 |
| 929 Sk4i da = Sk4i::Load(src) & 0xFF000000; |
| 930 |
| 931 uint32_t* dst32 = (uint32_t*) dst; |
| 932 dst32[0] = dstTables[0][ir[0]] << kRShift |
| 933 | dstTables[1][ig[0]] << kGShift |
| 934 | dstTables[2][ib[0]] << kBShift |
| 935 | da[0]; |
| 936 dst32[1] = dstTables[0][ir[1]] << kRShift |
| 937 | dstTables[1][ig[1]] << kGShift |
| 938 | dstTables[2][ib[1]] << kBShift |
| 939 | da[1]; |
| 940 dst32[2] = dstTables[0][ir[2]] << kRShift |
| 941 | dstTables[1][ig[2]] << kGShift |
| 942 | dstTables[2][ib[2]] << kBShift |
| 943 | da[2]; |
| 944 dst32[3] = dstTables[0][ir[3]] << kRShift |
| 945 | dstTables[1][ig[3]] << kGShift |
| 946 | dstTables[2][ib[3]] << kBShift |
| 947 | da[3]; |
| 948 } |
| 949 |
| 950 static inline void store_generic_1(void* dst, const uint32_t* src, |
| 951 Sk4f& rgba, const Sk4f&, |
| 952 const uint8_t* const dstTables[3], SwapRB kSw
apRB) { |
| 953 rgba = Sk4f::Min(Sk4f::Max(1023.0f * rgba, 0.0f), 1023.0f); |
| 954 |
| 955 Sk4i indices = Sk4f_round(rgba); |
| 956 |
| 957 *((uint32_t*) dst) = dstTables[0][indices[0]] << 0 |
| 958 | dstTables[1][indices[1]] << 8 |
| 959 | dstTables[2][indices[2]] << 16 |
| 960 | (*src & 0xFF000000); |
| 961 } |
| 962 |
| 963 template <SkColorSpace::GammaNamed kDstGamma, |
| 964 ColorSpaceMatch kCSM, |
| 965 SkAlphaType kAlphaType, |
| 966 SwapRB kSwapRB> |
| 967 static void color_xform_RGBA(void* dst, const uint32_t* src, int len, |
| 968 const float* const srcTables[3], const float matrix
[16], |
| 969 const uint8_t* const dstTables[3]) { |
| 970 decltype(store_srgb )* store; |
| 971 decltype(store_srgb_1 )* store_1; |
| 972 decltype(load_rgb_from_tables )* load; |
| 973 decltype(load_rgb_from_tables_1)* load_1; |
| 974 size_t sizeOfDstPixel; |
| 975 switch (kDstGamma) { |
| 976 case SkColorSpace::kSRGB_GammaNamed: |
| 977 load = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_table
s : |
| 978 load_rgb_from_tables
; |
| 979 load_1 = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_table
s_1 : |
| 980 load_rgb_from_tables
_1; |
| 981 store = store_srgb; |
| 982 store_1 = store_srgb_1; |
| 983 sizeOfDstPixel = 4; |
| 984 break; |
| 985 case SkColorSpace::k2Dot2Curve_GammaNamed: |
| 986 load = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_table
s : |
| 987 load_rgb_from_tables
; |
| 988 load_1 = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_table
s_1 : |
| 989 load_rgb_from_tables
_1; |
| 990 store = store_2dot2; |
| 991 store_1 = store_2dot2_1; |
| 992 sizeOfDstPixel = 4; |
| 993 break; |
| 994 case SkColorSpace::kLinear_GammaNamed: |
| 995 load = load_rgba_from_tables; |
| 996 load_1 = load_rgba_from_tables_1; |
| 997 store = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_opaque : |
| 998 store_f16; |
| 999 store_1 = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_1_opaque : |
| 1000 store_f16_1; |
| 1001 sizeOfDstPixel = 8; |
| 1002 break; |
| 1003 case SkColorSpace::kNonStandard_GammaNamed: |
| 1004 load = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_table
s : |
| 1005 load_rgb_from_tables
; |
| 1006 load_1 = (kPremul_SkAlphaType == kAlphaType) ? load_rgba_from_table
s_1 : |
| 1007 load_rgb_from_tables
_1; |
| 1008 store = store_generic; |
| 1009 store_1 = store_generic_1; |
| 1010 sizeOfDstPixel = 4; |
| 1011 break; |
| 1012 } |
| 1013 |
| 1014 Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT; |
| 1015 load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT); |
| 1016 |
| 1017 if (len >= 4) { |
| 1018 // Naively this would be a loop of load-transform-store, but we found it
faster to |
| 1019 // move the N+1th load ahead of the Nth store. We don't bother doing th
is for N<4. |
| 1020 Sk4f r, g, b, a; |
| 1021 load(src, r, g, b, a, srcTables); |
| 1022 src += 4; |
| 1023 len -= 4; |
| 1024 |
| 1025 Sk4f dr, dg, db, da; |
| 1026 while (len >= 4) { |
| 1027 if (kNone_ColorSpaceMatch == kCSM) { |
| 1028 transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db,
da); |
| 1029 translate_gamut(rTgTbT, dr, dg, db); |
| 1030 } else { |
| 1031 dr = r; |
| 1032 dg = g; |
| 1033 db = b; |
| 1034 da = a; |
| 1035 } |
| 1036 |
| 1037 if (kPremul_SkAlphaType == kAlphaType) { |
| 1038 premultiply(dr, dg, db, da); |
| 1039 } |
| 1040 |
| 1041 load(src, r, g, b, a, srcTables); |
| 1042 |
| 1043 store(dst, src - 4, dr, dg, db, da, dstTables, kSwapRB); |
| 1044 dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel); |
| 1045 src += 4; |
| 1046 len -= 4; |
| 1047 } |
| 1048 |
| 1049 if (kNone_ColorSpaceMatch == kCSM) { |
| 1050 transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da); |
| 1051 translate_gamut(rTgTbT, dr, dg, db); |
| 1052 } else { |
| 1053 dr = r; |
| 1054 dg = g; |
| 1055 db = b; |
| 1056 da = a; |
| 1057 } |
| 1058 |
| 1059 if (kPremul_SkAlphaType == kAlphaType) { |
| 1060 premultiply(dr, dg, db, da); |
| 1061 } |
| 1062 |
| 1063 store(dst, src - 4, dr, dg, db, da, dstTables, kSwapRB); |
| 1064 dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel); |
| 1065 } |
| 1066 |
| 1067 while (len > 0) { |
| 1068 Sk4f r, g, b, a; |
| 1069 load_1(src, r, g, b, a, srcTables); |
| 1070 |
| 1071 Sk4f rgba; |
| 1072 if (kNone_ColorSpaceMatch == kCSM) { |
| 1073 transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba); |
| 1074 translate_gamut_1(rTgTbT, rgba); |
| 1075 } else { |
| 1076 rgba = Sk4f(r[0], g[0], b[0], a[0]); |
| 1077 } |
| 1078 |
| 1079 if (kPremul_SkAlphaType == kAlphaType) { |
| 1080 premultiply_1(a, rgba); |
| 1081 } |
| 1082 |
| 1083 store_1(dst, src, rgba, a, dstTables, kSwapRB); |
| 1084 |
| 1085 src += 1; |
| 1086 len -= 1; |
| 1087 dst = SkTAddOffset<void>(dst, sizeOfDstPixel); |
| 1088 } |
| 1089 } |
| 1090 |
622 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 1091 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
623 | 1092 |
624 template <SkColorSpace::GammaNamed kDst> | 1093 template <SkColorSpace::GammaNamed kDst, ColorSpaceMatch kCSM> |
625 SkColorSpaceXform_Base<kDst>::SkColorSpaceXform_Base(const sk_sp<SkColorSpace>&
srcSpace, | 1094 SkColorSpaceXform_Base<kDst, kCSM>::SkColorSpaceXform_Base(const sk_sp<SkColorSp
ace>& srcSpace, |
626 const SkMatrix44& srcToDst, | 1095 const SkMatrix44& src
ToDst, |
627 const sk_sp<SkColorSpace>& d
stSpace) | 1096 const sk_sp<SkColorSp
ace>& dstSpace) |
628 : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) | 1097 : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) |
629 { | 1098 { |
630 srcToDst.asRowMajorf(fSrcToDst); | 1099 srcToDst.asRowMajorf(fSrcToDst); |
631 build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kT
oLinear); | 1100 build_gamma_tables(fSrcGammaTables, fSrcGammaTableStorage, 256, srcSpace, kT
oLinear); |
632 build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, kDstGammaTableSiz
e, | 1101 build_gamma_tables(fDstGammaTables, fDstGammaTableStorage, kDstGammaTableSiz
e, dstSpace, |
633 dstSpace, kFromLinear); | 1102 kFromLinear); |
634 } | 1103 } |
635 | 1104 |
636 template <SkColorSpace::GammaNamed kDst> | 1105 template <SkColorSpace::GammaNamed kDst, ColorSpaceMatch kCSM> |
637 void SkColorSpaceXform_Base<kDst> | 1106 void SkColorSpaceXform_Base<kDst, kCSM> |
638 ::apply(void* dst, const uint32_t* src, int len, SkColorType dstColorType, SkAlp
haType dstAlphaType) | 1107 ::apply(void* dst, const uint32_t* src, int len, SkColorType dstColorType, SkAlp
haType dstAlphaType) |
639 const | 1108 const |
640 { | 1109 { |
| 1110 if (kFull_ColorSpaceMatch == kCSM) { |
| 1111 switch (dstAlphaType) { |
| 1112 case kPremul_SkAlphaType: |
| 1113 // We can't skip the xform since we need to perform a premultipl
y in the |
| 1114 // linear space. |
| 1115 break; |
| 1116 default: |
| 1117 switch (dstColorType) { |
| 1118 case kRGBA_8888_SkColorType: |
| 1119 return (void) memcpy(dst, src, len * sizeof(uint32_t)); |
| 1120 case kBGRA_8888_SkColorType: |
| 1121 return SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len); |
| 1122 case kRGBA_F16_SkColorType: |
| 1123 // There's still work to do to xform to linear F16. |
| 1124 break; |
| 1125 default: |
| 1126 SkASSERT(false); |
| 1127 return; |
| 1128 } |
| 1129 } |
| 1130 } |
| 1131 |
641 if (fColorLUT) { | 1132 if (fColorLUT) { |
642 size_t storageBytes = len * sizeof(uint32_t); | 1133 size_t storageBytes = len * sizeof(uint32_t); |
643 #if defined(GOOGLE3) | 1134 #if defined(GOOGLE3) |
644 // Stack frame size is limited in GOOGLE3. | 1135 // Stack frame size is limited in GOOGLE3. |
645 SkAutoSMalloc<256 * sizeof(uint32_t)> storage(storageBytes); | 1136 SkAutoSMalloc<256 * sizeof(uint32_t)> storage(storageBytes); |
646 #else | 1137 #else |
647 SkAutoSMalloc<1024 * sizeof(uint32_t)> storage(storageBytes); | 1138 SkAutoSMalloc<1024 * sizeof(uint32_t)> storage(storageBytes); |
648 #endif | 1139 #endif |
649 | 1140 |
650 handle_color_lut((uint32_t*) storage.get(), src, len, fColorLUT.get()); | 1141 handle_color_lut((uint32_t*) storage.get(), src, len, fColorLUT.get()); |
651 src = (const uint32_t*) storage.get(); | 1142 src = (const uint32_t*) storage.get(); |
652 } | 1143 } |
653 | 1144 |
654 switch (dstAlphaType) { | 1145 switch (dstAlphaType) { |
655 case kPremul_SkAlphaType: | 1146 case kPremul_SkAlphaType: |
656 switch (dstColorType) { | 1147 switch (dstColorType) { |
657 case kRGBA_8888_SkColorType: | 1148 case kRGBA_8888_SkColorType: |
658 return color_xform_RGBA<kDst, kPremul_SkAlphaType, kNo_SwapR
B> | 1149 return color_xform_RGBA<kDst, kCSM, kPremul_SkAlphaType, kNo
_SwapRB> |
659 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); | 1150 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); |
660 case kBGRA_8888_SkColorType: | 1151 case kBGRA_8888_SkColorType: |
661 return color_xform_RGBA<kDst, kPremul_SkAlphaType, kYes_Swap
RB> | 1152 return color_xform_RGBA<kDst, kCSM, kPremul_SkAlphaType, kYe
s_SwapRB> |
662 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); | 1153 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); |
663 case kRGBA_F16_SkColorType: | 1154 case kRGBA_F16_SkColorType: |
664 return color_xform_RGBA | 1155 return color_xform_RGBA<SkColorSpace::kLinear_GammaNamed, kC
SM, |
665 <SkColorSpace::kLinear_GammaNamed, kPremul_SkAlphaTy
pe, kNo_SwapRB> | 1156 kPremul_SkAlphaType, kNo_SwapRB> |
666 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); | 1157 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); |
667 default: | 1158 default: |
668 SkASSERT(false); | 1159 SkASSERT(false); |
669 return; | 1160 return; |
670 } | 1161 } |
671 break; | 1162 break; |
672 case kUnpremul_SkAlphaType: | 1163 case kUnpremul_SkAlphaType: |
673 switch (dstColorType) { | 1164 switch (dstColorType) { |
674 case kRGBA_8888_SkColorType: | 1165 case kRGBA_8888_SkColorType: |
675 return color_xform_RGBA<kDst, kUnpremul_SkAlphaType, kNo_Swa
pRB> | 1166 return color_xform_RGBA<kDst, kCSM, kUnpremul_SkAlphaType, k
No_SwapRB> |
676 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); | 1167 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); |
677 case kBGRA_8888_SkColorType: | 1168 case kBGRA_8888_SkColorType: |
678 return color_xform_RGBA<kDst, kUnpremul_SkAlphaType, kYes_Sw
apRB> | 1169 return color_xform_RGBA<kDst, kCSM, kUnpremul_SkAlphaType, k
Yes_SwapRB> |
679 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); | 1170 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); |
680 case kRGBA_F16_SkColorType: | 1171 case kRGBA_F16_SkColorType: |
681 return color_xform_RGBA | 1172 return color_xform_RGBA<SkColorSpace::kLinear_GammaNamed, kC
SM, |
682 <SkColorSpace::kLinear_GammaNamed, kUnpremul_SkAlpha
Type, kNo_SwapRB> | 1173 kUnpremul_SkAlphaType, kNo_SwapRB> |
683 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); | 1174 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); |
684 default: | 1175 default: |
685 SkASSERT(false); | 1176 SkASSERT(false); |
686 return; | 1177 return; |
687 } | 1178 } |
688 case kOpaque_SkAlphaType: | 1179 case kOpaque_SkAlphaType: |
689 switch (dstColorType) { | 1180 switch (dstColorType) { |
690 case kRGBA_8888_SkColorType: | 1181 case kRGBA_8888_SkColorType: |
691 return color_xform_RGBA<kDst, kOpaque_SkAlphaType, kNo_SwapR
B> | 1182 return color_xform_RGBA<kDst, kCSM, kOpaque_SkAlphaType, kNo
_SwapRB> |
692 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); | 1183 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); |
693 case kBGRA_8888_SkColorType: | 1184 case kBGRA_8888_SkColorType: |
694 return color_xform_RGBA<kDst, kOpaque_SkAlphaType, kYes_Swap
RB> | 1185 return color_xform_RGBA<kDst, kCSM, kOpaque_SkAlphaType, kYe
s_SwapRB> |
695 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); | 1186 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); |
696 case kRGBA_F16_SkColorType: | 1187 case kRGBA_F16_SkColorType: |
697 return color_xform_RGBA | 1188 return color_xform_RGBA<SkColorSpace::kLinear_GammaNamed, kC
SM, |
698 <SkColorSpace::kLinear_GammaNamed, kOpaque_SkAlphaTy
pe, kNo_SwapRB> | 1189 kOpaque_SkAlphaType, kNo_SwapRB> |
699 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); | 1190 (dst, src, len, fSrcGammaTables, fSrcToDst, fDstGamm
aTables); |
700 default: | 1191 default: |
701 SkASSERT(false); | 1192 SkASSERT(false); |
702 return; | 1193 return; |
703 } | 1194 } |
704 default: | 1195 default: |
705 SkASSERT(false); | 1196 SkASSERT(false); |
706 return; | 1197 return; |
707 } | 1198 } |
708 } | 1199 } |
OLD | NEW |