| /* | 
 |  * Copyright 2014 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #include "Benchmark.h" | 
 | #include "SkCanvas.h" | 
 | #include "SkColor.h" | 
 | #include "SkNullCanvas.h" | 
 | #include "SkPaint.h" | 
 | #include "SkPicture.h" | 
 | #include "SkPictureRecorder.h" | 
 | #include "SkString.h" | 
 |  | 
 | class PictureNesting : public Benchmark { | 
 | public: | 
 |     PictureNesting(const char* name, int maxLevel, int maxPictureLevel) | 
 |         : fMaxLevel(maxLevel) | 
 |         , fMaxPictureLevel(maxPictureLevel) { | 
 |         fName.printf("picture_nesting_%s_%d", name, this->countPics()); | 
 |         fPaint.setColor(SK_ColorRED); | 
 |         fPaint.setAntiAlias(true); | 
 |         fPaint.setStyle(SkPaint::kStroke_Style); | 
 |     } | 
 |  | 
 | protected: | 
 |     const char* onGetName() override { | 
 |         return fName.c_str(); | 
 |     } | 
 |  | 
 |     void doDraw(SkCanvas* canvas) { | 
 |         SkIPoint canvasSize = onGetSize(); | 
 |         canvas->save(); | 
 |         canvas->scale(SkIntToScalar(canvasSize.x()), SkIntToScalar(canvasSize.y())); | 
 |  | 
 |         SkDEBUGCODE(int pics = ) this->sierpinsky(canvas, 0, fPaint); | 
 |         SkASSERT(pics == this->countPics()); | 
 |  | 
 |         canvas->restore(); | 
 |     } | 
 |  | 
 |     int sierpinsky(SkCanvas* canvas, int lvl, const SkPaint& paint) { | 
 |         if (++lvl > fMaxLevel) { | 
 |             return 0; | 
 |         } | 
 |  | 
 |         int pics = 0; | 
 |         bool recordPicture = lvl <= fMaxPictureLevel; | 
 |         SkPictureRecorder recorder; | 
 |         SkCanvas* c = canvas; | 
 |  | 
 |         if (recordPicture) { | 
 |             c = recorder.beginRecording(1, 1); | 
 |             pics++; | 
 |         } | 
 |  | 
 |         c->drawLine(0.5, 0, 0, 1, paint); | 
 |         c->drawLine(0.5, 0, 1, 1, paint); | 
 |         c->drawLine(0,   1, 1, 1, paint); | 
 |  | 
 |         c->save(); | 
 |             c->scale(0.5, 0.5); | 
 |  | 
 |             c->translate(0, 1); | 
 |             pics += this->sierpinsky(c, lvl, paint); | 
 |  | 
 |             c->translate(1, 0); | 
 |             pics += this->sierpinsky(c, lvl, paint); | 
 |  | 
 |             c->translate(-0.5, -1); | 
 |             pics += this->sierpinsky(c, lvl, paint); | 
 |         c->restore(); | 
 |  | 
 |         if (recordPicture) { | 
 |             SkAutoTUnref<SkPicture> picture(recorder.endRecording()); | 
 |             canvas->drawPicture(picture); | 
 |         } | 
 |  | 
 |         return pics; | 
 |     } | 
 |  | 
 |     int fMaxLevel; | 
 |     int fMaxPictureLevel; | 
 |  | 
 | private: | 
 |     int countPics() const { | 
 |         // Solve: pics from sierpinsky | 
 |         // f(m) = 1 + 3*f(m - 1) | 
 |         // f(0) = 0 | 
 |         //   via "recursive function to closed form" tricks | 
 |         // f(m) = 1/2 (3^m - 1) | 
 |         int pics = 1; | 
 |         for (int i = 0; i < fMaxPictureLevel; i++) { | 
 |             pics *= 3; | 
 |         } | 
 |         pics--; | 
 |         pics /= 2; | 
 |         return pics; | 
 |     } | 
 |  | 
 |     SkString fName; | 
 |     SkPaint  fPaint; | 
 |  | 
 |     typedef Benchmark INHERITED; | 
 | }; | 
 |  | 
 | class PictureNestingRecording : public PictureNesting { | 
 | public: | 
 |     PictureNestingRecording(int maxLevel, int maxPictureLevel) | 
 |         : INHERITED("recording", maxLevel, maxPictureLevel) { | 
 |     } | 
 |  | 
 | protected: | 
 |     bool isSuitableFor(Backend backend) override { | 
 |         return backend == kNonRendering_Backend; | 
 |     } | 
 |  | 
 |     void onDraw(int loops, SkCanvas*) override { | 
 |         SkIPoint canvasSize = onGetSize(); | 
 |         SkPictureRecorder recorder; | 
 |  | 
 |         for (int i = 0; i < loops; i++) { | 
 |             SkCanvas* c = recorder.beginRecording(SkIntToScalar(canvasSize.x()), | 
 |                                                   SkIntToScalar(canvasSize.y())); | 
 |             this->doDraw(c); | 
 |             SkAutoTUnref<SkPicture> picture(recorder.endRecording()); | 
 |         } | 
 |     } | 
 |  | 
 | private: | 
 |     typedef PictureNesting INHERITED; | 
 | }; | 
 |  | 
 | class PictureNestingPlayback : public PictureNesting { | 
 | public: | 
 |     PictureNestingPlayback(int maxLevel, int maxPictureLevel) | 
 |         : INHERITED("playback", maxLevel, maxPictureLevel) { | 
 |     } | 
 | protected: | 
 |     void onDelayedSetup() override { | 
 |         this->INHERITED::onDelayedSetup(); | 
 |  | 
 |         SkIPoint canvasSize = onGetSize(); | 
 |         SkPictureRecorder recorder; | 
 |         SkCanvas* c = recorder.beginRecording(SkIntToScalar(canvasSize.x()), | 
 |                                               SkIntToScalar(canvasSize.y())); | 
 |  | 
 |         this->doDraw(c); | 
 |         fPicture.reset(recorder.endRecording()); | 
 |     } | 
 |  | 
 |     void onDraw(int loops, SkCanvas* canvas) override { | 
 |         for (int i = 0; i < loops; i++) { | 
 |             canvas->drawPicture(fPicture); | 
 |         } | 
 |     } | 
 |  | 
 | private: | 
 |     SkAutoTUnref<SkPicture> fPicture; | 
 |  | 
 |     typedef PictureNesting INHERITED; | 
 | }; | 
 |  | 
 | DEF_BENCH( return new PictureNestingRecording(8, 0); ) | 
 | DEF_BENCH( return new PictureNestingRecording(8, 1); ) | 
 | DEF_BENCH( return new PictureNestingRecording(8, 2); ) | 
 | DEF_BENCH( return new PictureNestingRecording(8, 3); ) | 
 | DEF_BENCH( return new PictureNestingRecording(8, 4); ) | 
 | DEF_BENCH( return new PictureNestingRecording(8, 5); ) | 
 | DEF_BENCH( return new PictureNestingRecording(8, 6); ) | 
 | DEF_BENCH( return new PictureNestingRecording(8, 7); ) | 
 | DEF_BENCH( return new PictureNestingRecording(8, 8); ) | 
 |  | 
 | DEF_BENCH( return new PictureNestingPlayback(8, 0); ) | 
 | DEF_BENCH( return new PictureNestingPlayback(8, 1); ) | 
 | DEF_BENCH( return new PictureNestingPlayback(8, 2); ) | 
 | DEF_BENCH( return new PictureNestingPlayback(8, 3); ) | 
 | DEF_BENCH( return new PictureNestingPlayback(8, 4); ) | 
 | DEF_BENCH( return new PictureNestingPlayback(8, 5); ) | 
 | DEF_BENCH( return new PictureNestingPlayback(8, 6); ) | 
 | DEF_BENCH( return new PictureNestingPlayback(8, 7); ) | 
 | DEF_BENCH( return new PictureNestingPlayback(8, 8); ) |