1 /* 2 * Copyright 2011 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/SkCanvas.h" 10 #include "include/core/SkPath.h" 11 #include "include/core/SkRegion.h" 12 #include "include/core/SkString.h" 13 #include "include/utils/SkRandom.h" 14 #include "src/core/SkAAClip.h" 15 16 //////////////////////////////////////////////////////////////////////////////// 17 // This bench tests out AA/BW clipping via canvas' clipPath and clipRect calls 18 class AAClipBench : public Benchmark { 19 SkString fName; 20 SkPath fClipPath; 21 SkRect fClipRect; 22 SkRect fDrawRect; 23 bool fDoPath; 24 bool fDoAA; 25 26 public: AAClipBench(bool doPath,bool doAA)27 AAClipBench(bool doPath, bool doAA) 28 : fDoPath(doPath) 29 , fDoAA(doAA) { 30 31 fName.printf("aaclip_%s_%s", 32 doPath ? "path" : "rect", 33 doAA ? "AA" : "BW"); 34 35 fClipRect.setLTRB(10.5f, 10.5f, 50.5f, 50.5f); 36 fClipPath.addRoundRect(fClipRect, SkIntToScalar(10), SkIntToScalar(10)); 37 fDrawRect.setWH(100, 100); 38 39 SkASSERT(fClipPath.isConvex()); 40 } 41 42 protected: onGetName()43 const char* onGetName() override { return fName.c_str(); } onDraw(int loops,SkCanvas * canvas)44 void onDraw(int loops, SkCanvas* canvas) override { 45 46 SkPaint paint; 47 this->setupPaint(&paint); 48 49 for (int i = 0; i < loops; ++i) { 50 // jostle the clip regions each time to prevent caching 51 fClipRect.offset((i % 2) == 0 ? SkIntToScalar(10) : SkIntToScalar(-10), 0); 52 fClipPath.reset(); 53 fClipPath.addRoundRect(fClipRect, 54 SkIntToScalar(5), SkIntToScalar(5)); 55 SkASSERT(fClipPath.isConvex()); 56 57 canvas->save(); 58 #if 1 59 if (fDoPath) { 60 canvas->clipPath(fClipPath, SkClipOp::kIntersect, fDoAA); 61 } else { 62 canvas->clipRect(fClipRect, SkClipOp::kIntersect, fDoAA); 63 } 64 65 canvas->drawRect(fDrawRect, paint); 66 #else 67 // this path tests out directly draw the clip primitive 68 // use it to comparing just drawing the clip vs. drawing using 69 // the clip 70 if (fDoPath) { 71 canvas->drawPath(fClipPath, paint); 72 } else { 73 canvas->drawRect(fClipRect, paint); 74 } 75 #endif 76 canvas->restore(); 77 } 78 } 79 private: 80 using INHERITED = Benchmark; 81 }; 82 83 //////////////////////////////////////////////////////////////////////////////// 84 // This bench tests out nested clip stacks. It is intended to simulate 85 // how WebKit nests clips. 86 class NestedAAClipBench : public Benchmark { 87 SkString fName; 88 bool fDoAA; 89 SkRect fDrawRect; 90 SkRandom fRandom; 91 92 static const int kNestingDepth = 3; 93 static const int kImageSize = 400; 94 95 SkPoint fSizes[kNestingDepth+1]; 96 97 public: NestedAAClipBench(bool doAA)98 NestedAAClipBench(bool doAA) : fDoAA(doAA) { 99 fName.printf("nested_aaclip_%s", doAA ? "AA" : "BW"); 100 101 fDrawRect = SkRect::MakeLTRB(0, 0, 102 SkIntToScalar(kImageSize), 103 SkIntToScalar(kImageSize)); 104 105 fSizes[0].set(SkIntToScalar(kImageSize), SkIntToScalar(kImageSize)); 106 107 for (int i = 1; i < kNestingDepth+1; ++i) { 108 fSizes[i].set(fSizes[i-1].fX/2, fSizes[i-1].fY/2); 109 } 110 } 111 112 protected: onGetName()113 const char* onGetName() override { return fName.c_str(); } 114 115 recurse(SkCanvas * canvas,int depth,const SkPoint & offset)116 void recurse(SkCanvas* canvas, 117 int depth, 118 const SkPoint& offset) { 119 120 canvas->save(); 121 122 SkRect temp = SkRect::MakeLTRB(0, 0, 123 fSizes[depth].fX, fSizes[depth].fY); 124 temp.offset(offset); 125 126 SkPath path; 127 path.addRoundRect(temp, SkIntToScalar(3), SkIntToScalar(3)); 128 SkASSERT(path.isConvex()); 129 130 canvas->clipPath(path, SkClipOp::kIntersect, fDoAA); 131 132 if (kNestingDepth == depth) { 133 // we only draw the draw rect at the lowest nesting level 134 SkPaint paint; 135 paint.setColor(0xff000000 | fRandom.nextU()); 136 canvas->drawRect(fDrawRect, paint); 137 } else { 138 SkPoint childOffset = offset; 139 this->recurse(canvas, depth+1, childOffset); 140 141 childOffset += fSizes[depth+1]; 142 this->recurse(canvas, depth+1, childOffset); 143 144 childOffset.fX = offset.fX + fSizes[depth+1].fX; 145 childOffset.fY = offset.fY; 146 this->recurse(canvas, depth+1, childOffset); 147 148 childOffset.fX = offset.fX; 149 childOffset.fY = offset.fY + fSizes[depth+1].fY; 150 this->recurse(canvas, depth+1, childOffset); 151 } 152 153 canvas->restore(); 154 } 155 onDraw(int loops,SkCanvas * canvas)156 void onDraw(int loops, SkCanvas* canvas) override { 157 158 for (int i = 0; i < loops; ++i) { 159 SkPoint offset = SkPoint::Make(0, 0); 160 this->recurse(canvas, 0, offset); 161 } 162 } 163 164 private: 165 using INHERITED = Benchmark; 166 }; 167 168 //////////////////////////////////////////////////////////////////////////////// 169 class AAClipBuilderBench : public Benchmark { 170 SkString fName; 171 SkPath fPath; 172 SkRect fRect; 173 SkIRect fBounds; 174 bool fDoPath; 175 bool fDoAA; 176 177 public: AAClipBuilderBench(bool doPath,bool doAA)178 AAClipBuilderBench(bool doPath, bool doAA) { 179 fDoPath = doPath; 180 fDoAA = doAA; 181 182 fName.printf("aaclip_build_%s_%s", doPath ? "path" : "rect", 183 doAA ? "AA" : "BW"); 184 fBounds = {0, 0, 640, 480}; 185 fRect.set(fBounds); 186 fRect.inset(SK_Scalar1/4, SK_Scalar1/4); 187 fPath.addRoundRect(fRect, SkIntToScalar(20), SkIntToScalar(20)); 188 } 189 190 protected: onGetName()191 const char* onGetName() override { return fName.c_str(); } onDraw(int loops,SkCanvas *)192 void onDraw(int loops, SkCanvas*) override { 193 SkPaint paint; 194 this->setupPaint(&paint); 195 196 for (int i = 0; i < loops; ++i) { 197 SkAAClip clip; 198 if (fDoPath) { 199 clip.setPath(fPath, fBounds, fDoAA); 200 } else { 201 if (fDoAA) { 202 clip.setPath(SkPath::Rect(fRect), fBounds, fDoAA); 203 } else { 204 clip.setRect(fBounds); 205 } 206 } 207 } 208 } 209 private: 210 using INHERITED = Benchmark; 211 }; 212 213 //////////////////////////////////////////////////////////////////////////////// 214 class AAClipRegionBench : public Benchmark { 215 public: AAClipRegionBench()216 AAClipRegionBench() { 217 SkPath path; 218 // test conversion of a complex clip to a aaclip 219 path.addCircle(0, 0, SkIntToScalar(200)); 220 path.addCircle(0, 0, SkIntToScalar(180)); 221 // evenodd means we've constructed basically a stroked circle 222 path.setFillType(SkPathFillType::kEvenOdd); 223 224 SkIRect bounds; 225 path.getBounds().roundOut(&bounds); 226 fRegion.setPath(path, SkRegion(bounds)); 227 } 228 229 protected: onGetName()230 const char* onGetName() override { return "aaclip_setregion"; } onDraw(int loops,SkCanvas *)231 void onDraw(int loops, SkCanvas*) override { 232 for (int i = 0; i < loops; ++i) { 233 SkAAClip clip; 234 clip.setRegion(fRegion); 235 } 236 } 237 238 private: 239 SkRegion fRegion; 240 using INHERITED = Benchmark; 241 }; 242 243 //////////////////////////////////////////////////////////////////////////////// 244 245 DEF_BENCH(return new AAClipBuilderBench(false, false);) 246 DEF_BENCH(return new AAClipBuilderBench(false, true);) 247 DEF_BENCH(return new AAClipBuilderBench(true, false);) 248 DEF_BENCH(return new AAClipBuilderBench(true, true);) 249 DEF_BENCH(return new AAClipRegionBench();) 250 DEF_BENCH(return new AAClipBench(false, false);) 251 DEF_BENCH(return new AAClipBench(false, true);) 252 DEF_BENCH(return new AAClipBench(true, false);) 253 DEF_BENCH(return new AAClipBench(true, true);) 254 DEF_BENCH(return new NestedAAClipBench(false);) 255 DEF_BENCH(return new NestedAAClipBench(true);) 256