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 #include "SkClipOpPriv.h" 16 17 //////////////////////////////////////////////////////////////////////////////// 18 // This bench tests out AA/BW clipping via canvas' clipPath and clipRect calls 19 class AAClipBench : public Benchmark { 20 SkString fName; 21 SkPath fClipPath; 22 SkRect fClipRect; 23 SkRect fDrawRect; 24 bool fDoPath; 25 bool fDoAA; 26 27 public: AAClipBench(bool doPath,bool doAA)28 AAClipBench(bool doPath, bool doAA) 29 : fDoPath(doPath) 30 , fDoAA(doAA) { 31 32 fName.printf("aaclip_%s_%s", 33 doPath ? "path" : "rect", 34 doAA ? "AA" : "BW"); 35 36 fClipRect.set(10.5f, 10.5f, 37 50.5f, 50.5f); 38 fClipPath.addRoundRect(fClipRect, SkIntToScalar(10), SkIntToScalar(10)); 39 fDrawRect.set(SkIntToScalar(0), SkIntToScalar(0), 40 SkIntToScalar(100), SkIntToScalar(100)); 41 42 SkASSERT(fClipPath.isConvex()); 43 } 44 45 protected: onGetName()46 virtual const char* onGetName() { return fName.c_str(); } onDraw(int loops,SkCanvas * canvas)47 virtual void onDraw(int loops, SkCanvas* canvas) { 48 49 SkPaint paint; 50 this->setupPaint(&paint); 51 52 for (int i = 0; i < loops; ++i) { 53 // jostle the clip regions each time to prevent caching 54 fClipRect.offset((i % 2) == 0 ? SkIntToScalar(10) : SkIntToScalar(-10), 0); 55 fClipPath.reset(); 56 fClipPath.addRoundRect(fClipRect, 57 SkIntToScalar(5), SkIntToScalar(5)); 58 SkASSERT(fClipPath.isConvex()); 59 60 canvas->save(); 61 #if 1 62 if (fDoPath) { 63 canvas->clipPath(fClipPath, kReplace_SkClipOp, fDoAA); 64 } else { 65 canvas->clipRect(fClipRect, kReplace_SkClipOp, fDoAA); 66 } 67 68 canvas->drawRect(fDrawRect, paint); 69 #else 70 // this path tests out directly draw the clip primitive 71 // use it to comparing just drawing the clip vs. drawing using 72 // the clip 73 if (fDoPath) { 74 canvas->drawPath(fClipPath, paint); 75 } else { 76 canvas->drawRect(fClipRect, paint); 77 } 78 #endif 79 canvas->restore(); 80 } 81 } 82 private: 83 typedef Benchmark INHERITED; 84 }; 85 86 //////////////////////////////////////////////////////////////////////////////// 87 // This bench tests out nested clip stacks. It is intended to simulate 88 // how WebKit nests clips. 89 class NestedAAClipBench : public Benchmark { 90 SkString fName; 91 bool fDoAA; 92 SkRect fDrawRect; 93 SkRandom fRandom; 94 95 static const int kNestingDepth = 3; 96 static const int kImageSize = 400; 97 98 SkPoint fSizes[kNestingDepth+1]; 99 100 public: NestedAAClipBench(bool doAA)101 NestedAAClipBench(bool doAA) : fDoAA(doAA) { 102 fName.printf("nested_aaclip_%s", doAA ? "AA" : "BW"); 103 104 fDrawRect = SkRect::MakeLTRB(0, 0, 105 SkIntToScalar(kImageSize), 106 SkIntToScalar(kImageSize)); 107 108 fSizes[0].set(SkIntToScalar(kImageSize), SkIntToScalar(kImageSize)); 109 110 for (int i = 1; i < kNestingDepth+1; ++i) { 111 fSizes[i].set(fSizes[i-1].fX/2, fSizes[i-1].fY/2); 112 } 113 } 114 115 protected: onGetName()116 virtual const char* onGetName() { return fName.c_str(); } 117 118 recurse(SkCanvas * canvas,int depth,const SkPoint & offset)119 void recurse(SkCanvas* canvas, 120 int depth, 121 const SkPoint& offset) { 122 123 canvas->save(); 124 125 SkRect temp = SkRect::MakeLTRB(0, 0, 126 fSizes[depth].fX, fSizes[depth].fY); 127 temp.offset(offset); 128 129 SkPath path; 130 path.addRoundRect(temp, SkIntToScalar(3), SkIntToScalar(3)); 131 SkASSERT(path.isConvex()); 132 133 canvas->clipPath(path, 134 0 == depth ? kReplace_SkClipOp : kIntersect_SkClipOp, 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 onDraw(int loops,SkCanvas * canvas)161 virtual void onDraw(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: AAClipBuilderBench(bool doPath,bool doAA)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: onGetName()197 virtual const char* onGetName() { return fName.c_str(); } onDraw(int loops,SkCanvas *)198 virtual void onDraw(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: AAClipRegionBench()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: onGetName()232 virtual const char* onGetName() { return "aaclip_setregion"; } onDraw(int loops,SkCanvas *)233 virtual void onDraw(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 new AAClipBuilderBench(false, false);) 248 DEF_BENCH(return new AAClipBuilderBench(false, true);) 249 DEF_BENCH(return new AAClipBuilderBench(true, false);) 250 DEF_BENCH(return new AAClipBuilderBench(true, true);) 251 DEF_BENCH(return new AAClipRegionBench();) 252 DEF_BENCH(return new AAClipBench(false, false);) 253 DEF_BENCH(return new AAClipBench(false, true);) 254 DEF_BENCH(return new AAClipBench(true, false);) 255 DEF_BENCH(return new AAClipBench(true, true);) 256 DEF_BENCH(return new NestedAAClipBench(false);) 257 DEF_BENCH(return new NestedAAClipBench(true);) 258