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