1 /*
2  * Copyright 2011 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 #ifndef Benchmark_DEFINED
9 #define Benchmark_DEFINED
10 
11 #include "SkPoint.h"
12 #include "SkRefCnt.h"
13 #include "SkString.h"
14 #include "../tools/Registry.h"
15 
16 #define DEF_BENCH3(code, N) \
17     static BenchRegistry gBench##N([](void*) -> Benchmark* { code; });
18 #define DEF_BENCH2(code, N) DEF_BENCH3(code, N)
19 #define DEF_BENCH(code) DEF_BENCH2(code, __COUNTER__)
20 
21 /*
22  *  With the above macros, you can register benches as follows (at the bottom
23  *  of your .cpp)
24  *
25  *  DEF_BENCH(return new MyBenchmark(...))
26  *  DEF_BENCH(return new MyBenchmark(...))
27  *  DEF_BENCH(return new MyBenchmark(...))
28  */
29 
30 struct GrContextOptions;
31 class SkCanvas;
32 class SkPaint;
33 
34 class SkTriState {
35 public:
36     enum State {
37         kDefault,
38         kTrue,
39         kFalse
40     };
41     static const char* Name[];
42 };
43 
44 class Benchmark : public SkRefCnt {
45 public:
46     Benchmark();
47 
48     const char* getName();
49     const char* getUniqueName();
50     SkIPoint getSize();
51 
52     enum Backend {
53         kNonRendering_Backend,
54         kRaster_Backend,
55         kGPU_Backend,
56         kPDF_Backend,
57         kHWUI_Backend,
58     };
59 
60     // Call to determine whether the benchmark is intended for
61     // the rendering mode.
isSuitableFor(Backend backend)62     virtual bool isSuitableFor(Backend backend) {
63         return backend != kNonRendering_Backend;
64     }
65 
66     // Allows a benchmark to override options used to construct the GrContext.
modifyGrContextOptions(GrContextOptions *)67     virtual void modifyGrContextOptions(GrContextOptions*) {}
68 
calculateLoops(int defaultLoops)69     virtual int calculateLoops(int defaultLoops) const {
70         return defaultLoops;
71     }
72 
73     // Call before draw, allows the benchmark to do setup work outside of the
74     // timer. When a benchmark is repeatedly drawn, this should be called once
75     // before the initial draw.
76     void delayedSetup();
77 
78     // Called once before and after a series of draw calls to a single canvas.
79     // The setup/break down in these calls is not timed.
80     void perCanvasPreDraw(SkCanvas*);
81     void perCanvasPostDraw(SkCanvas*);
82 
83     // Called just before and after each call to draw().  Not timed.
84     void preDraw(SkCanvas*);
85     void postDraw(SkCanvas*);
86 
87     // Bench framework can tune loops to be large enough for stable timing.
88     void draw(int loops, SkCanvas*);
89 
setForceAlpha(int alpha)90     void setForceAlpha(int alpha) {
91         fForceAlpha = alpha;
92     }
93 
setDither(SkTriState::State state)94     void setDither(SkTriState::State state) {
95         fDither = state;
96     }
97 
98     /** Assign masks for paint-flags. These will be applied when setupPaint()
99      *  is called.
100      *
101      *  Performs the following on the paint:
102      *      uint32_t flags = paint.getFlags();
103      *      flags &= ~clearMask;
104      *      flags |= orMask;
105      *      paint.setFlags(flags);
106      */
setPaintMasks(uint32_t orMask,uint32_t clearMask)107     void setPaintMasks(uint32_t orMask, uint32_t clearMask) {
108         fOrMask = orMask;
109         fClearMask = clearMask;
110     }
111 
112     /*
113      * Benches which support running in a visual mode can advertise this functionality
114      */
isVisual()115     virtual bool isVisual() { return false; }
116 
117     /*
118      * VisualBench frequently resets the canvas.  As a result we need to bulk call all of the hooks
119      */
preTimingHooks(SkCanvas * canvas)120     void preTimingHooks(SkCanvas* canvas) {
121         this->perCanvasPreDraw(canvas);
122         this->preDraw(canvas);
123     }
124 
postTimingHooks(SkCanvas * canvas)125     void postTimingHooks(SkCanvas* canvas)  {
126         this->postDraw(canvas);
127         this->perCanvasPostDraw(canvas);
128     }
129 
getGpuStats(SkCanvas *,SkTArray<SkString> * keys,SkTArray<double> * values)130     virtual void getGpuStats(SkCanvas*, SkTArray<SkString>* keys, SkTArray<double>* values) {}
131 
132 protected:
133     virtual void setupPaint(SkPaint* paint);
134 
135     virtual const char* onGetName() = 0;
onGetUniqueName()136     virtual const char* onGetUniqueName() { return this->onGetName(); }
onDelayedSetup()137     virtual void onDelayedSetup() {}
onPerCanvasPreDraw(SkCanvas *)138     virtual void onPerCanvasPreDraw(SkCanvas*) {}
onPerCanvasPostDraw(SkCanvas *)139     virtual void onPerCanvasPostDraw(SkCanvas*) {}
onPreDraw(SkCanvas *)140     virtual void onPreDraw(SkCanvas*) {}
onPostDraw(SkCanvas *)141     virtual void onPostDraw(SkCanvas*) {}
142     // Each bench should do its main work in a loop like this:
143     //   for (int i = 0; i < loops; i++) { <work here> }
144     virtual void onDraw(int loops, SkCanvas*) = 0;
145 
146     virtual SkIPoint onGetSize();
147 
148 private:
149     int     fForceAlpha;
150     SkTriState::State  fDither;
151     uint32_t    fOrMask, fClearMask;
152 
153     typedef SkRefCnt INHERITED;
154 };
155 
156 typedef sk_tools::Registry<Benchmark*(*)(void*)> BenchRegistry;
157 
158 #endif
159