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