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 "Benchmark.h"
9 #include "SkCanvas.h"
10 #include "SkColor.h"
11 #include "SkNullCanvas.h"
12 #include "SkPaint.h"
13 #include "SkPicture.h"
14 #include "SkPictureRecorder.h"
15 #include "SkString.h"
16 
17 class PictureNesting : public Benchmark {
18 public:
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:
29     const char* onGetName() override {
30         return fName.c_str();
31     }
32 
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 
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:
87     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:
110     PictureNestingRecording(int maxLevel, int maxPictureLevel)
111         : INHERITED("recording", maxLevel, maxPictureLevel) {
112     }
113 
114 protected:
115     bool isSuitableFor(Backend backend) override {
116         return backend == kNonRendering_Backend;
117     }
118 
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:
137     PictureNestingPlayback(int maxLevel, int maxPictureLevel)
138         : INHERITED("playback", maxLevel, maxPictureLevel) {
139     }
140 protected:
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 
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