1 /* 2 * Copyright 2014 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/SkColor.h" 11 #include "include/core/SkPaint.h" 12 #include "include/core/SkPicture.h" 13 #include "include/core/SkPictureRecorder.h" 14 #include "include/core/SkString.h" 15 #include "include/utils/SkNullCanvas.h" 16 17 class PictureNesting : public Benchmark { 18 public: PictureNesting(const char * name,int maxLevel,int maxPictureLevel)19 PictureNesting(const char* name, int maxLevel, int maxPictureLevel) 20 : fMaxLevel(maxLevel) 21 , fMaxPictureLevel(maxPictureLevel) { 22 fName.printf("picture_nesting_%s_%d", name, this->countPics()); 23 fPaint.setColor(SK_ColorRED); 24 fPaint.setAntiAlias(true); 25 fPaint.setStyle(SkPaint::kStroke_Style); 26 } 27 28 protected: onGetName()29 const char* onGetName() override { 30 return fName.c_str(); 31 } 32 doDraw(SkCanvas * canvas)33 void doDraw(SkCanvas* canvas) { 34 SkIPoint canvasSize = onGetSize(); 35 canvas->save(); 36 canvas->scale(SkIntToScalar(canvasSize.x()), SkIntToScalar(canvasSize.y())); 37 38 SkDEBUGCODE(int pics = ) this->sierpinsky(canvas, 0, fPaint); 39 SkASSERT(pics == this->countPics()); 40 41 canvas->restore(); 42 } 43 sierpinsky(SkCanvas * canvas,int lvl,const SkPaint & paint)44 int sierpinsky(SkCanvas* canvas, int lvl, const SkPaint& paint) { 45 if (++lvl > fMaxLevel) { 46 return 0; 47 } 48 49 int pics = 0; 50 bool recordPicture = lvl <= fMaxPictureLevel; 51 SkPictureRecorder recorder; 52 SkCanvas* c = canvas; 53 54 if (recordPicture) { 55 c = recorder.beginRecording(1, 1); 56 pics++; 57 } 58 59 c->drawLine(0.5, 0, 0, 1, paint); 60 c->drawLine(0.5, 0, 1, 1, paint); 61 c->drawLine(0, 1, 1, 1, paint); 62 63 c->save(); 64 c->scale(0.5, 0.5); 65 66 c->translate(0, 1); 67 pics += this->sierpinsky(c, lvl, paint); 68 69 c->translate(1, 0); 70 pics += this->sierpinsky(c, lvl, paint); 71 72 c->translate(-0.5, -1); 73 pics += this->sierpinsky(c, lvl, paint); 74 c->restore(); 75 76 if (recordPicture) { 77 canvas->drawPicture(recorder.finishRecordingAsPicture()); 78 } 79 80 return pics; 81 } 82 83 int fMaxLevel; 84 int fMaxPictureLevel; 85 86 private: countPics() const87 int countPics() const { 88 // Solve: pics from sierpinsky 89 // f(m) = 1 + 3*f(m - 1) 90 // f(0) = 0 91 // via "recursive function to closed form" tricks 92 // f(m) = 1/2 (3^m - 1) 93 int pics = 1; 94 for (int i = 0; i < fMaxPictureLevel; i++) { 95 pics *= 3; 96 } 97 pics--; 98 pics /= 2; 99 return pics; 100 } 101 102 SkString fName; 103 SkPaint fPaint; 104 105 typedef Benchmark INHERITED; 106 }; 107 108 class PictureNestingRecording : public PictureNesting { 109 public: PictureNestingRecording(int maxLevel,int maxPictureLevel)110 PictureNestingRecording(int maxLevel, int maxPictureLevel) 111 : INHERITED("recording", maxLevel, maxPictureLevel) { 112 } 113 114 protected: isSuitableFor(Backend backend)115 bool isSuitableFor(Backend backend) override { 116 return backend == kNonRendering_Backend; 117 } 118 onDraw(int loops,SkCanvas *)119 void onDraw(int loops, SkCanvas*) override { 120 SkIPoint canvasSize = onGetSize(); 121 SkPictureRecorder recorder; 122 123 for (int i = 0; i < loops; i++) { 124 SkCanvas* c = recorder.beginRecording(SkIntToScalar(canvasSize.x()), 125 SkIntToScalar(canvasSize.y())); 126 this->doDraw(c); 127 (void)recorder.finishRecordingAsPicture(); 128 } 129 } 130 131 private: 132 typedef PictureNesting INHERITED; 133 }; 134 135 class PictureNestingPlayback : public PictureNesting { 136 public: PictureNestingPlayback(int maxLevel,int maxPictureLevel)137 PictureNestingPlayback(int maxLevel, int maxPictureLevel) 138 : INHERITED("playback", maxLevel, maxPictureLevel) { 139 } 140 protected: onDelayedSetup()141 void onDelayedSetup() override { 142 this->INHERITED::onDelayedSetup(); 143 144 SkIPoint canvasSize = onGetSize(); 145 SkPictureRecorder recorder; 146 SkCanvas* c = recorder.beginRecording(SkIntToScalar(canvasSize.x()), 147 SkIntToScalar(canvasSize.y())); 148 149 this->doDraw(c); 150 fPicture = recorder.finishRecordingAsPicture(); 151 } 152 onDraw(int loops,SkCanvas * canvas)153 void onDraw(int loops, SkCanvas* canvas) override { 154 for (int i = 0; i < loops; i++) { 155 canvas->drawPicture(fPicture); 156 } 157 } 158 159 private: 160 sk_sp<SkPicture> fPicture; 161 162 typedef PictureNesting INHERITED; 163 }; 164 165 DEF_BENCH( return new PictureNestingRecording(8, 0); ) 166 DEF_BENCH( return new PictureNestingRecording(8, 1); ) 167 DEF_BENCH( return new PictureNestingRecording(8, 2); ) 168 DEF_BENCH( return new PictureNestingRecording(8, 3); ) 169 DEF_BENCH( return new PictureNestingRecording(8, 4); ) 170 DEF_BENCH( return new PictureNestingRecording(8, 5); ) 171 DEF_BENCH( return new PictureNestingRecording(8, 6); ) 172 DEF_BENCH( return new PictureNestingRecording(8, 7); ) 173 DEF_BENCH( return new PictureNestingRecording(8, 8); ) 174 175 DEF_BENCH( return new PictureNestingPlayback(8, 0); ) 176 DEF_BENCH( return new PictureNestingPlayback(8, 1); ) 177 DEF_BENCH( return new PictureNestingPlayback(8, 2); ) 178 DEF_BENCH( return new PictureNestingPlayback(8, 3); ) 179 DEF_BENCH( return new PictureNestingPlayback(8, 4); ) 180 DEF_BENCH( return new PictureNestingPlayback(8, 5); ) 181 DEF_BENCH( return new PictureNestingPlayback(8, 6); ) 182 DEF_BENCH( return new PictureNestingPlayback(8, 7); ) 183 DEF_BENCH( return new PictureNestingPlayback(8, 8); ) 184