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

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