1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "bench/Benchmark.h" 9 #include "include/core/SkBlurTypes.h" 10 #include "include/core/SkCanvas.h" 11 #include "include/core/SkPaint.h" 12 #include "include/core/SkShader.h" 13 #include "include/core/SkString.h" 14 #include "src/base/SkRandom.h" 15 #include "src/core/SkBlurMask.h" 16 17 #define SMALL SkIntToScalar(2) 18 #define REAL 1.5f 19 static const SkScalar kMedium = SkIntToScalar(5); 20 #define BIG SkIntToScalar(10) 21 static const SkScalar kMedBig = SkIntToScalar(20); 22 #define REALBIG 30.5f 23 24 class BlurRectBench: public Benchmark { 25 int fLoopCount; 26 SkScalar fRadius; 27 SkString fName; 28 29 public: BlurRectBench(SkScalar rad)30 BlurRectBench(SkScalar rad) { 31 fRadius = rad; 32 33 if (fRadius > SkIntToScalar(25)) { 34 fLoopCount = 100; 35 } else if (fRadius > SkIntToScalar(5)) { 36 fLoopCount = 1000; 37 } else { 38 fLoopCount = 10000; 39 } 40 } 41 42 protected: onGetName()43 const char* onGetName() override { 44 return fName.c_str(); 45 } 46 radius() const47 SkScalar radius() const { 48 return fRadius; 49 } 50 setName(const SkString & name)51 void setName(const SkString& name) { 52 fName = name; 53 } 54 onDraw(int loops,SkCanvas *)55 void onDraw(int loops, SkCanvas*) override { 56 SkPaint paint; 57 this->setupPaint(&paint); 58 59 paint.setAntiAlias(true); 60 61 SkScalar pad = fRadius*3/2 + SK_Scalar1; 62 SkRect r = SkRect::MakeWH(2 * pad + SK_Scalar1, 2 * pad + SK_Scalar1); 63 64 preBenchSetup(r); 65 66 for (int i = 0; i < loops; i++) { 67 this->makeBlurryRect(r); 68 } 69 } 70 71 virtual void makeBlurryRect(const SkRect&) = 0; preBenchSetup(const SkRect &)72 virtual void preBenchSetup(const SkRect&) {} 73 private: 74 using INHERITED = Benchmark; 75 }; 76 77 78 class BlurRectDirectBench: public BlurRectBench { 79 public: BlurRectDirectBench(SkScalar rad)80 BlurRectDirectBench(SkScalar rad) : INHERITED(rad) { 81 SkString name; 82 83 if (SkScalarFraction(rad) != 0) { 84 name.printf("blurrect_direct_%.2f", rad); 85 } else { 86 name.printf("blurrect_direct_%d", SkScalarRoundToInt(rad)); 87 } 88 89 this->setName(name); 90 } 91 protected: makeBlurryRect(const SkRect & r)92 void makeBlurryRect(const SkRect& r) override { 93 SkMaskBuilder mask; 94 if (!SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(this->radius()), 95 &mask, r, kNormal_SkBlurStyle)) { 96 return; 97 } 98 SkMaskBuilder::FreeImage(mask.image()); 99 } 100 private: 101 using INHERITED = BlurRectBench; 102 }; 103 104 class BlurRectSeparableBench: public BlurRectBench { 105 106 public: BlurRectSeparableBench(SkScalar rad)107 BlurRectSeparableBench(SkScalar rad) : INHERITED(rad) { } 108 ~BlurRectSeparableBench()109 ~BlurRectSeparableBench() override { 110 SkMaskBuilder::FreeImage(fSrcMask.image()); 111 } 112 113 protected: preBenchSetup(const SkRect & r)114 void preBenchSetup(const SkRect& r) override { 115 SkMaskBuilder::FreeImage(fSrcMask.image()); 116 117 r.roundOut(&fSrcMask.bounds()); 118 fSrcMask.format() = SkMask::kA8_Format; 119 fSrcMask.rowBytes() = fSrcMask.fBounds.width(); 120 fSrcMask.image() = SkMaskBuilder::AllocImage(fSrcMask.computeTotalImageSize()); 121 122 memset(fSrcMask.image(), 0xff, fSrcMask.computeTotalImageSize()); 123 } 124 125 SkMaskBuilder fSrcMask; 126 private: 127 using INHERITED = BlurRectBench; 128 }; 129 130 class BlurRectBoxFilterBench: public BlurRectSeparableBench { 131 public: BlurRectBoxFilterBench(SkScalar rad)132 BlurRectBoxFilterBench(SkScalar rad) : INHERITED(rad) { 133 SkString name; 134 135 if (SkScalarFraction(rad) != 0) { 136 name.printf("blurrect_boxfilter_%.2f", rad); 137 } else { 138 name.printf("blurrect_boxfilter_%d", SkScalarRoundToInt(rad)); 139 } 140 141 this->setName(name); 142 } 143 144 protected: 145 makeBlurryRect(const SkRect &)146 void makeBlurryRect(const SkRect&) override { 147 SkMaskBuilder mask; 148 if (!SkBlurMask::BoxBlur(&mask, fSrcMask, SkBlurMask::ConvertRadiusToSigma(this->radius()), 149 kNormal_SkBlurStyle)) { 150 return; 151 } 152 SkMaskBuilder::FreeImage(mask.image()); 153 } 154 private: 155 using INHERITED = BlurRectSeparableBench; 156 }; 157 158 class BlurRectGaussianBench: public BlurRectSeparableBench { 159 public: BlurRectGaussianBench(SkScalar rad)160 BlurRectGaussianBench(SkScalar rad) : INHERITED(rad) { 161 SkString name; 162 163 if (SkScalarFraction(rad) != 0) { 164 name.printf("blurrect_gaussian_%.2f", rad); 165 } else { 166 name.printf("blurrect_gaussian_%d", SkScalarRoundToInt(rad)); 167 } 168 169 this->setName(name); 170 } 171 172 protected: 173 makeBlurryRect(const SkRect &)174 void makeBlurryRect(const SkRect&) override { 175 SkMaskBuilder mask; 176 if (!SkBlurMask::BlurGroundTruth(SkBlurMask::ConvertRadiusToSigma(this->radius()), 177 &mask, fSrcMask, kNormal_SkBlurStyle)) { 178 return; 179 } 180 SkMaskBuilder::FreeImage(mask.image()); 181 } 182 private: 183 using INHERITED = BlurRectSeparableBench; 184 }; 185 186 DEF_BENCH(return new BlurRectBoxFilterBench(SMALL);) 187 DEF_BENCH(return new BlurRectBoxFilterBench(BIG);) 188 DEF_BENCH(return new BlurRectBoxFilterBench(REALBIG);) 189 DEF_BENCH(return new BlurRectBoxFilterBench(REAL);) 190 DEF_BENCH(return new BlurRectGaussianBench(SMALL);) 191 DEF_BENCH(return new BlurRectGaussianBench(BIG);) 192 DEF_BENCH(return new BlurRectGaussianBench(REALBIG);) 193 DEF_BENCH(return new BlurRectGaussianBench(REAL);) 194 DEF_BENCH(return new BlurRectDirectBench(SMALL);) 195 DEF_BENCH(return new BlurRectDirectBench(BIG);) 196 DEF_BENCH(return new BlurRectDirectBench(REALBIG);) 197 DEF_BENCH(return new BlurRectDirectBench(REAL);) 198 199 DEF_BENCH(return new BlurRectDirectBench(kMedium);) 200 DEF_BENCH(return new BlurRectDirectBench(kMedBig);) 201 202 DEF_BENCH(return new BlurRectBoxFilterBench(kMedium);) 203 DEF_BENCH(return new BlurRectBoxFilterBench(kMedBig);) 204 205 #if 0 206 // disable Gaussian benchmarks; the algorithm works well enough 207 // and serves as a baseline for ground truth, but it's too slow 208 // to use in production for non-trivial radii, so no real point 209 // in having the bots benchmark it all the time. 210 211 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(1));) 212 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(2));) 213 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(3));) 214 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(4));) 215 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(5));) 216 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(6));) 217 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(7));) 218 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(8));) 219 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(9));) 220 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(10));) 221 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(11));) 222 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(12));) 223 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(13));) 224 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(14));) 225 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(15));) 226 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(16));) 227 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(17));) 228 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(18));) 229 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(19));) 230 DEF_BENCH(return new BlurRectGaussianBench(SkIntToScalar(20));) 231 #endif 232