2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
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"
19 // Just need an interesting filter, nothing to special about colormatrix
20 static sk_sp<SkColorFilter> make_grayscale() {
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;
27 return SkColorFilters::Matrix(matrix);
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)
35 class FilteredRectBench : public Benchmark {
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);
50 const char* onGetName() override {
54 void onDelayedSetup() override {
58 case kColorFilter_Type:
59 fPaint.setColorFilter(make_grayscale());
61 case kImageFilter_Type:
62 fPaint.setImageFilter(SkImageFilters::ColorFilter(make_grayscale(), nullptr));
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);
79 using INHERITED = Benchmark;
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); )
88 class ColorFilterBench final : public Benchmark {
90 using Factory = sk_sp<SkColorFilter>(*)();
92 explicit ColorFilterBench(const char* suffix, Factory f)
94 , fName(SkStringPrintf("colorfilter_%s", suffix)) {}
97 const char* onGetName() override {
101 SkIPoint onGetSize() override {
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);
110 fImage = surface->makeImageSnapshot();
111 fColorFilter = fFactory();
114 void onDraw(int loops, SkCanvas* canvas) override {
116 p.setColorFilter(fColorFilter);
118 for (int i = 0; i < loops; ++i) {
119 canvas->drawImage(fImage, 0, 0, SkSamplingOptions(), &p);
123 const Factory fFactory;
124 const SkString fName;
126 sk_sp<SkImage> fImage;
127 sk_sp<SkColorFilter> fColorFilter;
130 const char RuntimeNone_GPU_SRC[] = R"(
131 half4 main(half4 inColor) { return inColor; }
134 const char RuntimeColorMatrix_GPU_SRC[] = R"(
135 // WTB matrix/vector inputs.
136 uniform half m0 , m1 , m2 , m3 , m4 ,
137 m5 , m6 , m7 , m8 , m9 ,
138 m10, m11, m12, m13, m14,
139 m15, m16, m17, m18, m19;
140 half4 main(half4 inColor) {
141 half4 c = unpremul(inColor);
143 half4x4 m = half4x4(m0, m5, m10, m15,
147 c = m * c + half4 (m4, m9, m14, m19);
155 static constexpr float gColorMatrix[] = {
156 0.3f, 0.3f, 0.0f, 0.0f, 0.3f,
157 0.0f, 0.3f, 0.3f, 0.0f, 0.3f,
158 0.0f, 0.0f, 0.3f, 0.3f, 0.3f,
159 0.3f, 0.0f, 0.3f, 0.3f, 0.0f,
164 DEF_BENCH( return new ColorFilterBench("none",
165 []() { return sk_sp<SkColorFilter>(nullptr); }); )
166 DEF_BENCH( return new ColorFilterBench("blend_src",
167 []() { return SkColorFilters::Blend(0x80808080, SkBlendMode::kSrc); }); )
168 DEF_BENCH( return new ColorFilterBench("blend_srcover",
169 []() { return SkColorFilters::Blend(0x80808080, SkBlendMode::kSrcOver); }); )
170 DEF_BENCH( return new ColorFilterBench("linear_to_srgb",
171 []() { return SkColorFilters::LinearToSRGBGamma(); }); )
172 DEF_BENCH( return new ColorFilterBench("srgb_to_linear",
173 []() { return SkColorFilters::SRGBToLinearGamma(); }); )
174 DEF_BENCH( return new ColorFilterBench("matrix_rgba",
175 []() { return SkColorFilters::Matrix(gColorMatrix); }); )
176 DEF_BENCH( return new ColorFilterBench("matrix_hsla",
177 []() { return SkColorFilters::HSLAMatrix(gColorMatrix); }); )
178 DEF_BENCH( return new ColorFilterBench("compose_src",
179 []() { return SkColorFilters::Compose(SkColorFilters::Blend(0x80808080, SkBlendMode::kSrc),
180 SkColorFilters::Blend(0x80808080, SkBlendMode::kSrc));
182 DEF_BENCH( return new ColorFilterBench("lerp_src",
183 []() { return SkColorFilters::Lerp(0.3f,
184 SkColorFilters::Blend(0x80808080, SkBlendMode::kSrc),
185 SkColorFilters::Blend(0x80808080, SkBlendMode::kSrc));
188 DEF_BENCH( return new ColorFilterBench("highcontrast", []() {
189 return SkHighContrastFilter::Make({
190 false, SkHighContrastConfig::InvertStyle::kInvertLightness, 0.2f
193 DEF_BENCH( return new ColorFilterBench("overdraw", []() {
194 const SkColor colors[SkOverdrawColorFilter::kNumColors] = {
195 0x80FF0000, 0x8000FF00, 0x800000FF, 0x80FFFF00, 0x8000FFFF, 0x80FF00FF,
197 return SkOverdrawColorFilter::MakeWithSkColors(colors);
199 DEF_BENCH( return new ColorFilterBench("gaussian", []() {
200 return SkColorFilterPriv::MakeGaussian();
204 DEF_BENCH( return new ColorFilterBench("src_runtime", []() {
205 static sk_sp<SkRuntimeEffect> gEffect =
206 SkRuntimeEffect::MakeForColorFilter(SkString(RuntimeNone_GPU_SRC)).effect;
207 return gEffect->makeColorFilter(SkData::MakeEmpty());
209 DEF_BENCH( return new ColorFilterBench("matrix_runtime", []() {
210 static sk_sp<SkRuntimeEffect> gEffect =
211 SkRuntimeEffect::MakeForColorFilter(SkString(RuntimeColorMatrix_GPU_SRC)).effect;
212 return gEffect->makeColorFilter(SkData::MakeWithCopy(gColorMatrix, sizeof(gColorMatrix)));
216 class FilterColorBench final : public Benchmark {
218 explicit FilterColorBench() {}
220 bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
223 const char* onGetName() override { return "matrix_filterColor4f"; }
225 void onDelayedSetup() override {
226 SkScalar colorMatrix[20] = {
227 0.9f, 0.9f, 0.9f, 0.9f, 0.9f,
228 0.9f, 0.9f, 0.9f, 0.9f, 0.9f,
229 0.9f, 0.9f, 0.9f, 0.9f, 0.9f,
230 0.9f, 0.9f, 0.9f, 0.9f, 0.9f
232 fColorFilter = SkColorFilters::Matrix(colorMatrix);
235 void onDraw(int loops, SkCanvas*) override {
236 SkColor4f c = { 1.f, 1.f, 0.f, 1.0f };
238 for (int i = 0; i < loops; ++i) {
239 c = fColorFilter->filterColor4f(c, /*srcCS=*/nullptr, /*dstCS=*/nullptr);
243 sk_sp<SkColorFilter> fColorFilter;
246 DEF_BENCH( return new FilterColorBench(); )