Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(235)

Side by Side Diff: src/core/SkColorSpaceXform.cpp

Issue 2206403003: Optimize color xforms when src and dst are matching (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Response to comments Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkColorSpaceXform.h ('k') | src/core/SkColorSpaceXformOpts.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « src/core/SkColorSpaceXform.h ('k') | src/core/SkColorSpaceXformOpts.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698