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

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

Issue 119343003: Fast blurred rectangles on GPU (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Second rework of 119343003 for 10.6 and excluding GMs pending rebaseline Created 6 years, 10 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/effects/SkBlurMask.h ('k') | src/effects/SkBlurMaskFilter.cpp » ('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 /* 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"
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after
664 664
665 if ( x > 0.5f ) { 665 if ( x > 0.5f ) {
666 return 0.5625f - (x3 / 6.0f - 3.0f * x2 * 0.25f + 1.125f * x); 666 return 0.5625f - (x3 / 6.0f - 3.0f * x2 * 0.25f + 1.125f * x);
667 } 667 }
668 if ( x > -0.5f ) { 668 if ( x > -0.5f ) {
669 return 0.5f - (0.75f * x - x3 / 3.0f); 669 return 0.5f - (0.75f * x - x3 / 3.0f);
670 } 670 }
671 return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x); 671 return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x);
672 } 672 }
673 673
674 /* compute_profile allocates and fills in an array of floating 674 /* ComputeBlurProfile allocates and fills in an array of floating
675 point values between 0 and 255 for the profile signature of 675 point values between 0 and 255 for the profile signature of
676 a blurred half-plane with the given blur radius. Since we're 676 a blurred half-plane with the given blur radius. Since we're
677 going to be doing screened multiplications (i.e., 1 - (1-x)(1-y)) 677 going to be doing screened multiplications (i.e., 1 - (1-x)(1-y))
678 all the time, we actually fill in the profile pre-inverted 678 all the time, we actually fill in the profile pre-inverted
679 (already done 255-x). 679 (already done 255-x).
680 680
681 It's the responsibility of the caller to delete the 681 It's the responsibility of the caller to delete the
682 memory returned in profile_out. 682 memory returned in profile_out.
683 */ 683 */
684 684
685 static void compute_profile(SkScalar sigma, unsigned int **profile_out) { 685 void SkBlurMask::ComputeBlurProfile(SkScalar sigma, uint8_t **profile_out) {
686 int size = SkScalarCeilToInt(6*sigma); 686 int size = SkScalarCeilToInt(6*sigma);
687 687
688 int center = size >> 1; 688 int center = size >> 1;
689 unsigned int *profile = SkNEW_ARRAY(unsigned int, size); 689 uint8_t *profile = SkNEW_ARRAY(uint8_t, size);
690 690
691 float invr = 1.f/(2*sigma); 691 float invr = 1.f/(2*sigma);
692 692
693 profile[0] = 255; 693 profile[0] = 255;
694 for (int x = 1 ; x < size ; ++x) { 694 for (int x = 1 ; x < size ; ++x) {
695 float scaled_x = (center - x - .5f) * invr; 695 float scaled_x = (center - x - .5f) * invr;
696 float gi = gaussianIntegral(scaled_x); 696 float gi = gaussianIntegral(scaled_x);
697 profile[x] = 255 - (uint8_t) (255.f * gi); 697 profile[x] = 255 - (uint8_t) (255.f * gi);
698 } 698 }
699 699
700 *profile_out = profile; 700 *profile_out = profile;
701 } 701 }
702 702
703 // TODO MAYBE: Maintain a profile cache to avoid recomputing this for 703 // TODO MAYBE: Maintain a profile cache to avoid recomputing this for
704 // commonly used radii. Consider baking some of the most common blur radii 704 // commonly used radii. Consider baking some of the most common blur radii
705 // directly in as static data? 705 // directly in as static data?
706 706
707 // Implementation adapted from Michael Herf's approach: 707 // Implementation adapted from Michael Herf's approach:
708 // http://stereopsis.com/shadowrect/ 708 // http://stereopsis.com/shadowrect/
709 709
710 static inline unsigned int profile_lookup( unsigned int *profile, int loc, int b lurred_width, int sharp_width ) { 710 uint8_t SkBlurMask::ProfileLookup(const uint8_t *profile, int loc, int blurred_w idth, int sharp_width) {
711 int dx = SkAbs32(((loc << 1) + 1) - blurred_width) - sharp_width; // how far are we from the original edge? 711 int dx = SkAbs32(((loc << 1) + 1) - blurred_width) - sharp_width; // how far are we from the original edge?
712 int ox = dx >> 1; 712 int ox = dx >> 1;
713 if (ox < 0) { 713 if (ox < 0) {
714 ox = 0; 714 ox = 0;
715 } 715 }
716 716
717 return profile[ox]; 717 return profile[ox];
718 } 718 }
719 719
720 void SkBlurMask::ComputeBlurredScanline(uint8_t *pixels, const uint8_t *profile,
721 unsigned int width, SkScalar sigma) {
722
723 unsigned int profile_size = SkScalarCeilToInt(6*sigma);
724 SkAutoTMalloc<uint8_t> horizontalScanline(width);
725
726 unsigned int sw = width - profile_size;
727 // nearest odd number less than the profile size represents the center
728 // of the (2x scaled) profile
729 int center = ( profile_size & ~1 ) - 1;
730
731 int w = sw - center;
732
733 for (unsigned int x = 0 ; x < width ; ++x) {
734 if (profile_size <= sw) {
735 pixels[x] = ProfileLookup(profile, x, width, w);
736 } else {
737 float span = float(sw)/(2*sigma);
738 float giX = 1.5f - (x+.5f)/(2*sigma);
739 pixels[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegra l(giX + span)));
740 }
741 }
742 }
743
720 bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src, 744 bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
721 SkScalar radius, Style style, 745 SkScalar radius, Style style,
722 SkIPoint *margin, SkMask::CreateMode createMode) { 746 SkIPoint *margin, SkMask::CreateMode createMode) {
723 return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius), 747 return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius),
724 dst, src, 748 dst, src,
725 style, margin, createMode); 749 style, margin, createMode);
726 } 750 }
727 751
728 bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, 752 bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst,
729 const SkRect &src, Style style, 753 const SkRect &src, Style style,
(...skipping 20 matching lines...) Expand all
750 if (createMode == SkMask::kJustComputeBounds_CreateMode) { 774 if (createMode == SkMask::kJustComputeBounds_CreateMode) {
751 if (style == kInner_Style) { 775 if (style == kInner_Style) {
752 dst->fBounds.set(SkScalarRoundToInt(src.fLeft), 776 dst->fBounds.set(SkScalarRoundToInt(src.fLeft),
753 SkScalarRoundToInt(src.fTop), 777 SkScalarRoundToInt(src.fTop),
754 SkScalarRoundToInt(src.fRight), 778 SkScalarRoundToInt(src.fRight),
755 SkScalarRoundToInt(src.fBottom)); // restore trimme d bounds 779 SkScalarRoundToInt(src.fBottom)); // restore trimme d bounds
756 dst->fRowBytes = sw; 780 dst->fRowBytes = sw;
757 } 781 }
758 return true; 782 return true;
759 } 783 }
760 unsigned int *profile = NULL; 784 uint8_t *profile = NULL;
761 785
762 compute_profile(sigma, &profile); 786 ComputeBlurProfile(sigma, &profile);
763 SkAutoTDeleteArray<unsigned int> ada(profile); 787 SkAutoTDeleteArray<uint8_t> ada(profile);
764 788
765 size_t dstSize = dst->computeImageSize(); 789 size_t dstSize = dst->computeImageSize();
766 if (0 == dstSize) { 790 if (0 == dstSize) {
767 return false; // too big to allocate, abort 791 return false; // too big to allocate, abort
768 } 792 }
769 793
770 uint8_t* dp = SkMask::AllocImage(dstSize); 794 uint8_t* dp = SkMask::AllocImage(dstSize);
771 795
772 dst->fImage = dp; 796 dst->fImage = dp;
773 797
774 int dstHeight = dst->fBounds.height(); 798 int dstHeight = dst->fBounds.height();
775 int dstWidth = dst->fBounds.width(); 799 int dstWidth = dst->fBounds.width();
776 800
777 // nearest odd number less than the profile size represents the center
778 // of the (2x scaled) profile
779 int center = ( profile_size & ~1 ) - 1;
780
781 int w = sw - center;
782 int h = sh - center;
783
784 uint8_t *outptr = dp; 801 uint8_t *outptr = dp;
785 802
786 SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); 803 SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth);
787 804 SkAutoTMalloc<uint8_t> verticalScanline(dstHeight);
788 for (int x = 0 ; x < dstWidth ; ++x) { 805
789 if (profile_size <= sw) { 806 ComputeBlurredScanline(horizontalScanline, profile, dstWidth, sigma);
790 horizontalScanline[x] = profile_lookup(profile, x, dstWidth, w); 807 ComputeBlurredScanline(verticalScanline, profile, dstHeight, sigma);
791 } else {
792 float span = float(sw)/(2*sigma);
793 float giX = 1.5f - (x+.5f)/(2*sigma);
794 horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - ga ussianIntegral(giX + span)));
795 }
796 }
797 808
798 for (int y = 0 ; y < dstHeight ; ++y) { 809 for (int y = 0 ; y < dstHeight ; ++y) {
799 unsigned int profile_y;
800 if (profile_size <= sh) {
801 profile_y = profile_lookup(profile, y, dstHeight, h);
802 } else {
803 float span = float(sh)/(2*sigma);
804 float giY = 1.5f - (y+.5f)/(2*sigma);
805 profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIntegr al(giY + span)));
806 }
807
808 for (int x = 0 ; x < dstWidth ; x++) { 810 for (int x = 0 ; x < dstWidth ; x++) {
809 unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], profi le_y); 811 unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], verti calScanline[y]);
810 *(outptr++) = maskval; 812 *(outptr++) = maskval;
811 } 813 }
812 } 814 }
813 815
814 if (style == kInner_Style) { 816 if (style == kInner_Style) {
815 // now we allocate the "real" dst, mirror the size of src 817 // now we allocate the "real" dst, mirror the size of src
816 size_t srcSize = (size_t)(src.width() * src.height()); 818 size_t srcSize = (size_t)(src.width() * src.height());
817 if (0 == srcSize) { 819 if (0 == srcSize) {
818 return false; // too big to allocate, abort 820 return false; // too big to allocate, abort
819 } 821 }
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
992 (void)autoCall.detach(); 994 (void)autoCall.detach();
993 } 995 }
994 996
995 if (style == kInner_Style) { 997 if (style == kInner_Style) {
996 dst->fBounds = src.fBounds; // restore trimmed bounds 998 dst->fBounds = src.fBounds; // restore trimmed bounds
997 dst->fRowBytes = src.fRowBytes; 999 dst->fRowBytes = src.fRowBytes;
998 } 1000 }
999 1001
1000 return true; 1002 return true;
1001 } 1003 }
OLDNEW
« no previous file with comments | « src/effects/SkBlurMask.h ('k') | src/effects/SkBlurMaskFilter.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698