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 #include "Benchmark.h"
8 #include "SkCanvas.h"
9 #include "SkGradientShader.h"
10 #include "SkPaint.h"
11 #include "SkPatchUtils.h"
12 #include "SkString.h"
13 
14 /**
15  * This bench measures the rendering time of the call SkCanvas::drawPatch with different types of
16  * input patches (regular case, with loops, a square, with a big difference between "parallel"
17  * sides). This bench also tests the different combination of optional parameters for the function
18  * (passing texture coordinates and colors, only textures coordinates, only colors or none).
19  * Finally, it applies a scale to test if the size affects the rendering time.
20  */
21 
22 class PatchBench : public Benchmark {
23 
24 public:
25 
26     enum VertexMode {
27         kNone_VertexMode,
28         kColors_VertexMode,
29         kTexCoords_VertexMode,
30         kBoth_VertexMode
31     };
32 
33     PatchBench(SkPoint scale, VertexMode vertexMode)
34     : fScale(scale)
35     , fVertexMode(vertexMode) { }
36 
37     // to add name of specific class override this method
38     virtual void appendName(SkString* name) {
39         name->append("normal");
40     }
41 
42     // to make other type of patches override this method
43     virtual void setCubics() {
44         const SkPoint points[SkPatchUtils::kNumCtrlPts] = {
45             //top points
46             {100,100},{150,50},{250,150}, {300,100},
47             //right points
48             {350, 150},{250,200},
49             //bottom points
50             {300,300},{250,250},{150,350},{100,300},
51             //left points
52             {50,250},{150,50}
53         };
54         memcpy(fCubics, points, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
55     }
56 
57     virtual void setColors() {
58         const SkColor colors[SkPatchUtils::kNumCorners] = {
59             SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorCYAN
60         };
61         memcpy(fColors, colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
62     }
63 
64     virtual void setTexCoords() {
65         const SkPoint texCoords[SkPatchUtils::kNumCorners] = {
66             {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f,1.0f}, {0.0f, 1.0f}
67         };
68         memcpy(fTexCoords, texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
69     }
70 
71     // override this method to change the shader
72     virtual sk_sp<SkShader> createShader() {
73         const SkColor colors[] = {
74             SK_ColorRED, SK_ColorCYAN, SK_ColorGREEN, SK_ColorWHITE,
75             SK_ColorMAGENTA, SK_ColorBLUE, SK_ColorYELLOW,
76         };
77         const SkPoint pts[] = { { 200.f / 4.f, 0.f }, { 3.f * 200.f / 4, 200.f } };
78 
79         return SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors),
80                                             SkShader::kMirror_TileMode);
81     }
82 
83 protected:
84     const char* onGetName() override {
85         SkString vertexMode;
86         switch (fVertexMode) {
87             case kNone_VertexMode:
88                 vertexMode.set("meshlines");
89                 break;
90             case kColors_VertexMode:
91                 vertexMode.set("colors");
92                 break;
93             case kTexCoords_VertexMode:
94                 vertexMode.set("texs");
95                 break;
96             case kBoth_VertexMode:
97                 vertexMode.set("colors_texs");
98                 break;
99             default:
100                 break;
101         }
102         SkString type;
103         this->appendName(&type);
104         fName.printf("patch_%s_%s_%fx%f", type.c_str(), vertexMode.c_str(),
105                     fScale.x(), fScale.y());
106         return fName.c_str();
107     }
108 
109     void onDelayedSetup() override {
110         this->setCubics();
111         this->setColors();
112         this->setTexCoords();
113         this->setupPaint(&fPaint);
114         switch (fVertexMode) {
115             case kTexCoords_VertexMode:
116             case kBoth_VertexMode:
117                 fPaint.setShader(this->createShader());
118                 break;
119             default:
120                 fPaint.setShader(nullptr);
121                 break;
122         }
123     }
124 
125     void onDraw(int loops, SkCanvas* canvas) override {
126         canvas->scale(fScale.x(), fScale.y());
127         for (int i = 0; i < loops; i++) {
128             switch (fVertexMode) {
129                 case kNone_VertexMode:
130                     canvas->drawPatch(fCubics, nullptr, nullptr, fPaint);
131                     break;
132                 case kColors_VertexMode:
133                     canvas->drawPatch(fCubics, fColors, nullptr, fPaint);
134                     break;
135                 case kTexCoords_VertexMode:
136                     canvas->drawPatch(fCubics, nullptr, fTexCoords, fPaint);
137                     break;
138                 case kBoth_VertexMode:
139                     canvas->drawPatch(fCubics, fColors, fTexCoords, fPaint);
140                     break;
141                 default:
142                     break;
143             }
144         }
145     }
146 
147     SkPaint     fPaint;
148     SkString    fName;
149     SkVector    fScale;
150     SkPoint     fCubics[12];
151     SkPoint     fTexCoords[4];
152     SkColor     fColors[4];
153     VertexMode  fVertexMode;
154 
155     typedef Benchmark INHERITED;
156 };
157 
158 class SquarePatchBench : public PatchBench {
159 public:
160     SquarePatchBench(SkPoint scale, VertexMode vertexMode)
161     : INHERITED(scale, vertexMode) { }
162 
163     void appendName(SkString* name) override {
164         name->append("square");
165     }
166 
167     void setCubics() override {
168         const SkPoint points[SkPatchUtils::kNumCtrlPts] = {
169             //top points
170             {100,100},{150,100},{250,100}, {300,100},
171             //right points
172             {300, 150},{300,250},
173             //bottom points
174             {300,300},{250,300},{150,300},{100,300},
175             //left points
176             {100,250},{100,150}
177         };
178         memcpy(fCubics, points, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
179     }
180 private:
181     typedef PatchBench INHERITED;
182 };
183 
184 class LODDiffPatchBench : public PatchBench {
185 public:
186     LODDiffPatchBench(SkPoint scale, VertexMode vertexMode)
187     : INHERITED(scale, vertexMode) { }
188 
189     void appendName(SkString* name) override {
190         name->append("LOD_Diff");
191     }
192 
193     void setCubics() override {
194         const SkPoint points[SkPatchUtils::kNumCtrlPts] = {
195             //top points
196             {100,175},{150,100},{250,100}, {300,0},
197             //right points
198             {300, 150},{300,250},
199             //bottom points
200             {300,400},{250,300},{150,300},{100,225},
201             //left points
202             {100,215},{100,185}
203         };
204         memcpy(fCubics, points, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
205     }
206 private:
207     typedef PatchBench INHERITED;
208 };
209 
210 class LoopPatchBench : public PatchBench {
211 public:
212     LoopPatchBench(SkPoint scale, VertexMode vertexMode)
213     : INHERITED(scale, vertexMode) { }
214 
215     void appendName(SkString* name) override {
216         name->append("loop");
217     }
218 
219     void setCubics() override {
220         const SkPoint points[SkPatchUtils::kNumCtrlPts] = {
221             //top points
222             {100,100},{300,200},{100,200}, {300,100},
223             //right points
224             {380, 400},{380,0},
225             //bottom points
226             {300,300},{250,250},{30,200},{100,300},
227             //left points
228             {140,325},{150,150}
229         };
230         memcpy(fCubics, points, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
231     }
232 private:
233     typedef PatchBench INHERITED;
234 };
235 
236 ///////////////////////////////////////////////////////////////////////////////
237 
238 DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kNone_VertexMode); )
239 DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kColors_VertexMode); )
240 DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kTexCoords_VertexMode); )
241 DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kBoth_VertexMode); )
242 DEF_BENCH( return new PatchBench(SkVector::Make(1.f, 1.0f), PatchBench::kNone_VertexMode); )
243 DEF_BENCH( return new PatchBench(SkVector::Make(1.0f, 1.0f), PatchBench::kColors_VertexMode); )
244 DEF_BENCH( return new PatchBench(SkVector::Make(1.0f, 1.0f), PatchBench::kTexCoords_VertexMode); )
245 DEF_BENCH( return new PatchBench(SkVector::Make(1.0f, 1.0f), PatchBench::kBoth_VertexMode); )
246 DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kNone_VertexMode); )
247 DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kColors_VertexMode); )
248 DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kTexCoords_VertexMode); )
249 DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kBoth_VertexMode); )
250 
251 DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
252                                        PatchBench::kNone_VertexMode); )
253 DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
254                                        PatchBench::kColors_VertexMode); )
255 DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
256                                        PatchBench::kTexCoords_VertexMode); )
257 DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
258                                        PatchBench::kBoth_VertexMode); )
259 DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.f, 1.0f),
260                                        PatchBench::kNone_VertexMode); )
261 DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.0f, 1.0f),
262                                        PatchBench::kColors_VertexMode); )
263 DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.0f, 1.0f),
264                                        PatchBench::kTexCoords_VertexMode); )
265 DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.0f, 1.0f),
266                                        PatchBench::kBoth_VertexMode); )
267 DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
268                                        PatchBench::kNone_VertexMode); )
269 DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
270                                        PatchBench::kColors_VertexMode); )
271 DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
272                                        PatchBench::kTexCoords_VertexMode); )
273 DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
274                                        PatchBench::kBoth_VertexMode); )
275 
276 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
277                                        PatchBench::kNone_VertexMode); )
278 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
279                                        PatchBench::kColors_VertexMode); )
280 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
281                                        PatchBench::kTexCoords_VertexMode); )
282 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
283                                        PatchBench::kBoth_VertexMode); )
284 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.f, 1.0f),
285                                        PatchBench::kNone_VertexMode); )
286 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.0f, 1.0f),
287                                        PatchBench::kColors_VertexMode); )
288 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.0f, 1.0f),
289                                        PatchBench::kTexCoords_VertexMode); )
290 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.0f, 1.0f),
291                                        PatchBench::kBoth_VertexMode); )
292 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
293                                        PatchBench::kNone_VertexMode); )
294 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
295                                        PatchBench::kColors_VertexMode); )
296 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
297                                        PatchBench::kTexCoords_VertexMode); )
298 DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
299                                        PatchBench::kBoth_VertexMode); )
300 
301 DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
302                                         PatchBench::kNone_VertexMode); )
303 DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
304                                         PatchBench::kColors_VertexMode); )
305 DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
306                                         PatchBench::kTexCoords_VertexMode); )
307 DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
308                                         PatchBench::kBoth_VertexMode); )
309 DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.f, 1.0f),
310                                         PatchBench::kNone_VertexMode); )
311 DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.0f, 1.0f),
312                                         PatchBench::kColors_VertexMode); )
313 DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.0f, 1.0f),
314                                         PatchBench::kTexCoords_VertexMode); )
315 DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.0f, 1.0f),
316                                         PatchBench::kBoth_VertexMode); )
317 DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
318                                         PatchBench::kNone_VertexMode); )
319 DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
320                                         PatchBench::kColors_VertexMode); )
321 DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
322                                         PatchBench::kTexCoords_VertexMode); )
323 DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
324                                         PatchBench::kBoth_VertexMode); )
325 
326 //////////////////////////////////////////////
327 #include "SkPatchUtils.h"
328 
329 class PatchUtilsBench : public Benchmark {
330     SkString    fName;
331     const bool  fLinearInterp;
332 public:
333     PatchUtilsBench(bool linearInterp) : fLinearInterp(linearInterp) {
334         fName.printf("patchutils_%s", linearInterp ? "linear" : "legacy");
335     }
336 
337     const char* onGetName() override { return fName.c_str(); }
338 
339     bool isSuitableFor(Backend backend) override {
340         return backend == kNonRendering_Backend;
341     }
342 
343     void onDraw(int loops, SkCanvas*) override {
344         const SkColor colors[] = { 0xFF000000, 0xFF00FF00, 0xFF0000FF, 0xFFFF0000 };
345         const SkPoint pts[] = {
346             { 0, 0 }, { 10, 0 }, { 20, 0 }, { 30, 0 },
347             { 30,10}, { 30,20 }, { 30,30 }, { 20,30 },
348             { 10,30}, { 0, 30 }, { 0, 20 }, { 0, 10 },
349         };
350         const SkPoint tex[] = {
351             { 0, 0 }, { 10, 0 }, { 10, 10 }, { 0, 10 },
352         };
353 
354         for (int i = 0; i < 100*loops; ++i) {
355             SkPatchUtils::MakeVertices(pts, colors, tex, 20, 20, fLinearInterp);
356         }
357     }
358 };
359 DEF_BENCH( return new PatchUtilsBench(false); )
360 DEF_BENCH( return new PatchUtilsBench(true); )
361