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

Side by Side Diff: src/effects/SkBlurMask.cpp

Issue 471473002: Optimize CSS box-shadow performance (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: store SkMask and SkCachedData in cache Created 6 years, 2 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
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkBlurMask.h" 10 #include "SkBlurMask.h"
11 #include "SkCachedData.h"
11 #include "SkMath.h" 12 #include "SkMath.h"
13 #include "SkResourceCache.h"
12 #include "SkTemplates.h" 14 #include "SkTemplates.h"
13 #include "SkEndian.h" 15 #include "SkEndian.h"
14 16
15 17
16 // This constant approximates the scaling done in the software path's 18 // This constant approximates the scaling done in the software path's
17 // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). 19 // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
18 // IMHO, it actually should be 1: we blur "less" than we should do 20 // IMHO, it actually should be 1: we blur "less" than we should do
19 // according to the CSS and canvas specs, simply because Safari does the same. 21 // according to the CSS and canvas specs, simply because Safari does the same.
20 // Firefox used to do the same too, until 4.0 where they fixed it. So at some 22 // Firefox used to do the same too, until 4.0 where they fixed it. So at some
21 // point we should probably get rid of these scaling constants and rebaseline 23 // point we should probably get rid of these scaling constants and rebaseline
(...skipping 450 matching lines...) Expand 10 before | Expand all | Expand 10 after
472 474
473 /////////////////////////////////////////////////////////////////////////////// 475 ///////////////////////////////////////////////////////////////////////////////
474 476
475 // we use a local function to wrap the class static method to work around 477 // we use a local function to wrap the class static method to work around
476 // a bug in gcc98 478 // a bug in gcc98
477 void SkMask_FreeImage(uint8_t* image); 479 void SkMask_FreeImage(uint8_t* image);
478 void SkMask_FreeImage(uint8_t* image) { 480 void SkMask_FreeImage(uint8_t* image) {
479 SkMask::FreeImage(image); 481 SkMask::FreeImage(image);
480 } 482 }
481 483
482 bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, 484 bool SkBlurMask::BoxBlur(SkMask* dst, SkCachedData** data, const SkMask& src,
483 SkScalar sigma, SkBlurStyle style, SkBlurQuality qualit y, 485 SkScalar sigma, SkBlurStyle style, SkBlurQuality qualit y,
484 SkIPoint* margin, bool force_quality) { 486 SkIPoint* margin, bool force_quality) {
485 487
486 if (src.fFormat != SkMask::kA8_Format) { 488 if (src.fFormat != SkMask::kA8_Format) {
487 return false; 489 return false;
488 } 490 }
489 491
490 // Force high quality off for small radii (performance) 492 // Force high quality off for small radii (performance)
491 if (!force_quality && sigma <= SkIntToScalar(2)) { 493 if (!force_quality && sigma <= SkIntToScalar(2)) {
492 quality = kLow_SkBlurQuality; 494 quality = kLow_SkBlurQuality;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 536
535 if (src.fImage) { 537 if (src.fImage) {
536 size_t dstSize = dst->computeImageSize(); 538 size_t dstSize = dst->computeImageSize();
537 if (0 == dstSize) { 539 if (0 == dstSize) {
538 return false; // too big to allocate, abort 540 return false; // too big to allocate, abort
539 } 541 }
540 542
541 int sw = src.fBounds.width(); 543 int sw = src.fBounds.width();
542 int sh = src.fBounds.height(); 544 int sh = src.fBounds.height();
543 const uint8_t* sp = src.fImage; 545 const uint8_t* sp = src.fImage;
544 uint8_t* dp = SkMask::AllocImage(dstSize); 546 uint8_t* dp = NULL;
545 SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp); 547 SkCachedData* tmpData = NULL;
548 if (NULL == data) {
reed1 2014/10/21 21:32:55 we have to repeat this pattern pretty often. This
549 dp = SkMask::AllocImage(dstSize);
550 } else {
551 tmpData = SkResourceCache::NewCachedData(dstSize);
552 dp = (uint8_t*)(tmpData->data());
553 }
546 554
547 // build the blurry destination 555 // build the blurry destination
548 SkAutoTMalloc<uint8_t> tmpBuffer(dstSize); 556 SkAutoTMalloc<uint8_t> tmpBuffer(dstSize);
549 uint8_t* tp = tmpBuffer.get(); 557 uint8_t* tp = tmpBuffer.get();
550 int w = sw, h = sh; 558 int w = sw, h = sh;
551 559
552 if (outerWeight == 255) { 560 if (outerWeight == 255) {
553 int loRadius, hiRadius; 561 int loRadius, hiRadius;
554 get_adjusted_radii(passRadius, &loRadius, &hiRadius); 562 get_adjusted_radii(passRadius, &loRadius, &hiRadius);
555 if (kHigh_SkBlurQuality == quality) { 563 if (kHigh_SkBlurQuality == quality) {
(...skipping 19 matching lines...) Expand all
575 h = boxBlurInterp(tp, h, dp, ry, h, w, false, outerW eight); 583 h = boxBlurInterp(tp, h, dp, ry, h, w, false, outerW eight);
576 h = boxBlurInterp(dp, h, tp, ry, h, w, false, outerW eight); 584 h = boxBlurInterp(dp, h, tp, ry, h, w, false, outerW eight);
577 h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWe ight); 585 h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWe ight);
578 } else { 586 } else {
579 w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, true, outerWe ight); 587 w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, true, outerWe ight);
580 h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWe ight); 588 h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWe ight);
581 } 589 }
582 } 590 }
583 591
584 dst->fImage = dp; 592 dst->fImage = dp;
593 if (data) {
594 *data = tmpData;
595 (*data)->ref();
596 }
585 // if need be, alloc the "real" dst (same size as src) and copy/merge 597 // if need be, alloc the "real" dst (same size as src) and copy/merge
586 // the blur into it (applying the src) 598 // the blur into it (applying the src)
587 if (style == kInner_SkBlurStyle) { 599 if (style == kInner_SkBlurStyle) {
588 // now we allocate the "real" dst, mirror the size of src 600 // now we allocate the "real" dst, mirror the size of src
589 size_t srcSize = src.computeImageSize(); 601 size_t srcSize = src.computeImageSize();
590 if (0 == srcSize) { 602 if (0 == srcSize) {
603 if (NULL == data) {
604 SkMask::FreeImage(dp);
605 } else {
606 tmpData->unref();
607 (*data)->unref();
608 }
591 return false; // too big to allocate, abort 609 return false; // too big to allocate, abort
592 } 610 }
593 dst->fImage = SkMask::AllocImage(srcSize); 611 if (NULL == data) {
612 dst->fImage = SkMask::AllocImage(srcSize);
613 } else {
614 (*data)->unref();
615 (*data) = SkResourceCache::NewCachedData(srcSize);
616 dst->fImage = (uint8_t*)((*data)->data());
617 }
594 merge_src_with_blur(dst->fImage, src.fRowBytes, 618 merge_src_with_blur(dst->fImage, src.fRowBytes,
595 sp, src.fRowBytes, 619 sp, src.fRowBytes,
596 dp + passCount * (rx + ry * dst->fRowBytes), 620 dp + passCount * (rx + ry * dst->fRowBytes),
597 dst->fRowBytes, sw, sh); 621 dst->fRowBytes, sw, sh);
598 SkMask::FreeImage(dp); 622 if (NULL == data) {
623 SkMask::FreeImage(dp);
reed1 2014/10/21 21:32:55 We don't have the if/else pattern here. How is thi
624 }
599 } else if (style != kNormal_SkBlurStyle) { 625 } else if (style != kNormal_SkBlurStyle) {
600 clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes), 626 clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes),
601 dst->fRowBytes, sp, src.fRowBytes, sw, sh, style); 627 dst->fRowBytes, sp, src.fRowBytes, sw, sh, style);
602 } 628 }
603 (void)autoCall.detach(); 629 if (data) {
630 tmpData->unref();
631 }
604 } 632 }
605 633
606 if (style == kInner_SkBlurStyle) { 634 if (style == kInner_SkBlurStyle) {
607 dst->fBounds = src.fBounds; // restore trimmed bounds 635 dst->fBounds = src.fBounds; // restore trimmed bounds
608 dst->fRowBytes = src.fRowBytes; 636 dst->fRowBytes = src.fRowBytes;
609 } 637 }
610 638
611 return true; 639 return true;
612 } 640 }
613 641
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
730 if (profile_size <= sw) { 758 if (profile_size <= sw) {
731 pixels[x] = ProfileLookup(profile, x, width, w); 759 pixels[x] = ProfileLookup(profile, x, width, w);
732 } else { 760 } else {
733 float span = float(sw)/(2*sigma); 761 float span = float(sw)/(2*sigma);
734 float giX = 1.5f - (x+.5f)/(2*sigma); 762 float giX = 1.5f - (x+.5f)/(2*sigma);
735 pixels[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegra l(giX + span))); 763 pixels[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegra l(giX + span)));
736 } 764 }
737 } 765 }
738 } 766 }
739 767
740 bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, 768 bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, SkCachedData** data,
741 const SkRect &src, SkBlurStyle style, 769 const SkRect &src, SkBlurStyle style,
742 SkIPoint *margin, SkMask::CreateMode createMode) { 770 SkIPoint *margin, SkMask::CreateMode createMode) {
743 int profile_size = SkScalarCeilToInt(6*sigma); 771 int profile_size = SkScalarCeilToInt(6*sigma);
744 772
745 int pad = profile_size/2; 773 int pad = profile_size/2;
746 if (margin) { 774 if (margin) {
747 margin->set( pad, pad ); 775 margin->set( pad, pad );
748 } 776 }
749 777
750 dst->fBounds.set(SkScalarRoundToInt(src.fLeft - pad), 778 dst->fBounds.set(SkScalarRoundToInt(src.fLeft - pad),
(...skipping 21 matching lines...) Expand all
772 uint8_t *profile = NULL; 800 uint8_t *profile = NULL;
773 801
774 ComputeBlurProfile(sigma, &profile); 802 ComputeBlurProfile(sigma, &profile);
775 SkAutoTDeleteArray<uint8_t> ada(profile); 803 SkAutoTDeleteArray<uint8_t> ada(profile);
776 804
777 size_t dstSize = dst->computeImageSize(); 805 size_t dstSize = dst->computeImageSize();
778 if (0 == dstSize) { 806 if (0 == dstSize) {
779 return false; // too big to allocate, abort 807 return false; // too big to allocate, abort
780 } 808 }
781 809
782 uint8_t* dp = SkMask::AllocImage(dstSize); 810 uint8_t* dp = NULL;
811 SkCachedData* tmpData = NULL;
812 if (NULL == data) {
813 dp = SkMask::AllocImage(dstSize);
814 } else {
815 tmpData = SkResourceCache::NewCachedData(dstSize);
816 dp = (uint8_t*)(tmpData->data());
817 }
783 818
784 dst->fImage = dp; 819 dst->fImage = dp;
820 if (data) {
821 *data = tmpData;
822 (*data)->ref();
823 }
785 824
786 int dstHeight = dst->fBounds.height(); 825 int dstHeight = dst->fBounds.height();
787 int dstWidth = dst->fBounds.width(); 826 int dstWidth = dst->fBounds.width();
788 827
789 uint8_t *outptr = dp; 828 uint8_t *outptr = dp;
790 829
791 SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); 830 SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth);
792 SkAutoTMalloc<uint8_t> verticalScanline(dstHeight); 831 SkAutoTMalloc<uint8_t> verticalScanline(dstHeight);
793 832
794 ComputeBlurredScanline(horizontalScanline, profile, dstWidth, sigma); 833 ComputeBlurredScanline(horizontalScanline, profile, dstWidth, sigma);
795 ComputeBlurredScanline(verticalScanline, profile, dstHeight, sigma); 834 ComputeBlurredScanline(verticalScanline, profile, dstHeight, sigma);
796 835
797 for (int y = 0 ; y < dstHeight ; ++y) { 836 for (int y = 0 ; y < dstHeight ; ++y) {
798 for (int x = 0 ; x < dstWidth ; x++) { 837 for (int x = 0 ; x < dstWidth ; x++) {
799 unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], verti calScanline[y]); 838 unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], verti calScanline[y]);
800 *(outptr++) = maskval; 839 *(outptr++) = maskval;
801 } 840 }
802 } 841 }
803 842
804 if (style == kInner_SkBlurStyle) { 843 if (style == kInner_SkBlurStyle) {
805 // now we allocate the "real" dst, mirror the size of src 844 // now we allocate the "real" dst, mirror the size of src
806 size_t srcSize = (size_t)(src.width() * src.height()); 845 size_t srcSize = (size_t)(src.width() * src.height());
807 if (0 == srcSize) { 846 if (0 == srcSize) {
847 if (NULL == data) {
848 SkMask::FreeImage(dp);
849 } else {
850 tmpData->unref();
851 (*data)->unref();
852 }
808 return false; // too big to allocate, abort 853 return false; // too big to allocate, abort
809 } 854 }
810 dst->fImage = SkMask::AllocImage(srcSize); 855 if (NULL == data) {
856 dst->fImage = SkMask::AllocImage(srcSize);
857 } else {
858 (*data)->unref();
859 (*data) = SkResourceCache::NewCachedData(srcSize);
860 dst->fImage = (uint8_t*)((*data)->data());
861 }
811 for (int y = 0 ; y < sh ; y++) { 862 for (int y = 0 ; y < sh ; y++) {
812 uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad; 863 uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad;
813 uint8_t *inner_scanline = dst->fImage + y*sw; 864 uint8_t *inner_scanline = dst->fImage + y*sw;
814 memcpy(inner_scanline, blur_scanline, sw); 865 memcpy(inner_scanline, blur_scanline, sw);
815 } 866 }
816 SkMask::FreeImage(dp); 867 if (NULL == data) {
868 SkMask::FreeImage(dp);
869 }
817 870
818 dst->fBounds.set(SkScalarRoundToInt(src.fLeft), 871 dst->fBounds.set(SkScalarRoundToInt(src.fLeft),
819 SkScalarRoundToInt(src.fTop), 872 SkScalarRoundToInt(src.fTop),
820 SkScalarRoundToInt(src.fRight), 873 SkScalarRoundToInt(src.fRight),
821 SkScalarRoundToInt(src.fBottom)); // restore trimmed bo unds 874 SkScalarRoundToInt(src.fBottom)); // restore trimmed bo unds
822 dst->fRowBytes = sw; 875 dst->fRowBytes = sw;
823 876
824 } else if (style == kOuter_SkBlurStyle) { 877 } else if (style == kOuter_SkBlurStyle) {
825 for (int y = pad ; y < dstHeight-pad ; y++) { 878 for (int y = pad ; y < dstHeight-pad ; y++) {
826 uint8_t *dst_scanline = dp + y*dstWidth + pad; 879 uint8_t *dst_scanline = dp + y*dstWidth + pad;
827 memset(dst_scanline, 0, sw); 880 memset(dst_scanline, 0, sw);
828 } 881 }
829 } else if (style == kSolid_SkBlurStyle) { 882 } else if (style == kSolid_SkBlurStyle) {
830 for (int y = pad ; y < dstHeight-pad ; y++) { 883 for (int y = pad ; y < dstHeight-pad ; y++) {
831 uint8_t *dst_scanline = dp + y*dstWidth + pad; 884 uint8_t *dst_scanline = dp + y*dstWidth + pad;
832 memset(dst_scanline, 0xff, sw); 885 memset(dst_scanline, 0xff, sw);
833 } 886 }
834 } 887 }
888 if (data) {
889 tmpData->unref();
890 }
835 // normal and solid styles are the same for analytic rect blurs, so don't 891 // normal and solid styles are the same for analytic rect blurs, so don't
836 // need to handle solid specially. 892 // need to handle solid specially.
837 893
838 return true; 894 return true;
839 } 895 }
840 896
841 bool SkBlurMask::BlurRRect(SkScalar sigma, SkMask *dst, 897 bool SkBlurMask::BlurRRect(SkScalar sigma, SkMask *dst, SkCachedData** data,
842 const SkRRect &src, SkBlurStyle style, 898 const SkRRect &src, SkBlurStyle style,
843 SkIPoint *margin, SkMask::CreateMode createMode) { 899 SkIPoint *margin, SkMask::CreateMode createMode) {
844 // Temporary for now -- always fail, should cause caller to fall back 900 // Temporary for now -- always fail, should cause caller to fall back
845 // to old path. Plumbing just to land API and parallelize effort. 901 // to old path. Plumbing just to land API and parallelize effort.
846 902
847 return false; 903 return false;
848 } 904 }
849 905
850 // The "simple" blur is a direct implementation of separable convolution with a discrete 906 // The "simple" blur is a direct implementation of separable convolution with a discrete
851 // gaussian kernel. It's "ground truth" in a sense; too slow to be used, but ve ry 907 // gaussian kernel. It's "ground truth" in a sense; too slow to be used, but ve ry
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
987 (void)autoCall.detach(); 1043 (void)autoCall.detach();
988 } 1044 }
989 1045
990 if (style == kInner_SkBlurStyle) { 1046 if (style == kInner_SkBlurStyle) {
991 dst->fBounds = src.fBounds; // restore trimmed bounds 1047 dst->fBounds = src.fBounds; // restore trimmed bounds
992 dst->fRowBytes = src.fRowBytes; 1048 dst->fRowBytes = src.fRowBytes;
993 } 1049 }
994 1050
995 return true; 1051 return true;
996 } 1052 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698