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

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

Issue 248613004: Fast path for blurred round rects -- blur a small 9patch rect on the CPU (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: merge fully with Mike's new reorg" Created 6 years, 7 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.cpp ('k') | src/images/SkImageDecoder_libwebp.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 #include "SkBlurMaskFilter.h" 9 #include "SkBlurMaskFilter.h"
10 #include "SkBlurMask.h" 10 #include "SkBlurMask.h"
11 #include "SkGpuBlurUtils.h" 11 #include "SkGpuBlurUtils.h"
12 #include "SkReadBuffer.h" 12 #include "SkReadBuffer.h"
13 #include "SkWriteBuffer.h" 13 #include "SkWriteBuffer.h"
14 #include "SkMaskFilter.h" 14 #include "SkMaskFilter.h"
15 #include "SkRRect.h" 15 #include "SkRRect.h"
16 #include "SkRTConf.h" 16 #include "SkRTConf.h"
17 #include "SkStringUtils.h" 17 #include "SkStringUtils.h"
18 #include "SkStrokeRec.h" 18 #include "SkStrokeRec.h"
19 19
20 #if SK_SUPPORT_GPU 20 #if SK_SUPPORT_GPU
21 #include "GrContext.h" 21 #include "GrContext.h"
22 #include "GrTexture.h" 22 #include "GrTexture.h"
23 #include "GrEffect.h" 23 #include "GrEffect.h"
24 #include "gl/GrGLEffect.h" 24 #include "gl/GrGLEffect.h"
25 #include "effects/GrSimpleTextureEffect.h" 25 #include "effects/GrSimpleTextureEffect.h"
26 #include "GrTBackendEffectFactory.h" 26 #include "GrTBackendEffectFactory.h"
27 #include "SkGrPixelRef.h" 27 #include "SkGrPixelRef.h"
28 #include "SkDraw.h"
28 #endif 29 #endif
29 30
30 class SkBlurMaskFilterImpl : public SkMaskFilter { 31 class SkBlurMaskFilterImpl : public SkMaskFilter {
31 public: 32 public:
32 SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle, uint32_t flags); 33 SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle, uint32_t flags);
33 34
34 // overrides from SkMaskFilter 35 // overrides from SkMaskFilter
35 virtual SkMask::Format getFormat() const SK_OVERRIDE; 36 virtual SkMask::Format getFormat() const SK_OVERRIDE;
36 virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, 37 virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
37 SkIPoint* margin) const SK_OVERRIDE; 38 SkIPoint* margin) const SK_OVERRIDE;
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 } 245 }
245 return true; 246 return true;
246 } 247 }
247 248
248 static bool rect_exceeds(const SkRect& r, SkScalar v) { 249 static bool rect_exceeds(const SkRect& r, SkScalar v) {
249 return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v || 250 return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
250 r.width() > v || r.height() > v; 251 r.width() > v || r.height() > v;
251 } 252 }
252 253
253 #ifdef SK_IGNORE_FAST_RRECT_BLUR 254 #ifdef SK_IGNORE_FAST_RRECT_BLUR
254 SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticRRect", fa lse, "Use the faster analytic blur approach for ninepatch rects" ); 255 SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect" , false, "Use the faster analytic blur approach for ninepatch rects" );
255 #else 256 #else
256 SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticRRect", tr ue, "Use the faster analytic blur approach for ninepatch round rects" ); 257 SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect" , true, "Use the faster analytic blur approach for ninepatch round rects" );
257 #endif 258 #endif
258 259
259 SkMaskFilter::FilterReturn 260 SkMaskFilter::FilterReturn
260 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma trix, 261 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma trix,
261 const SkIRect& clipBounds, 262 const SkIRect& clipBounds,
262 NinePatch* patch) const { 263 NinePatch* patch) const {
263 SkASSERT(patch != NULL); 264 SkASSERT(patch != NULL);
264 switch (rrect.getType()) { 265 switch (rrect.getType()) {
265 case SkRRect::kUnknown_Type: 266 case SkRRect::kUnknown_Type:
266 // Unknown should never be returned. 267 // Unknown should never be returned.
(...skipping 535 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 return false; 803 return false;
803 } 804 }
804 805
805 806
806 grp->addCoverageEffect(effect); 807 grp->addCoverageEffect(effect);
807 808
808 context->drawRect(*grp, rect); 809 context->drawRect(*grp, rect);
809 return true; 810 return true;
810 } 811 }
811 812
813 class GrGLRRectBlurEffect;
814
815 class GrRRectBlurEffect : public GrEffect {
816 public:
817
818 static GrEffectRef* Create(GrContext* context, float sigma, const SkRRect&);
819
820 virtual ~GrRRectBlurEffect() {};
821 static const char* Name() { return "GrRRectBlur"; }
822
823 const SkRRect& getRRect() const { return fRRect; }
824 float getSigma() const { return fSigma; }
825
826 typedef GrGLRRectBlurEffect GLEffect;
827
828 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags ) const SK_OVERRIDE;
829
830 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
831
832 private:
833 GrRRectBlurEffect(float sigma, const SkRRect&, GrTexture* profileTexture);
834
835 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
836
837 SkRRect fRRect;
838 float fSigma;
839 GrTextureAccess fNinePatchAccess;
840
841 GR_DECLARE_EFFECT_TEST;
842
843 typedef GrEffect INHERITED;
844 };
845
846
847 GrEffectRef* GrRRectBlurEffect::Create(GrContext* context, float sigma, const Sk RRect& rrect) {
848 if (!rrect.isSimpleCircular()) {
849 SkDebugf( "not simple circular\n" );
850 return NULL;
851 }
852
853 // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
854 // sufficiently small relative to both the size of the corner radius and the
855 // width (and height) of the rrect.
856
857 unsigned int blurRadius = 3*SkScalarCeilToInt(sigma-1/6.0f);
858 unsigned int cornerRadius = SkScalarCeilToInt(rrect.getSimpleRadii().x());
859 if (cornerRadius + blurRadius > rrect.width()/2 ||
860 cornerRadius + blurRadius > rrect.height()/2) {
861 return NULL;
862 }
863
864 static const GrCacheID::Domain gRRectBlurDomain = GrCacheID::GenerateDomain( );
865 GrCacheID::Key key;
866 memset(&key, 0, sizeof(key));
867 key.fData32[0] = blurRadius;
868 key.fData32[1] = cornerRadius;
869 GrCacheID blurRRectNinePatchID(gRRectBlurDomain, key);
870
871 GrTextureParams params;
872 params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
873
874 unsigned int smallRectSide = 2*(blurRadius + cornerRadius) + 1;
875 unsigned int texSide = smallRectSide + 2*blurRadius;
876 GrTextureDesc texDesc;
877 texDesc.fWidth = texSide;
878 texDesc.fHeight = texSide;
879 texDesc.fConfig = kAlpha_8_GrPixelConfig;
880
881 GrTexture *blurNinePatchTexture = context->findAndRefTexture(texDesc, blurRR ectNinePatchID, &params);
882
883 if (NULL == blurNinePatchTexture) {
884 SkMask mask;
885
886 mask.fBounds = SkIRect::MakeWH(smallRectSide, smallRectSide);
887 mask.fFormat = SkMask::kA8_Format;
888 mask.fRowBytes = mask.fBounds.width();
889 mask.fImage = SkMask::AllocImage(mask.computeTotalImageSize());
890 SkAutoMaskFreeImage amfi(mask.fImage);
891
892 memset(mask.fImage, 0, mask.computeTotalImageSize());
893
894 SkRect smallRect;
895 smallRect.setWH(SkIntToScalar(smallRectSide), SkIntToScalar(smallRectSid e));
896
897 SkRRect smallRRect;
898 smallRRect.setRectXY(smallRect, SkIntToScalar(cornerRadius), SkIntToScal ar(cornerRadius));
899
900 SkPath path;
901 path.addRRect( smallRRect );
902
903 SkDraw::DrawToMask(path, &mask.fBounds, NULL, NULL, &mask, SkMask::kJust RenderImage_CreateMode, SkPaint::kFill_Style);
904
905 SkMask blurred_mask;
906 SkBlurMask::BoxBlur(&blurred_mask, mask, sigma, kNormal_SkBlurStyle, kHi gh_SkBlurQuality, NULL, true );
907
908 blurNinePatchTexture = context->createTexture(&params, texDesc, blurRRec tNinePatchID, blurred_mask.fImage, 0);
909 }
910
911 if (NULL == blurNinePatchTexture) {
912 return NULL;
913 }
914
915 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrRRectBlurEffect,
916 (sigma, rrect, blurNinePat chTexture))));
917 }
918
919 void GrRRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* val idFlags) const {
920 *validFlags = 0;
921 }
922
923 const GrBackendEffectFactory& GrRRectBlurEffect::getFactory() const {
924 return GrTBackendEffectFactory<GrRRectBlurEffect>::getInstance();
925 }
926
927 GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTextur e *ninePatchTexture)
928 : fRRect(rrect),
929 fSigma(sigma),
930 fNinePatchAccess(ninePatchTexture) {
931 this->addTextureAccess(&fNinePatchAccess);
932 this->setWillReadFragmentPosition();
933 }
934
935 bool GrRRectBlurEffect::onIsEqual(const GrEffect& other) const {
936 const GrRRectBlurEffect& rrbe = CastEffect<GrRRectBlurEffect>(other);
937 return fRRect.getSimpleRadii().fX == rrbe.fRRect.getSimpleRadii().fX && fSig ma == rrbe.fSigma;
938 }
939
940 //////////////////////////////////////////////////////////////////////////////
941
942 GR_DEFINE_EFFECT_TEST(GrRRectBlurEffect);
943
944 GrEffectRef* GrRRectBlurEffect::TestCreate(SkRandom* random,
945 GrContext* context,
946 const GrDrawTargetCaps& caps,
947 GrTexture*[]) {
948 SkScalar w = random->nextRangeScalar(100.f, 1000.f);
949 SkScalar h = random->nextRangeScalar(100.f, 1000.f);
950 SkScalar r = random->nextRangeF(1.f, 9.f);
951 SkScalar sigma = random->nextRangeF(1.f,10.f);
952 SkRRect rrect;
953 rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
954 return GrRRectBlurEffect::Create(context, sigma, rrect);
955 }
956
957 //////////////////////////////////////////////////////////////////////////////
958
959 class GrGLRRectBlurEffect : public GrGLEffect {
960 public:
961 GrGLRRectBlurEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
962
963 virtual void emitCode(GrGLShaderBuilder* builder,
964 const GrDrawEffect& drawEffect,
965 EffectKey key,
966 const char* outputColor,
967 const char* inputColor,
968 const TransformedCoordsArray&,
969 const TextureSamplerArray&) SK_OVERRIDE;
970
971 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER RIDE;
972
973 private:
974 GrGLUniformManager::UniformHandle fProxyRectUniform;
975 GrGLUniformManager::UniformHandle fCornerRadiusUniform;
976 GrGLUniformManager::UniformHandle fBlurRadiusUniform;
977 typedef GrGLEffect INHERITED;
978 };
979
980 GrGLRRectBlurEffect::GrGLRRectBlurEffect(const GrBackendEffectFactory& factory,
981 const GrDrawEffect& drawEffect)
982 : INHERITED (factory) {
983 }
984
985 void GrGLRRectBlurEffect::emitCode(GrGLShaderBuilder* builder,
986 const GrDrawEffect& drawEffect,
987 EffectKey key,
988 const char* outputColor,
989 const char* inputColor,
990 const TransformedCoordsArray&,
991 const TextureSamplerArray& samplers) {
992 const char *rectName;
993 const char *cornerRadiusName;
994 const char *blurRadiusName;
995
996 // The proxy rect has left, top, right, and bottom edges correspond to
997 // components x, y, z, and w, respectively.
998
999 fProxyRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibil ity,
1000 kVec4f_GrSLType,
1001 "proxyRect",
1002 &rectName);
1003 fCornerRadiusUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visi bility,
1004 kFloat_GrSLType,
1005 "cornerRadius",
1006 &cornerRadiusName);
1007 fBlurRadiusUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibi lity,
1008 kFloat_GrSLType,
1009 "blurRadius",
1010 &blurRadiusName);
1011 const char* fragmentPos = builder->fragmentPosition();
1012
1013 // warp the fragment position to the appropriate part of the 9patch blur tex ture
1014
1015 builder->fsCodeAppendf("\t\tvec2 rectCenter = (%s.xy + %s.zw)/2.0;\n", rectN ame, rectName);
1016 builder->fsCodeAppendf("\t\tvec2 translatedFragPos = %s.xy - %s.xy;\n", frag mentPos, rectName);
1017 builder->fsCodeAppendf("\t\tfloat threshold = %s + 2.0*%s;\n", cornerRadiusN ame, blurRadiusName );
1018 builder->fsCodeAppendf("\t\tvec2 middle = %s.zw - %s.xy - 2.0*threshold;\n", rectName, rectName );
1019
1020 builder->fsCodeAppendf("\t\tif (translatedFragPos.x >= threshold && translat edFragPos.x < (middle.x+threshold)) {\n" );
1021 builder->fsCodeAppendf("\t\t\ttranslatedFragPos.x = threshold;\n");
1022 builder->fsCodeAppendf("\t\t} else if (translatedFragPos.x >= (middle.x + th reshold)) {\n");
1023 builder->fsCodeAppendf("\t\t\ttranslatedFragPos.x -= middle.x;\n");
1024 builder->fsCodeAppendf("\t\t}\n");
1025
1026 builder->fsCodeAppendf("\t\tif (translatedFragPos.y > threshold && translate dFragPos.y < (middle.y+threshold)) {\n" );
1027 builder->fsCodeAppendf("\t\t\ttranslatedFragPos.y = threshold;\n");
1028 builder->fsCodeAppendf("\t\t} else if (translatedFragPos.y >= (middle.y + th reshold)) {\n");
1029 builder->fsCodeAppendf("\t\t\ttranslatedFragPos.y -= middle.y;\n");
1030 builder->fsCodeAppendf("\t\t}\n");
1031
1032 builder->fsCodeAppendf("\t\tvec2 proxyDims = vec2(2.0*threshold+1.0);\n");
1033 builder->fsCodeAppendf("\t\tvec2 texCoord = translatedFragPos / proxyDims;\n ");
1034
1035 builder->fsCodeAppendf("\t%s = ", outputColor);
1036 builder->fsAppendTextureLookupAndModulate(inputColor, samplers[0], "texCoord ");
1037 builder->fsCodeAppend(";\n");
1038 }
1039
1040 void GrGLRRectBlurEffect::setData(const GrGLUniformManager& uman,
1041 const GrDrawEffect& drawEffect) {
1042 const GrRRectBlurEffect& brre = drawEffect.castEffect<GrRRectBlurEffect>();
1043 SkRRect rrect = brre.getRRect();
1044
1045 float blurRadius = 3.f*SkScalarCeilToScalar(brre.getSigma()-1/6.0f);
1046 uman.set1f(fBlurRadiusUniform, blurRadius);
1047
1048 SkRect rect = rrect.getBounds();
1049 rect.outset(blurRadius, blurRadius);
1050 uman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBott om);
1051
1052 SkScalar radius = 0;
1053 SkASSERT(rrect.isSimpleCircular() || rrect.isRect());
1054 radius = rrect.getSimpleRadii().fX;
1055 uman.set1f(fCornerRadiusUniform, radius);
1056 }
1057
1058
812 bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context, 1059 bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context,
813 GrPaint* grp, 1060 GrPaint* grp,
814 const SkStrokeRec& strokeRec , 1061 const SkStrokeRec& strokeRec ,
815 const SkRRect& rrect) const { 1062 const SkRRect& rrect) const {
816 return false; 1063 if (fBlurStyle != kNormal_SkBlurStyle) {
1064 return false;
1065 }
1066
1067 if (!strokeRec.isFillStyle()) {
1068 return false;
1069 }
1070
1071 SkRect proxy_rect = rrect.rect();
1072 SkMatrix ctm = context->getMatrix();
1073 SkScalar xformedSigma = this->computeXformedSigma(ctm);
1074 float extra=3.f*SkScalarCeilToScalar(xformedSigma-1/6.0f);
1075 proxy_rect.outset(extra, extra);
1076
1077 SkAutoTUnref<GrEffectRef> effect(GrRRectBlurEffect::Create(
1078 context, xformedSigma, rrect));
1079 if (!effect) {
1080 return false;
1081 }
1082
1083 GrContext::AutoMatrix am;
1084 if (!am.setIdentity(context, grp)) {
1085 return false;
1086 }
1087
1088 grp->addCoverageEffect(effect);
1089
1090 context->drawRect(*grp, proxy_rect);
1091 return true;
817 } 1092 }
818 1093
819 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds, 1094 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
820 const SkIRect& clipBounds, 1095 const SkIRect& clipBounds,
821 const SkMatrix& ctm, 1096 const SkMatrix& ctm,
822 SkRect* maskRect) const { 1097 SkRect* maskRect) const {
823 SkScalar xformedSigma = this->computeXformedSigma(ctm); 1098 SkScalar xformedSigma = this->computeXformedSigma(ctm);
824 if (xformedSigma <= 0) { 1099 if (xformedSigma <= 0) {
825 return false; 1100 return false;
826 } 1101 }
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
930 } else { 1205 } else {
931 str->append("None"); 1206 str->append("None");
932 } 1207 }
933 str->append("))"); 1208 str->append("))");
934 } 1209 }
935 #endif 1210 #endif
936 1211
937 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) 1212 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
938 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) 1213 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
939 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 1214 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
OLDNEW
« no previous file with comments | « src/effects/SkBlurMask.cpp ('k') | src/images/SkImageDecoder_libwebp.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698