OLD | NEW |
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 Loading... |
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 Loading... |
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, ¶ms); |
| 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(¶ms, 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 Loading... |
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 |
OLD | NEW |