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

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: Created 6 years, 8 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
« src/effects/SkBlurMask.h ('K') | « src/effects/SkBlurMask.cpp ('k') | no next file » | 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, SkBlurMaskFilter::BlurStyle, uint32_t f lags); 33 SkBlurMaskFilterImpl(SkScalar sigma, SkBlurMaskFilter::BlurStyle, uint32_t f lags);
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 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 } 254 }
254 return true; 255 return true;
255 } 256 }
256 257
257 static bool rect_exceeds(const SkRect& r, SkScalar v) { 258 static bool rect_exceeds(const SkRect& r, SkScalar v) {
258 return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v || 259 return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
259 r.width() > v || r.height() > v; 260 r.width() > v || r.height() > v;
260 } 261 }
261 262
262 #ifdef SK_IGNORE_FAST_RRECT_BLUR 263 #ifdef SK_IGNORE_FAST_RRECT_BLUR
263 SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticRRect", fa lse, "Use the faster analytic blur approach for ninepatch rects" ); 264 SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analytibrrect", fa lse, "Use the faster analytic blur approach for ninepatch rects" );
bsalomon 2014/04/23 19:50:30 analytibrrect?
264 #else 265 #else
265 SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticRRect", tr ue, "Use the faster analytic blur approach for ninepatch round rects" ); 266 SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analytibrrect", tr ue, "Use the faster analytic blur approach for ninepatch round rects" );
266 #endif 267 #endif
267 268
268 SkMaskFilter::FilterReturn 269 SkMaskFilter::FilterReturn
269 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma trix, 270 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma trix,
270 const SkIRect& clipBounds, 271 const SkIRect& clipBounds,
271 NinePatch* patch) const { 272 NinePatch* patch) const {
272 SkASSERT(patch != NULL); 273 SkASSERT(patch != NULL);
273 switch (rrect.getType()) { 274 switch (rrect.getType()) {
274 case SkRRect::kUnknown_Type: 275 case SkRRect::kUnknown_Type:
275 // Unknown should never be returned. 276 // Unknown should never be returned.
(...skipping 536 matching lines...) Expand 10 before | Expand all | Expand 10 after
812 return false; 813 return false;
813 } 814 }
814 815
815 816
816 grp->addCoverageEffect(effect); 817 grp->addCoverageEffect(effect);
817 818
818 context->drawRect(*grp, rect); 819 context->drawRect(*grp, rect);
819 return true; 820 return true;
820 } 821 }
821 822
823 class GrGLRRectBlurEffect;
824
825 class GrRRectBlurEffect : public GrEffect {
826 public:
827
828 // The flags are used to indicate which corners are circluar (unflagged corn ers are assumed to
bsalomon 2014/04/23 19:50:30 Delete comment?
humper 2014/04/23 20:11:49 Done.
829 // be square).
830 static GrEffectRef* Create(GrContext* context, float sigma, const SkRRect&);
831
832 virtual ~GrRRectBlurEffect() {};
833 static const char* Name() { return "GrRRectBlur"; }
834
835 const SkRRect& getRRect() const { return fRRect; }
836 float getSigma() const { return fSigma; }
837
838 typedef GrGLRRectBlurEffect GLEffect;
839
840 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags ) const SK_OVERRIDE;
841
842 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
843
844 private:
845 GrRRectBlurEffect(float sigma, const SkRRect&, GrTexture* profileTexture);
846
847 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
848
849 SkRRect fRRect;
850 float fSigma;
851 GrTextureAccess fNinePatchAccess;
852
853 GR_DECLARE_EFFECT_TEST;
854
855 typedef GrEffect INHERITED;
856 };
857
858
859 GrEffectRef* GrRRectBlurEffect::Create(GrContext* context, float sigma, const Sk RRect& rrect) {
860 if (!rrect.isSimpleCircular()) {
861 SkDebugf( "not simple circular\n" );
862 return NULL;
863 }
864
865 // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
866 // sufficiently small relative to both the size of the corner radius and the
867 // width (and height) of the rrect.
868
869 unsigned int blurRadius = 3*SkScalarCeilToInt(sigma-1/6.0f);
870 unsigned int cornerRadius = SkScalarCeilToInt(rrect.getSimpleRadii().x());
871 if (cornerRadius + blurRadius > rrect.width()/2 ||
872 cornerRadius + blurRadius > rrect.height()/2) {
873 return NULL;
874 }
875
876 static const GrCacheID::Domain gRRectBlurDomain = GrCacheID::GenerateDomain( );
877 GrCacheID::Key key;
878 memset(&key, 0, sizeof(key));
879 key.fData32[0] = blurRadius;
880 key.fData32[1] = cornerRadius;
881 GrCacheID blurRRectNinePatchID(gRRectBlurDomain, key);
882
883 GrTextureParams params;
884 params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
885
886 unsigned int smallRectSide = 2*(blurRadius + cornerRadius) + 1;
887 unsigned int texSide = smallRectSide + 2*blurRadius;
888 GrTextureDesc texDesc;
889 texDesc.fWidth = texSide;
890 texDesc.fHeight = texSide;
891 texDesc.fConfig = kAlpha_8_GrPixelConfig;
892
893 GrTexture *blurNinePatchTexture = context->findAndRefTexture(texDesc, blurRR ectNinePatchID, &params);
894
895 if (NULL == blurNinePatchTexture) {
896 SkMask mask;
897
898 mask.fBounds = SkIRect::MakeWH(smallRectSide, smallRectSide);
899 mask.fFormat = SkMask::kA8_Format;
900 mask.fRowBytes = mask.fBounds.width();
901 mask.fImage = SkMask::AllocImage(mask.computeTotalImageSize());
902 SkAutoMaskFreeImage amfi(mask.fImage);
903
904 memset(mask.fImage, 0, mask.computeTotalImageSize());
905
906 SkRect smallRect;
907 smallRect.setWH( smallRectSide,smallRectSide );
bsalomon 2014/04/23 19:50:30 smallRect.setWH(smallRectSide, smallRectSide); //
humper 2014/04/23 20:11:49 Done.
908
909 SkRRect smallRRect;
910 smallRRect.setRectXY(smallRect, cornerRadius, cornerRadius);
911
912 SkPath path;
913 path.addRRect( smallRRect );
914
915 SkDraw::DrawToMask(path, &mask.fBounds, NULL, NULL, &mask, SkMask::kJust RenderImage_CreateMode, SkPaint::kFill_Style);
916
917 SkMask blurred_mask;
918 SkBlurMask::BoxBlur(&blurred_mask, mask, sigma, SkBlurMask::kNormal_Styl e, SkBlurMask::kHigh_Quality, NULL, true );
919
920 blurNinePatchTexture = context->createTexture(&params, texDesc, blurRRec tNinePatchID, blurred_mask.fImage, 0);
921 }
922
923 if (NULL == blurNinePatchTexture) {
924 return NULL;
925 }
926
927 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrRRectBlurEffect,
928 (sigma, rrect, blurNinePat chTexture))));
929 }
930
931 void GrRRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* val idFlags) const {
932 *validFlags = 0;
933 }
934
935 const GrBackendEffectFactory& GrRRectBlurEffect::getFactory() const {
936 return GrTBackendEffectFactory<GrRRectBlurEffect>::getInstance();
937 }
938
939 GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTextur e *ninePatchTexture)
940 : fRRect(rrect),
941 fSigma(sigma),
942 fNinePatchAccess(ninePatchTexture) {
943 this->addTextureAccess(&fNinePatchAccess);
944 this->setWillReadFragmentPosition();
945 }
946
947 bool GrRRectBlurEffect::onIsEqual(const GrEffect& other) const {
948 const GrRRectBlurEffect& rrbe = CastEffect<GrRRectBlurEffect>(other);
949 return fRRect == rrbe.fRRect && fSigma == rrbe.fSigma;
bsalomon 2014/04/23 19:50:30 maybe it doesn't really matter much, but it seems
humper 2014/04/23 20:11:49 This was a bug -- changed to just look at the corn
950 }
951
952 //////////////////////////////////////////////////////////////////////////////
953
954 GR_DEFINE_EFFECT_TEST(GrRRectBlurEffect);
955
956 GrEffectRef* GrRRectBlurEffect::TestCreate(SkRandom* random,
957 GrContext* context,
958 const GrDrawTargetCaps& caps,
959 GrTexture*[]) {
960 SkScalar w = random->nextRangeScalar(20.f, 1000.f);
961 SkScalar h = random->nextRangeScalar(20.f, 1000.f);
962 SkScalar r = random->nextRangeF(0, 9.f);
bsalomon 2014/04/23 19:50:30 I think if r was actually 0 it would cause ::Creat
humper 2014/04/23 20:11:49 Done.
963 SkScalar sigma = random->nextRangeF(1,20);
964 SkRRect rrect;
965 rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
966 return GrRRectBlurEffect::Create(context, sigma, rrect);
967 }
968
969 //////////////////////////////////////////////////////////////////////////////
970
971 class GrGLRRectBlurEffect : public GrGLEffect {
972 public:
973 GrGLRRectBlurEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
974
975 virtual void emitCode(GrGLShaderBuilder* builder,
976 const GrDrawEffect& drawEffect,
977 EffectKey key,
978 const char* outputColor,
979 const char* inputColor,
980 const TransformedCoordsArray&,
981 const TextureSamplerArray&) SK_OVERRIDE;
982
983 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER RIDE;
984
985 private:
986 GrGLUniformManager::UniformHandle fProxyRectUniform;
987 GrGLUniformManager::UniformHandle fCornerRadiusUniform;
988 GrGLUniformManager::UniformHandle fBlurRadiusUniform;
989 typedef GrGLEffect INHERITED;
990 };
991
992 GrGLRRectBlurEffect::GrGLRRectBlurEffect(const GrBackendEffectFactory& factory,
993 const GrDrawEffect& drawEffect)
994 : INHERITED (factory) {
995 }
996
997 void GrGLRRectBlurEffect::emitCode(GrGLShaderBuilder* builder,
998 const GrDrawEffect& drawEffect,
999 EffectKey key,
1000 const char* outputColor,
1001 const char* inputColor,
1002 const TransformedCoordsArray&,
1003 const TextureSamplerArray& samplers) {
1004 const char *rectName;
1005 const char *cornerRadiusName;
1006 const char *blurRadiusName;
1007
1008 // The proxy rect has left, top, right, and bottom edges correspond to
1009 // components x, y, z, and w, respectively.
1010
1011 fProxyRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibil ity,
1012 kVec4f_GrSLType,
1013 "proxyRect",
1014 &rectName);
1015 fCornerRadiusUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visi bility,
1016 kFloat_GrSLType,
1017 "cornerRadius",
1018 &cornerRadiusName);
1019 fBlurRadiusUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibi lity,
1020 kFloat_GrSLType,
1021 "blurRadius",
1022 &blurRadiusName);
1023 const char* fragmentPos = builder->fragmentPosition();
1024
1025 // warp the fragment position to the appropriate part of the 9patch blur tex ture
1026
1027 builder->fsCodeAppendf("\t\tvec2 rectCenter = (%s.xy + %s.zw)/2.0;\n", rectN ame, rectName);
1028 builder->fsCodeAppendf("\t\tvec2 translatedFragPos = %s.xy - %s.xy;\n", frag mentPos, rectName);
1029 builder->fsCodeAppendf("\t\tfloat threshold = %s + 2.0*%s;\n", cornerRadiusN ame, blurRadiusName );
1030 builder->fsCodeAppendf("\t\tvec2 middle = %s.zw - %s.xy - 2.0*threshold;\n", rectName, rectName );
1031
1032 builder->fsCodeAppendf("\t\tif (translatedFragPos.x >= threshold && translat edFragPos.x < (middle.x+threshold)) {\n" );
1033 builder->fsCodeAppendf("\t\t\ttranslatedFragPos.x = threshold;\n");
1034 builder->fsCodeAppendf("\t\t} else if (translatedFragPos.x >= (middle.x + th reshold)) {\n");
1035 builder->fsCodeAppendf("\t\t\ttranslatedFragPos.x -= middle.x;\n");
1036 builder->fsCodeAppendf("\t\t}\n");
1037
1038 builder->fsCodeAppendf("\t\tif (translatedFragPos.y > threshold && translate dFragPos.y < (middle.y+threshold)) {\n" );
1039 builder->fsCodeAppendf("\t\t\ttranslatedFragPos.y = threshold+1;\n");
1040 builder->fsCodeAppendf("\t\t} else if (translatedFragPos.y >= (middle.y + th reshold)) {\n");
1041 builder->fsCodeAppendf("\t\t\ttranslatedFragPos.y -= middle.y;\n");
1042 builder->fsCodeAppendf("\t\t}\n");
1043
1044 builder->fsCodeAppendf("\t\tvec2 proxyDims = vec2(2.0*threshold+1.0);\n");
1045 builder->fsCodeAppendf("\t\tvec2 texCoord = translatedFragPos / proxyDims;\n ");
1046
1047 builder->fsCodeAppendf("\t%s = ", outputColor);
1048 builder->fsAppendTextureLookupAndModulate(inputColor, samplers[0], "texCoord ");
1049 builder->fsCodeAppend(";\n");
1050 }
1051
1052 void GrGLRRectBlurEffect::setData(const GrGLUniformManager& uman,
1053 const GrDrawEffect& drawEffect) {
1054 const GrRRectBlurEffect& brre = drawEffect.castEffect<GrRRectBlurEffect>();
1055 SkRRect rrect = brre.getRRect();
1056
1057 unsigned int blurRadius = 3*SkScalarCeilToInt(brre.getSigma()-1/6.0f);
1058 uman.set1f(fBlurRadiusUniform, blurRadius);
1059
1060 SkRect rect = rrect.getBounds();
1061 rect.outset(blurRadius, blurRadius);
1062 uman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBott om);
1063
1064 SkScalar radius = 0;
1065 SkASSERT(rrect.isSimpleCircular() || rrect.isRect());
1066 radius = rrect.getSimpleRadii().fX;
1067 uman.set1f(fCornerRadiusUniform, radius);
1068 }
1069
1070
822 bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context, 1071 bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context,
823 GrPaint* grp, 1072 GrPaint* grp,
824 const SkStrokeRec& strokeRec , 1073 const SkStrokeRec& strokeRec ,
825 const SkRRect& rrect) const { 1074 const SkRRect& rrect) const {
826 return false; 1075 if (fBlurStyle != SkBlurMaskFilter::kNormal_BlurStyle) {
1076 return false;
1077 }
1078
1079 if (!strokeRec.isFillStyle()) {
1080 return false;
1081 }
1082
1083 SkRect proxy_rect = rrect.rect();
1084 SkMatrix ctm = context->getMatrix();
1085 SkScalar xformedSigma = this->computeXformedSigma(ctm);
1086 unsigned int extra=3*SkScalarCeilToInt(xformedSigma-1/6.0f);
1087 proxy_rect.outset(extra,extra);
1088
1089 SkAutoTUnref<GrEffectRef> effect(GrRRectBlurEffect::Create(
1090 context, xformedSigma, rrect));
1091 if (!effect) {
1092 return false;
1093 }
1094
1095 GrContext::AutoMatrix am;
1096 if (!am.setIdentity(context, grp)) {
1097 return false;
1098 }
1099
1100 grp->addCoverageEffect(effect);
1101
1102 context->drawRect(*grp, proxy_rect);
1103 return true;
827 } 1104 }
828 1105
829 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds, 1106 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
830 const SkIRect& clipBounds, 1107 const SkIRect& clipBounds,
831 const SkMatrix& ctm, 1108 const SkMatrix& ctm,
832 SkRect* maskRect) const { 1109 SkRect* maskRect) const {
833 SkScalar xformedSigma = this->computeXformedSigma(ctm); 1110 SkScalar xformedSigma = this->computeXformedSigma(ctm);
834 if (xformedSigma <= 0) { 1111 if (xformedSigma <= 0) {
835 return false; 1112 return false;
836 } 1113 }
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
940 } else { 1217 } else {
941 str->append("None"); 1218 str->append("None");
942 } 1219 }
943 str->append("))"); 1220 str->append("))");
944 } 1221 }
945 #endif 1222 #endif
946 1223
947 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) 1224 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
948 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) 1225 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
949 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 1226 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
OLDNEW
« src/effects/SkBlurMask.h ('K') | « src/effects/SkBlurMask.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698