/* * 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: virtual bool isSuitableFor(Backend backend) { return backend == kNonRendering_Backend; } virtual void onDraw(const int loops, SkCanvas*) { 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 onPreDraw() override { this->INHERITED::onPreDraw(); SkIPoint canvasSize = onGetSize(); SkPictureRecorder recorder; SkCanvas* c = recorder.beginRecording(SkIntToScalar(canvasSize.x()), SkIntToScalar(canvasSize.y())); this->doDraw(c); fPicture.reset(recorder.endRecording()); } virtual void onDraw(const int loops, SkCanvas* canvas) { 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); )