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