blob: 7c586f4a319f8d542d2ec509115423828978d842 [file] [log] [blame]
senorblanco@chromium.org0d643562014-04-10 16:16:13 +00001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "bench/Benchmark.h"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkImage.h"
Michael Ludwig23003182019-08-05 11:25:23 -040011#include "include/effects/SkImageFilters.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "tools/Resources.h"
senorblanco@chromium.org0d643562014-04-10 16:16:13 +000013
14// Exercise a blur filter connected to 5 inputs of the same merge filter.
15// This bench shows an improvement in performance once cacheing of re-used
16// nodes is implemented, since the DAG is no longer flattened to a tree.
tfarinaf168b862014-06-19 12:32:29 -070017class ImageFilterDAGBench : public Benchmark {
senorblanco@chromium.org0d643562014-04-10 16:16:13 +000018public:
mtkleinbb6a0282014-07-01 08:43:42 -070019 ImageFilterDAGBench() {}
senorblanco@chromium.org0d643562014-04-10 16:16:13 +000020
21protected:
mtklein36352bf2015-03-25 18:17:31 -070022 const char* onGetName() override {
senorblanco@chromium.org0d643562014-04-10 16:16:13 +000023 return "image_filter_dag";
24 }
25
mtkleina1ebeb22015-10-01 09:43:39 -070026 void onDraw(int loops, SkCanvas* canvas) override {
robertphillips2238c9d2016-03-30 13:34:16 -070027 const SkRect rect = SkRect::Make(SkIRect::MakeWH(400, 400));
28
Michael Ludwig23003182019-08-05 11:25:23 -040029 // Set up the filters once, we're not interested in measuring allocation time here
30 sk_sp<SkImageFilter> blur(SkImageFilters::Blur(20.0f, 20.0f, nullptr));
31 sk_sp<SkImageFilter> inputs[kNumInputs];
32 for (int i = 0; i < kNumInputs; ++i) {
33 inputs[i] = blur;
34 }
35 SkPaint paint;
36 paint.setImageFilter(SkImageFilters::Merge(inputs, kNumInputs));
37
38 // Only measure the filter computations done in drawRect()
39 // TODO (michaelludwig) - This benchmark, and the ones defined below, allocate their filters
40 // outside of the loop. This means that repeatedly drawing with the same filter will hit
41 // the global image filter cache inside the loop. Raster backend uses this cache so will see
42 // artificially improved performance. Ganesh will not because it uses a cache per filter
43 // call, so only within-DAG cache hits are measured (as desired). skbug:9297 wants to move
44 // raster backend to the same pattern, which will make the benchmark executions fair again.
mtkleinbb6a0282014-07-01 08:43:42 -070045 for (int j = 0; j < loops; j++) {
mtkleinbb6a0282014-07-01 08:43:42 -070046 canvas->drawRect(rect, paint);
senorblanco@chromium.org0d643562014-04-10 16:16:13 +000047 }
senorblanco@chromium.org0d643562014-04-10 16:16:13 +000048 }
49
50private:
robertphillips2238c9d2016-03-30 13:34:16 -070051 static const int kNumInputs = 5;
52
tfarinaf168b862014-06-19 12:32:29 -070053 typedef Benchmark INHERITED;
senorblanco@chromium.org0d643562014-04-10 16:16:13 +000054};
55
brianosman04a44d02016-09-21 09:46:57 -070056class ImageMakeWithFilterDAGBench : public Benchmark {
57public:
58 ImageMakeWithFilterDAGBench() {}
59
60protected:
61 const char* onGetName() override {
62 return "image_make_with_filter_dag";
63 }
64
65 void onDelayedSetup() override {
Hal Canaryc465d132017-12-08 10:21:31 -050066 fImage = GetResourceAsImage("images/mandrill_512.png");
brianosman04a44d02016-09-21 09:46:57 -070067 }
68
69 void onDraw(int loops, SkCanvas* canvas) override {
70 SkIRect subset = SkIRect::MakeSize(fImage->dimensions());
71 SkIPoint offset = SkIPoint::Make(0, 0);
72 SkIRect discardSubset;
Michael Ludwig23003182019-08-05 11:25:23 -040073 // makeWithFilter will only use the GPU backend if the image is already a texture
Brian Osmand566e2e2019-08-14 13:19:04 -040074 sk_sp<SkImage> image = fImage->makeTextureImage(canvas->getGrContext());
Michael Ludwig23003182019-08-05 11:25:23 -040075 if (!image) {
76 image = fImage;
77 }
brianosman04a44d02016-09-21 09:46:57 -070078
Michael Ludwig23003182019-08-05 11:25:23 -040079 // Set up the filters once so the allocation cost isn't included per-loop
80 sk_sp<SkImageFilter> blur(SkImageFilters::Blur(20.0f, 20.0f, nullptr));
81 sk_sp<SkImageFilter> inputs[kNumInputs];
82 for (int i = 0; i < kNumInputs; ++i) {
83 inputs[i] = blur;
84 }
85 sk_sp<SkImageFilter> mergeFilter = SkImageFilters::Merge(inputs, kNumInputs);
86
87 // But measure makeWithFilter() per loop since that's the focus of this benchmark
brianosman04a44d02016-09-21 09:46:57 -070088 for (int j = 0; j < loops; j++) {
brianosman04a44d02016-09-21 09:46:57 -070089 image = image->makeWithFilter(mergeFilter.get(), subset, subset, &discardSubset,
90 &offset);
91 SkASSERT(image && image->dimensions() == fImage->dimensions());
92 }
93 }
94
95private:
96 static const int kNumInputs = 5;
97 sk_sp<SkImage> fImage;
98
99 typedef Benchmark INHERITED;
100};
101
senorblanco7b87ee72015-10-26 06:55:47 -0700102// Exercise a blur filter connected to both inputs of an SkDisplacementMapEffect.
103
104class ImageFilterDisplacedBlur : public Benchmark {
105public:
106 ImageFilterDisplacedBlur() {}
107
108protected:
109 const char* onGetName() override {
110 return "image_filter_displaced_blur";
111 }
112
113 void onDraw(int loops, SkCanvas* canvas) override {
Michael Ludwig23003182019-08-05 11:25:23 -0400114 // Setup filter once
115 sk_sp<SkImageFilter> blur(SkImageFilters::Blur(4.0f, 4.0f, nullptr));
116 SkScalar scale = 2;
117
118 SkPaint paint;
119 paint.setImageFilter(SkImageFilters::DisplacementMap(SkColorChannel::kR, SkColorChannel::kR,
120 scale, blur, blur));
121
122 SkRect rect = SkRect::Make(SkIRect::MakeWH(400, 400));
123
124 // As before, measure just the filter computation time inside the loops
senorblanco7b87ee72015-10-26 06:55:47 -0700125 for (int j = 0; j < loops; j++) {
senorblanco7b87ee72015-10-26 06:55:47 -0700126 canvas->drawRect(rect, paint);
127 }
128 }
129
130private:
131 typedef Benchmark INHERITED;
132};
133
Xianzhu Wang0bff4182017-09-11 09:12:56 -0700134// Exercise an Xfermode kSrcIn filter compositing two inputs which have a small intersection.
135class ImageFilterXfermodeIn : public Benchmark {
136public:
137 ImageFilterXfermodeIn() {}
138
139protected:
140 const char* onGetName() override { return "image_filter_xfermode_in"; }
141
142 void onDraw(int loops, SkCanvas* canvas) override {
Michael Ludwig23003182019-08-05 11:25:23 -0400143 // Allocate filters once to avoid measuring instantiation time
144 auto blur = SkImageFilters::Blur(20.0f, 20.0f, nullptr);
145 auto offset1 = SkImageFilters::Offset(100.0f, 100.0f, blur);
146 auto offset2 = SkImageFilters::Offset(-100.0f, -100.0f, blur);
147 auto xfermode =
148 SkImageFilters::Xfermode(SkBlendMode::kSrcIn, offset1, offset2, nullptr);
Xianzhu Wang0bff4182017-09-11 09:12:56 -0700149
Michael Ludwig23003182019-08-05 11:25:23 -0400150 SkPaint paint;
151 paint.setImageFilter(xfermode);
152
153 // Measure only the filter time
154 for (int j = 0; j < loops; j++) {
Xianzhu Wang0bff4182017-09-11 09:12:56 -0700155 canvas->drawRect(SkRect::MakeWH(200.0f, 200.0f), paint);
156 }
157 }
158
159private:
160 typedef Benchmark INHERITED;
161};
162
senorblanco@chromium.org0d643562014-04-10 16:16:13 +0000163DEF_BENCH(return new ImageFilterDAGBench;)
brianosman04a44d02016-09-21 09:46:57 -0700164DEF_BENCH(return new ImageMakeWithFilterDAGBench;)
senorblanco7b87ee72015-10-26 06:55:47 -0700165DEF_BENCH(return new ImageFilterDisplacedBlur;)
Xianzhu Wang0bff4182017-09-11 09:12:56 -0700166DEF_BENCH(return new ImageFilterXfermodeIn;)