| /* | |
| * 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) { | |
| canvas->drawPicture(recorder.finishRecordingAsPicture()); | |
| } | |
| 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); | |
| (void)recorder.finishRecordingAsPicture(); | |
| } | |
| } | |
| 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 = recorder.finishRecordingAsPicture(); | |
| } | |
| void onDraw(int loops, SkCanvas* canvas) override { | |
| for (int i = 0; i < loops; i++) { | |
| canvas->drawPicture(fPicture); | |
| } | |
| } | |
| private: | |
| sk_sp<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); ) |