1 /*
2 * Copyright 2013 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/SkColorFilter.h"
11 #include "include/core/SkSurface.h"
12 #include "include/effects/SkHighContrastFilter.h"
13 #include "include/effects/SkImageFilters.h"
14 #include "include/effects/SkOverdrawColorFilter.h"
15 #include "include/effects/SkRuntimeEffect.h"
16 #include "src/core/SkColorFilterPriv.h"
17 #include "tools/Resources.h"
18
19 // Just need an interesting filter, nothing to special about colormatrix
make_grayscale()20 static sk_sp<SkColorFilter> make_grayscale() {
21 float matrix[20];
22 memset(matrix, 0, 20 * sizeof(float));
23 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
24 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
25 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
26 matrix[18] = 1.0f;
27 return SkColorFilters::Matrix(matrix);
28 }
29
30 /**
31 * Different ways to draw the same thing (a red rect)
32 * All of their timings should be about the same
33 * (we allow for slight overhead to figure out that we can undo the presence of the filters)
34 */
35 class FilteredRectBench : public Benchmark {
36 public:
37 enum Type {
38 kNoFilter_Type,
39 kColorFilter_Type,
40 kImageFilter_Type,
41 };
42
FilteredRectBench(Type t)43 FilteredRectBench(Type t) : fType(t) {
44 static const char* suffix[] = { "nofilter", "colorfilter", "imagefilter" };
45 fName.printf("filteredrect_%s", suffix[t]);
46 fPaint.setColor(SK_ColorRED);
47 }
48
49 protected:
onGetName()50 const char* onGetName() override {
51 return fName.c_str();
52 }
53
onDelayedSetup()54 void onDelayedSetup() override {
55 switch (fType) {
56 case kNoFilter_Type:
57 break;
58 case kColorFilter_Type:
59 fPaint.setColorFilter(make_grayscale());
60 break;
61 case kImageFilter_Type:
62 fPaint.setImageFilter(SkImageFilters::ColorFilter(make_grayscale(), nullptr));
63 break;
64 }
65 }
66
onDraw(int loops,SkCanvas * canvas)67 void onDraw(int loops, SkCanvas* canvas) override {
68 const SkRect r = { 0, 0, 256, 256 };
69 for (int i = 0; i < loops; ++i) {
70 canvas->drawRect(r, fPaint);
71 }
72 }
73
74 private:
75 SkPaint fPaint;
76 SkString fName;
77 Type fType;
78
79 typedef Benchmark INHERITED;
80 };
81
82 DEF_BENCH( return new FilteredRectBench(FilteredRectBench::kNoFilter_Type); )
83 DEF_BENCH( return new FilteredRectBench(FilteredRectBench::kColorFilter_Type); )
84 DEF_BENCH( return new FilteredRectBench(FilteredRectBench::kImageFilter_Type); )
85
86 namespace {
87
88 class ColorFilterBench final : public Benchmark {
89 public:
90 using Factory = sk_sp<SkColorFilter>(*)();
91
ColorFilterBench(const char * suffix,Factory f)92 explicit ColorFilterBench(const char* suffix, Factory f)
93 : fFactory(f)
94 , fName(SkStringPrintf("colorfilter_%s", suffix)) {}
95
96 private:
onGetName()97 const char* onGetName() override {
98 return fName.c_str();
99 }
100
onGetSize()101 SkIPoint onGetSize() override {
102 return { 256, 256 };
103 }
104
onDelayedSetup()105 void onDelayedSetup() override {
106 // Pass the image though a premul canvas so that we "forget" it is opaque.
107 auto surface = SkSurface::MakeRasterN32Premul(256, 256);
108 surface->getCanvas()->drawImage(GetResourceAsImage("images/mandrill_256.png"), 0, 0);
109
110 fImage = surface->makeImageSnapshot();
111 fColorFilter = fFactory();
112 }
113
onDraw(int loops,SkCanvas * canvas)114 void onDraw(int loops, SkCanvas* canvas) override {
115 SkPaint p;
116 p.setColorFilter(fColorFilter);
117
118 for (int i = 0; i < loops; ++i) {
119 canvas->drawImage(fImage, 0, 0, &p);
120 }
121 }
122
123 const Factory fFactory;
124 const SkString fName;
125
126 sk_sp<SkImage> fImage;
127 sk_sp<SkColorFilter> fColorFilter;
128 };
129
130 const char RuntimeNone_GPU_SRC[] = R"(
131 void main(inout half4 c) {}
132 )";
133
134 // TODO: Use intrinsic max/saturate when those are implemented by the interpreter
135 const char RuntimeColorMatrix_GPU_SRC[] = R"(
136 // WTB matrix/vector inputs.
137 uniform half m0 , m1 , m2 , m3 , m4 ,
138 m5 , m6 , m7 , m8 , m9 ,
139 m10, m11, m12, m13, m14,
140 m15, m16, m17, m18, m19;
141 void main(inout half4 c) {
142 half nonZeroAlpha = c.a < 0.0001 ? 0.0001 : c.a;
143 c = half4(c.rgb / nonZeroAlpha, nonZeroAlpha);
144
145 half4x4 m = half4x4(m0, m5, m10, m15,
146 m1, m6, m11, m16,
147 m2, m7, m12, m17,
148 m3, m8, m13, m18);
149 c = m * c + half4 (m4, m9, m14, m19);
150
151 // c = saturate(c);
152 c.rgb *= c.a;
153 }
154 )";
155
156 static constexpr float gColorMatrix[] = {
157 0.3f, 0.3f, 0.0f, 0.0f, 0.3f,
158 0.0f, 0.3f, 0.3f, 0.0f, 0.3f,
159 0.0f, 0.0f, 0.3f, 0.3f, 0.3f,
160 0.3f, 0.0f, 0.3f, 0.3f, 0.0f,
161 };
162
163 } // namespace
164
165 DEF_BENCH( return new ColorFilterBench("none",
__anonddf019d50202() 166 []() { return sk_sp<SkColorFilter>(nullptr); }); )
167 DEF_BENCH( return new ColorFilterBench("blend_src",
__anonddf019d50302() 168 []() { return SkColorFilters::Blend(0x80808080, SkBlendMode::kSrc); }); )
169 DEF_BENCH( return new ColorFilterBench("blend_srcover",
__anonddf019d50402() 170 []() { return SkColorFilters::Blend(0x80808080, SkBlendMode::kSrcOver); }); )
171 DEF_BENCH( return new ColorFilterBench("linear_to_srgb",
__anonddf019d50502() 172 []() { return SkColorFilters::LinearToSRGBGamma(); }); )
173 DEF_BENCH( return new ColorFilterBench("srgb_to_linear",
__anonddf019d50602() 174 []() { return SkColorFilters::SRGBToLinearGamma(); }); )
175 DEF_BENCH( return new ColorFilterBench("matrix_rgba",
__anonddf019d50702() 176 []() { return SkColorFilters::Matrix(gColorMatrix); }); )
177 DEF_BENCH( return new ColorFilterBench("matrix_hsla",
__anonddf019d50802() 178 []() { return SkColorFilters::HSLAMatrix(gColorMatrix); }); )
179 DEF_BENCH( return new ColorFilterBench("compose_src",
__anonddf019d50902() 180 []() { return SkColorFilters::Compose(SkColorFilters::Blend(0x80808080, SkBlendMode::kSrc),
181 SkColorFilters::Blend(0x80808080, SkBlendMode::kSrc));
182 }); )
183 DEF_BENCH( return new ColorFilterBench("lerp_src",
__anonddf019d50a02() 184 []() { return SkColorFilters::Lerp(0.3f,
185 SkColorFilters::Blend(0x80808080, SkBlendMode::kSrc),
186 SkColorFilters::Blend(0x80808080, SkBlendMode::kSrc));
187 }); )
188
__anonddf019d50b02() 189 DEF_BENCH( return new ColorFilterBench("highcontrast", []() {
190 return SkHighContrastFilter::Make({
191 false, SkHighContrastConfig::InvertStyle::kInvertLightness, 0.2f
192 });
193 }); )
__anonddf019d50c02() 194 DEF_BENCH( return new ColorFilterBench("overdraw", []() {
195 const SkColor colors[SkOverdrawColorFilter::kNumColors] = {
196 0x80FF0000, 0x8000FF00, 0x800000FF, 0x80FFFF00, 0x8000FFFF, 0x80FF00FF,
197 };
198 return SkOverdrawColorFilter::MakeWithSkColors(colors);
199 }); )
__anonddf019d50d02() 200 DEF_BENCH( return new ColorFilterBench("gaussian", []() {
201 return SkColorFilterPriv::MakeGaussian();
202 }); )
203
204 #ifdef SK_SUPPORT_GPU
__anonddf019d50e02() 205 DEF_BENCH( return new ColorFilterBench("src_runtime", []() {
206 static sk_sp<SkRuntimeEffect> gEffect = std::get<0>(
207 SkRuntimeEffect::Make(SkString(RuntimeNone_GPU_SRC)));
208 return gEffect->makeColorFilter(SkData::MakeEmpty());
209 });)
__anonddf019d50f02() 210 DEF_BENCH( return new ColorFilterBench("matrix_runtime", []() {
211 static sk_sp<SkRuntimeEffect> gEffect = std::get<0>(
212 SkRuntimeEffect::Make(SkString(RuntimeColorMatrix_GPU_SRC)));
213 return gEffect->makeColorFilter(SkData::MakeWithCopy(gColorMatrix, sizeof(gColorMatrix)));
214 });)
215 #endif
216