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 "bench/Benchmark.h" 9 #include "include/core/SkCanvas.h" 10 #include "include/core/SkImage.h" 11 #include "include/effects/SkImageFilters.h" 12 #include "tools/DecodeUtils.h" 13 #include "tools/Resources.h" 14 15 #if defined(SK_GANESH) 16 #include "include/gpu/ganesh/GrRecordingContext.h" 17 #include "include/gpu/ganesh/SkImageGanesh.h" 18 #endif 19 20 #if defined(SK_GRAPHITE) 21 #include "include/gpu/graphite/Image.h" 22 #endif 23 24 // Exercise a blur filter connected to 5 inputs of the same merge filter. 25 // This bench shows an improvement in performance once cacheing of re-used 26 // nodes is implemented, since the DAG is no longer flattened to a tree. 27 class ImageFilterDAGBench : public Benchmark { 28 public: ImageFilterDAGBench()29 ImageFilterDAGBench() {} 30 31 protected: onGetName()32 const char* onGetName() override { 33 return "image_filter_dag"; 34 } 35 onDraw(int loops,SkCanvas * canvas)36 void onDraw(int loops, SkCanvas* canvas) override { 37 const SkRect rect = SkRect::Make(SkIRect::MakeWH(400, 400)); 38 39 // Set up the filters once, we're not interested in measuring allocation time here 40 sk_sp<SkImageFilter> blur(SkImageFilters::Blur(20.0f, 20.0f, nullptr)); 41 sk_sp<SkImageFilter> inputs[kNumInputs]; 42 for (int i = 0; i < kNumInputs; ++i) { 43 inputs[i] = blur; 44 } 45 SkPaint paint; 46 paint.setImageFilter(SkImageFilters::Merge(inputs, kNumInputs)); 47 48 // Only measure the filter computations done in drawRect() 49 // TODO (michaelludwig) - This benchmark, and the ones defined below, allocate their filters 50 // outside of the loop. This means that repeatedly drawing with the same filter will hit 51 // the global image filter cache inside the loop. Raster backend uses this cache so will see 52 // artificially improved performance. Ganesh will not because it uses a cache per filter 53 // call, so only within-DAG cache hits are measured (as desired). skbug:9297 wants to move 54 // raster backend to the same pattern, which will make the benchmark executions fair again. 55 for (int j = 0; j < loops; j++) { 56 canvas->drawRect(rect, paint); 57 } 58 } 59 60 private: 61 static const int kNumInputs = 5; 62 63 using INHERITED = Benchmark; 64 }; 65 66 class ImageMakeWithFilterDAGBench : public Benchmark { 67 public: ImageMakeWithFilterDAGBench()68 ImageMakeWithFilterDAGBench() {} 69 70 protected: onGetName()71 const char* onGetName() override { 72 return "image_make_with_filter_dag"; 73 } 74 onDelayedSetup()75 void onDelayedSetup() override { 76 fImage = ToolUtils::GetResourceAsImage("images/mandrill_512.png"); 77 } 78 onDraw(int loops,SkCanvas * canvas)79 void onDraw(int loops, SkCanvas* canvas) override { 80 SkIRect subset = SkIRect::MakeSize(fImage->dimensions()); 81 SkIPoint offset = SkIPoint::Make(0, 0); 82 SkIRect discardSubset; 83 84 // Set up the filters once so the allocation cost isn't included per-loop 85 sk_sp<SkImageFilter> blur(SkImageFilters::Blur(20.0f, 20.0f, nullptr)); 86 sk_sp<SkImageFilter> inputs[kNumInputs]; 87 for (int i = 0; i < kNumInputs; ++i) { 88 inputs[i] = blur; 89 } 90 sk_sp<SkImageFilter> mergeFilter = SkImageFilters::Merge(inputs, kNumInputs); 91 92 // But measure MakeWithFilter() per loop since that's the focus of this benchmark 93 for (int j = 0; j < loops; j++) { 94 sk_sp<SkImage> image; 95 96 #if defined(SK_GANESH) 97 if (auto rContext = canvas->recordingContext()) { 98 image = SkImages::MakeWithFilter(rContext, fImage, mergeFilter.get(), 99 subset, subset, &discardSubset, &offset); 100 } else 101 #endif 102 #if defined(SK_GRAPHITE) 103 if (auto recorder = canvas->recorder()) { 104 image = SkImages::MakeWithFilter(recorder, fImage, mergeFilter.get(), 105 subset, subset, &discardSubset, &offset); 106 } else 107 #endif 108 { 109 image = SkImages::MakeWithFilter(fImage, mergeFilter.get(), 110 subset, subset, &discardSubset, &offset); 111 } 112 } 113 } 114 115 private: 116 static const int kNumInputs = 5; 117 sk_sp<SkImage> fImage; 118 119 using INHERITED = Benchmark; 120 }; 121 122 // Exercise a blur filter connected to both inputs of an SkDisplacementMapEffect. 123 124 class ImageFilterDisplacedBlur : public Benchmark { 125 public: ImageFilterDisplacedBlur()126 ImageFilterDisplacedBlur() {} 127 128 protected: onGetName()129 const char* onGetName() override { 130 return "image_filter_displaced_blur"; 131 } 132 onDraw(int loops,SkCanvas * canvas)133 void onDraw(int loops, SkCanvas* canvas) override { 134 // Setup filter once 135 sk_sp<SkImageFilter> blur(SkImageFilters::Blur(4.0f, 4.0f, nullptr)); 136 SkScalar scale = 2; 137 138 SkPaint paint; 139 paint.setImageFilter(SkImageFilters::DisplacementMap(SkColorChannel::kR, SkColorChannel::kR, 140 scale, blur, blur)); 141 142 SkRect rect = SkRect::Make(SkIRect::MakeWH(400, 400)); 143 144 // As before, measure just the filter computation time inside the loops 145 for (int j = 0; j < loops; j++) { 146 canvas->drawRect(rect, paint); 147 } 148 } 149 150 private: 151 using INHERITED = Benchmark; 152 }; 153 154 // Exercise an Xfermode kSrcIn filter compositing two inputs which have a small intersection. 155 class ImageFilterXfermodeIn : public Benchmark { 156 public: ImageFilterXfermodeIn()157 ImageFilterXfermodeIn() {} 158 159 protected: onGetName()160 const char* onGetName() override { return "image_filter_xfermode_in"; } 161 onDraw(int loops,SkCanvas * canvas)162 void onDraw(int loops, SkCanvas* canvas) override { 163 // Allocate filters once to avoid measuring instantiation time 164 auto blur = SkImageFilters::Blur(20.0f, 20.0f, nullptr); 165 auto offset1 = SkImageFilters::Offset(100.0f, 100.0f, blur); 166 auto offset2 = SkImageFilters::Offset(-100.0f, -100.0f, blur); 167 auto xfermode = 168 SkImageFilters::Blend(SkBlendMode::kSrcIn, offset1, offset2, nullptr); 169 170 SkPaint paint; 171 paint.setImageFilter(xfermode); 172 173 // Measure only the filter time 174 for (int j = 0; j < loops; j++) { 175 canvas->drawRect(SkRect::MakeWH(200.0f, 200.0f), paint); 176 } 177 } 178 179 private: 180 using INHERITED = Benchmark; 181 }; 182 183 DEF_BENCH(return new ImageFilterDAGBench;) 184 DEF_BENCH(return new ImageMakeWithFilterDAGBench;) 185 DEF_BENCH(return new ImageFilterDisplacedBlur;) 186 DEF_BENCH(return new ImageFilterXfermodeIn;) 187