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
22class PatchBench : public Benchmark {
23
24public:
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
83protected:
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
158class SquarePatchBench : public PatchBench {
159public:
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    }
180private:
181    typedef PatchBench INHERITED;
182};
183
184class LODDiffPatchBench : public PatchBench {
185public:
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    }
206private:
207    typedef PatchBench INHERITED;
208};
209
210class LoopPatchBench : public PatchBench {
211public:
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    }
232private:
233    typedef PatchBench INHERITED;
234};
235
236///////////////////////////////////////////////////////////////////////////////
237
238DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kNone_VertexMode); )
239DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kColors_VertexMode); )
240DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kTexCoords_VertexMode); )
241DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kBoth_VertexMode); )
242DEF_BENCH( return new PatchBench(SkVector::Make(1.f, 1.0f), PatchBench::kNone_VertexMode); )
243DEF_BENCH( return new PatchBench(SkVector::Make(1.0f, 1.0f), PatchBench::kColors_VertexMode); )
244DEF_BENCH( return new PatchBench(SkVector::Make(1.0f, 1.0f), PatchBench::kTexCoords_VertexMode); )
245DEF_BENCH( return new PatchBench(SkVector::Make(1.0f, 1.0f), PatchBench::kBoth_VertexMode); )
246DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kNone_VertexMode); )
247DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kColors_VertexMode); )
248DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kTexCoords_VertexMode); )
249DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kBoth_VertexMode); )
250
251DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
252                                       PatchBench::kNone_VertexMode); )
253DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
254                                       PatchBench::kColors_VertexMode); )
255DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
256                                       PatchBench::kTexCoords_VertexMode); )
257DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
258                                       PatchBench::kBoth_VertexMode); )
259DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.f, 1.0f),
260                                       PatchBench::kNone_VertexMode); )
261DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.0f, 1.0f),
262                                       PatchBench::kColors_VertexMode); )
263DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.0f, 1.0f),
264                                       PatchBench::kTexCoords_VertexMode); )
265DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.0f, 1.0f),
266                                       PatchBench::kBoth_VertexMode); )
267DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
268                                       PatchBench::kNone_VertexMode); )
269DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
270                                       PatchBench::kColors_VertexMode); )
271DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
272                                       PatchBench::kTexCoords_VertexMode); )
273DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
274                                       PatchBench::kBoth_VertexMode); )
275
276DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
277                                       PatchBench::kNone_VertexMode); )
278DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
279                                       PatchBench::kColors_VertexMode); )
280DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
281                                       PatchBench::kTexCoords_VertexMode); )
282DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
283                                       PatchBench::kBoth_VertexMode); )
284DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.f, 1.0f),
285                                       PatchBench::kNone_VertexMode); )
286DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.0f, 1.0f),
287                                       PatchBench::kColors_VertexMode); )
288DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.0f, 1.0f),
289                                       PatchBench::kTexCoords_VertexMode); )
290DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.0f, 1.0f),
291                                       PatchBench::kBoth_VertexMode); )
292DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
293                                       PatchBench::kNone_VertexMode); )
294DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
295                                       PatchBench::kColors_VertexMode); )
296DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
297                                       PatchBench::kTexCoords_VertexMode); )
298DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
299                                       PatchBench::kBoth_VertexMode); )
300
301DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
302                                        PatchBench::kNone_VertexMode); )
303DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
304                                        PatchBench::kColors_VertexMode); )
305DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
306                                        PatchBench::kTexCoords_VertexMode); )
307DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
308                                        PatchBench::kBoth_VertexMode); )
309DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.f, 1.0f),
310                                        PatchBench::kNone_VertexMode); )
311DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.0f, 1.0f),
312                                        PatchBench::kColors_VertexMode); )
313DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.0f, 1.0f),
314                                        PatchBench::kTexCoords_VertexMode); )
315DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.0f, 1.0f),
316                                        PatchBench::kBoth_VertexMode); )
317DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
318                                        PatchBench::kNone_VertexMode); )
319DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
320                                        PatchBench::kColors_VertexMode); )
321DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
322                                        PatchBench::kTexCoords_VertexMode); )
323DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
324                                        PatchBench::kBoth_VertexMode); )
325
326//////////////////////////////////////////////
327#include "SkPatchUtils.h"
328
329class PatchUtilsBench : public Benchmark {
330    SkString    fName;
331    const bool  fLinearInterp;
332public:
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};
359DEF_BENCH( return new PatchUtilsBench(false); )
360DEF_BENCH( return new PatchUtilsBench(true); )
361