/*
* 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); )