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 "include/core/SkRefCnt.h" 12 #include "include/core/SkSize.h" 13 #include "include/core/SkString.h" 14 #include "include/private/base/SkTArray.h" 15 #include "tools/Registry.h" 16 17 #if defined(SK_GRAPHITE) 18 #include "include/gpu/graphite/Context.h" 19 #endif 20 21 #include <functional> 22 23 #define DEF_BENCH3(code, N) \ 24 static BenchRegistry gBench##N([](void*) -> Benchmark* { code; }); 25 #define DEF_BENCH2(code, N) DEF_BENCH3(code, N) 26 #define DEF_BENCH(code) DEF_BENCH2(code, __COUNTER__) 27 28 /* 29 * With the above macros, you can register benches as follows (at the bottom 30 * of your .cpp) 31 * 32 * DEF_BENCH(return new MyBenchmark(...)) 33 * DEF_BENCH(return new MyBenchmark(...)) 34 * DEF_BENCH(return new MyBenchmark(...)) 35 */ 36 37 struct GrContextOptions; 38 class GrRecordingContext; 39 class SkCanvas; 40 class SkPaint; 41 42 class Benchmark : public SkRefCnt { 43 public: 44 Benchmark(); 45 46 const char* getName(); 47 const char* getUniqueName(); 48 SkISize getSize(); 49 50 enum class Backend { 51 kNonRendering, 52 kRaster, 53 kGanesh, 54 kGraphite, 55 kPDF, 56 kHWUI, 57 }; 58 59 // Call to determine whether the benchmark is intended for 60 // the rendering mode. isSuitableFor(Backend backend)61 virtual bool isSuitableFor(Backend backend) { 62 return backend != Backend::kNonRendering; 63 } 64 65 // Allows a benchmark to override options used to construct the GrContext. modifyGrContextOptions(GrContextOptions *)66 virtual void modifyGrContextOptions(GrContextOptions*) {} 67 68 #if defined(SK_GRAPHITE) modifyGraphiteContextOptions(skgpu::graphite::ContextOptions *)69 virtual void modifyGraphiteContextOptions(skgpu::graphite::ContextOptions*) {} 70 #endif 71 72 // Whether or not this benchmark requires multiple samples to get a meaningful result. shouldLoop()73 virtual bool shouldLoop() const { 74 return true; 75 } 76 77 // Call before draw, allows the benchmark to do setup work outside of the 78 // timer. When a benchmark is repeatedly drawn, this should be called once 79 // before the initial draw. 80 void delayedSetup(); 81 82 // Called once before and after a series of draw calls to a single canvas. 83 // The setup/break down in these calls is not timed. 84 void perCanvasPreDraw(SkCanvas*); 85 void perCanvasPostDraw(SkCanvas*); 86 87 // Called just before and after each call to draw(). Not timed. 88 void preDraw(SkCanvas*); 89 void postDraw(SkCanvas*); 90 91 // Bench framework can tune loops to be large enough for stable timing. 92 void draw(int loops, SkCanvas*, std::function<void()> submitFrame = nullptr); 93 getGpuStats(SkCanvas *,skia_private::TArray<SkString> * keys,skia_private::TArray<double> * values)94 virtual void getGpuStats(SkCanvas*, 95 skia_private::TArray<SkString>* keys, 96 skia_private::TArray<double>* values) {} 97 98 // Replaces the GrRecordingContext's dmsaaStats() with a single frame of this benchmark. getDMSAAStats(GrRecordingContext *)99 virtual bool getDMSAAStats(GrRecordingContext*) { return false; } 100 101 // Count of units (pixels, whatever) being exercised, to scale timing by. getUnits()102 int getUnits() const { return fUnits; } 103 104 protected: setUnits(int units)105 void setUnits(int units) { SkASSERT(units > 0); fUnits = units; } 106 107 virtual void setupPaint(SkPaint* paint); 108 109 virtual const char* onGetName() = 0; onGetUniqueName()110 virtual const char* onGetUniqueName() { return this->onGetName(); } onDelayedSetup()111 virtual void onDelayedSetup() {} onPerCanvasPreDraw(SkCanvas *)112 virtual void onPerCanvasPreDraw(SkCanvas*) {} onPerCanvasPostDraw(SkCanvas *)113 virtual void onPerCanvasPostDraw(SkCanvas*) {} onPreDraw(SkCanvas *)114 virtual void onPreDraw(SkCanvas*) {} onPostDraw(SkCanvas *)115 virtual void onPostDraw(SkCanvas*) {} 116 // Each bench should do its main work in a loop like this: 117 // for (int i = 0; i < loops; i++) { <work here> } 118 virtual void onDraw(int loops, SkCanvas*) = 0; 119 // Similar to onDraw except after each frame the Benchmark draws it should call the endFrame 120 // callback (if valid). This is useful for Benchmarks like MSKP which inherently draw multiple 121 // frames within one draw call. Benchmarks that want to use this should make sure to return 122 // true from hasInternalFrames. onDrawFrame(int loops,SkCanvas *,std::function<void ()> endFrame)123 virtual void onDrawFrame(int loops, SkCanvas*, std::function<void()> endFrame) {} 124 125 virtual SkISize onGetSize(); 126 127 private: 128 // If the Benchmark has its own internal frames (e.g. MSKPs) this function should return true. 129 // If it returns true then onDrawFrame will be called intstead of onDraw. submitsInternalFrames()130 virtual bool submitsInternalFrames() { return false; } 131 132 int fUnits = 1; 133 134 using INHERITED = SkRefCnt; 135 }; 136 137 typedef sk_tools::Registry<Benchmark*(*)(void*)> BenchRegistry; 138 139 #endif 140