blob: 365ca6f8aac109a7810108967a8b87c95bb5f50b [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 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 */
reed6c225732014-06-09 19:52:07 -07007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "bench/Benchmark.h"
9#include "include/core/SkBitmap.h"
10#include "include/core/SkCanvas.h"
11#include "include/core/SkColorPriv.h"
12#include "include/core/SkPaint.h"
13#include "include/core/SkString.h"
14#include "include/utils/SkRandom.h"
15#include "tools/ToolUtils.h"
reed@android.comf523e252009-01-26 23:15:37 +000016
reed@android.comf523e252009-01-26 23:15:37 +000017/* Variants for bitmaps
rmistry@google.comfbfcd562012-08-23 18:09:54 +000018
reed@android.comf523e252009-01-26 23:15:37 +000019 - src depth (32 w+w/o alpha), 565, 4444, index, a8
20 - paint options: filtering, dither, alpha
21 - matrix options: translate, scale, rotate, persp
22 - tiling: none, repeat, mirror, clamp
rmistry@google.comfbfcd562012-08-23 18:09:54 +000023
reed@android.comf523e252009-01-26 23:15:37 +000024 */
25
tfarinaf168b862014-06-19 12:32:29 -070026class BitmapBench : public Benchmark {
reed6c225732014-06-09 19:52:07 -070027 const SkColorType fColorType;
28 const SkAlphaType fAlphaType;
29 const bool fForceUpdate; //bitmap marked as dirty before each draw. forces bitmap to be updated on device cache
30 const bool fIsVolatile;
mtklein14e4d392014-10-23 14:35:01 -070031 const bool fDoScale;
reed6c225732014-06-09 19:52:07 -070032
33 SkBitmap fBitmap;
34 SkPaint fPaint;
35 SkString fName;
36
djsollen@google.comc2532dd2013-04-09 18:06:06 +000037 enum { W = 128 };
38 enum { H = 128 };
reed@android.comf523e252009-01-26 23:15:37 +000039public:
mtklein14e4d392014-10-23 14:35:01 -070040 BitmapBench(SkColorType ct, SkAlphaType at, bool forceUpdate, bool isVolatile, bool doScale)
reed6c225732014-06-09 19:52:07 -070041 : fColorType(ct)
42 , fAlphaType(at)
djsollen@google.comc2532dd2013-04-09 18:06:06 +000043 , fForceUpdate(forceUpdate)
reed6c225732014-06-09 19:52:07 -070044 , fIsVolatile(isVolatile)
mtklein14e4d392014-10-23 14:35:01 -070045 , fDoScale(doScale)
reed6c225732014-06-09 19:52:07 -070046 {}
reed@android.comf523e252009-01-26 23:15:37 +000047
48protected:
mtkleinf0599002015-07-13 06:18:39 -070049 const char* onGetName() override {
reed@android.comf523e252009-01-26 23:15:37 +000050 fName.set("bitmap");
Mike Kleinea3f0142019-03-20 11:12:10 -050051 fName.appendf("_%s%s",
52 ToolUtils::colortype_name(fColorType),
reed6c225732014-06-09 19:52:07 -070053 kOpaque_SkAlphaType == fAlphaType ? "" : "_A");
mtklein14e4d392014-10-23 14:35:01 -070054 if (fDoScale) {
55 fName.append("_scale");
56 }
57 if (fForceUpdate) {
junov@google.com4ee7ae52011-06-30 17:30:49 +000058 fName.append("_update");
mtklein14e4d392014-10-23 14:35:01 -070059 }
60 if (fIsVolatile) {
junov@google.com4ee7ae52011-06-30 17:30:49 +000061 fName.append("_volatile");
mtklein14e4d392014-10-23 14:35:01 -070062 }
junov@google.com4ee7ae52011-06-30 17:30:49 +000063
reed@android.comf523e252009-01-26 23:15:37 +000064 return fName.c_str();
65 }
66
joshualitt8a6697a2015-09-30 12:11:07 -070067 void onDelayedSetup() override {
djsollen@google.comc2532dd2013-04-09 18:06:06 +000068 SkBitmap bm;
69
Mike Reeda920d362017-07-03 13:36:17 -040070 bm.allocPixels(SkImageInfo::Make(W, H, fColorType, fAlphaType));
reed6c225732014-06-09 19:52:07 -070071 bm.eraseColor(kOpaque_SkAlphaType == fAlphaType ? SK_ColorBLACK : 0);
djsollen@google.comc2532dd2013-04-09 18:06:06 +000072
mtkleinf0599002015-07-13 06:18:39 -070073 this->onDrawIntoBitmap(bm);
djsollen@google.comc2532dd2013-04-09 18:06:06 +000074
Mike Reeda920d362017-07-03 13:36:17 -040075 fBitmap = bm;
djsollen@google.comc2532dd2013-04-09 18:06:06 +000076 fBitmap.setIsVolatile(fIsVolatile);
77 }
78
mtkleina1ebeb22015-10-01 09:43:39 -070079 void onDraw(int loops, SkCanvas* canvas) override {
mtklein14e4d392014-10-23 14:35:01 -070080 if (fDoScale) {
81 canvas->scale(.99f, .99f);
82 }
reed@android.comf523e252009-01-26 23:15:37 +000083 SkIPoint dim = this->getSize();
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000084 SkRandom rand;
reed@android.comf523e252009-01-26 23:15:37 +000085
86 SkPaint paint(fPaint);
87 this->setupPaint(&paint);
88
89 const SkBitmap& bitmap = fBitmap;
90 const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2);
91 const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000092
commit-bot@chromium.org33614712013-12-03 18:17:16 +000093 for (int i = 0; i < loops; i++) {
reed@android.comf523e252009-01-26 23:15:37 +000094 SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
95 SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
junov@google.com4ee7ae52011-06-30 17:30:49 +000096
97 if (fForceUpdate)
98 bitmap.notifyPixelsChanged();
99
reed@android.comf523e252009-01-26 23:15:37 +0000100 canvas->drawBitmap(bitmap, x, y, &paint);
101 }
102 }
103
mtkleinf0599002015-07-13 06:18:39 -0700104 virtual void onDrawIntoBitmap(const SkBitmap& bm) {
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000105 const int w = bm.width();
106 const int h = bm.height();
107
108 SkCanvas canvas(bm);
109 SkPaint p;
110 p.setAntiAlias(true);
111 p.setColor(SK_ColorRED);
112 canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2,
113 SkIntToScalar(SkMin32(w, h))*3/8, p);
114
115 SkRect r;
116 r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
117 p.setStyle(SkPaint::kStroke_Style);
118 p.setStrokeWidth(SkIntToScalar(4));
119 p.setColor(SK_ColorBLUE);
120 canvas.drawRect(r, p);
121 }
122
reed@android.comf523e252009-01-26 23:15:37 +0000123private:
tfarinaf168b862014-06-19 12:32:29 -0700124 typedef Benchmark INHERITED;
reed@android.comf523e252009-01-26 23:15:37 +0000125};
126
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000127/** Explicitly invoke some filter types to improve coverage of acceleration
128 procs. */
129
reed@google.comef77ec22013-05-29 15:39:54 +0000130enum Flags {
131 kScale_Flag = 1 << 0,
132 kRotate_Flag = 1 << 1,
133 kBilerp_Flag = 1 << 2,
134 kBicubic_Flag = 1 << 3,
135};
136
137static bool isBilerp(uint32_t flags) {
138 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag);
139}
140
141static bool isBicubic(uint32_t flags) {
142 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag | kBicubic_Flag);
143}
144
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000145class FilterBitmapBench : public BitmapBench {
reed@google.comef77ec22013-05-29 15:39:54 +0000146 uint32_t fFlags;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000147 SkString fFullName;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000148public:
reed6c225732014-06-09 19:52:07 -0700149 FilterBitmapBench(SkColorType ct, SkAlphaType at,
reed@google.comef77ec22013-05-29 15:39:54 +0000150 bool forceUpdate, bool isVolitile, uint32_t flags)
mtklein14e4d392014-10-23 14:35:01 -0700151 : INHERITED(ct, at, forceUpdate, isVolitile, false)
reed@google.comef77ec22013-05-29 15:39:54 +0000152 , fFlags(flags) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000153 }
154
155protected:
mtkleinf0599002015-07-13 06:18:39 -0700156 const char* onGetName() override {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000157 fFullName.set(INHERITED::onGetName());
reed@google.comef77ec22013-05-29 15:39:54 +0000158 if (fFlags & kScale_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000159 fFullName.append("_scale");
reed@google.comef77ec22013-05-29 15:39:54 +0000160 }
161 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000162 fFullName.append("_rotate");
reed@google.comef77ec22013-05-29 15:39:54 +0000163 }
164 if (isBilerp(fFlags)) {
165 fFullName.append("_bilerp");
166 } else if (isBicubic(fFlags)) {
167 fFullName.append("_bicubic");
168 }
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000169
170 return fFullName.c_str();
171 }
172
mtkleina1ebeb22015-10-01 09:43:39 -0700173 void onDraw(int loops, SkCanvas* canvas) override {
Mike Reed3661bc92017-02-22 13:21:42 -0500174 SkISize dim = canvas->getBaseLayerSize();
reed@google.comef77ec22013-05-29 15:39:54 +0000175 if (fFlags & kScale_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000176 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
177 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000178
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000179 canvas->translate(x, y);
180 // just enough so we can't take the sprite case
Mike Reed76c6ff02019-07-31 16:33:55 -0400181 canvas->scale(1.1f, 1.1f);
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000182 canvas->translate(-x, -y);
183 }
reed@google.comef77ec22013-05-29 15:39:54 +0000184 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000185 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
186 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
bungeman7438bfc2016-07-12 15:01:19 -0700187 canvas->rotate(SkIntToScalar(35), x, y);
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000188 }
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000189 INHERITED::onDraw(loops, canvas);
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000190 }
191
mtklein36352bf2015-03-25 18:17:31 -0700192 void setupPaint(SkPaint* paint) override {
reed@google.com9cfc83c2013-07-22 17:18:18 +0000193 this->INHERITED::setupPaint(paint);
194
195 int index = 0;
196 if (fFlags & kBilerp_Flag) {
197 index |= 1;
198 }
199 if (fFlags & kBicubic_Flag) {
200 index |= 2;
201 }
reed93a12152015-03-16 10:08:34 -0700202 static const SkFilterQuality gQualitys[] = {
203 kNone_SkFilterQuality,
204 kLow_SkFilterQuality,
205 kMedium_SkFilterQuality,
206 kHigh_SkFilterQuality
reed@google.com9cfc83c2013-07-22 17:18:18 +0000207 };
reed93a12152015-03-16 10:08:34 -0700208 paint->setFilterQuality(gQualitys[index]);
reed@google.com9cfc83c2013-07-22 17:18:18 +0000209}
210
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000211private:
212 typedef BitmapBench INHERITED;
213};
214
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000215/** Verify optimizations that test source alpha values. */
216
217class SourceAlphaBitmapBench : public BitmapBench {
218public:
219 enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha,
220 kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha};
221private:
222 SkString fFullName;
223 SourceAlpha fSourceAlpha;
224public:
reed6c225732014-06-09 19:52:07 -0700225 SourceAlphaBitmapBench(SourceAlpha alpha, SkColorType ct,
reed@google.comef77ec22013-05-29 15:39:54 +0000226 bool forceUpdate = false, bool bitmapVolatile = false)
mtklein14e4d392014-10-23 14:35:01 -0700227 : INHERITED(ct, kPremul_SkAlphaType, forceUpdate, bitmapVolatile, false)
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000228 , fSourceAlpha(alpha) {
229 }
230
231protected:
mtkleinf0599002015-07-13 06:18:39 -0700232 const char* onGetName() override {
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000233 fFullName.set(INHERITED::onGetName());
234
235 if (fSourceAlpha == kOpaque_SourceAlpha) {
236 fFullName.append("_source_opaque");
237 } else if (fSourceAlpha == kTransparent_SourceAlpha) {
238 fFullName.append("_source_transparent");
239 } else if (fSourceAlpha == kTwoStripes_SourceAlpha) {
240 fFullName.append("_source_stripes_two");
241 } else if (fSourceAlpha == kThreeStripes_SourceAlpha) {
242 fFullName.append("_source_stripes_three");
243 }
244
245 return fFullName.c_str();
246 }
247
mtklein36352bf2015-03-25 18:17:31 -0700248 void onDrawIntoBitmap(const SkBitmap& bm) override {
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000249 const int w = bm.width();
250 const int h = bm.height();
251
252 if (kOpaque_SourceAlpha == fSourceAlpha) {
253 bm.eraseColor(SK_ColorBLACK);
254 } else if (kTransparent_SourceAlpha == fSourceAlpha) {
255 bm.eraseColor(0);
256 } else if (kTwoStripes_SourceAlpha == fSourceAlpha) {
257 bm.eraseColor(0);
258
259 SkCanvas canvas(bm);
260 SkPaint p;
261 p.setAntiAlias(false);
262 p.setStyle(SkPaint::kFill_Style);
263 p.setColor(SK_ColorRED);
264
265 // Draw red vertical stripes on transparent background
266 SkRect r;
267 for (int x = 0; x < w; x+=2)
268 {
269 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
270 canvas.drawRect(r, p);
271 }
272
273 } else if (kThreeStripes_SourceAlpha == fSourceAlpha) {
274 bm.eraseColor(0);
275
276 SkCanvas canvas(bm);
277 SkPaint p;
278 p.setAntiAlias(false);
279 p.setStyle(SkPaint::kFill_Style);
280
281 // Draw vertical stripes on transparent background with a pattern
282 // where the first pixel is fully transparent, the next is semi-transparent
283 // and the third is fully opaque.
284 SkRect r;
285 for (int x = 0; x < w; x++)
286 {
287 if (x % 3 == 0) {
288 continue; // Keep transparent
289 } else if (x % 3 == 1) {
290 p.setColor(SkColorSetARGB(127, 127, 127, 127)); // Semi-transparent
291 } else if (x % 3 == 2) {
292 p.setColor(SK_ColorRED); // Opaque
293 }
294 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
295 canvas.drawRect(r, p);
296 }
297 }
298 }
299
300private:
301 typedef BitmapBench INHERITED;
302};
reed@google.com2ece2872013-05-28 20:48:14 +0000303
mtklein14e4d392014-10-23 14:35:01 -0700304DEF_BENCH( return new BitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, false); )
305DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, false); )
306DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, true); )
307DEF_BENCH( return new BitmapBench(kRGB_565_SkColorType, kOpaque_SkAlphaType, false, false, false); )
mtklein14e4d392014-10-23 14:35:01 -0700308DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, false); )
309DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, false); )
reed@android.comf523e252009-01-26 23:15:37 +0000310
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000311// scale filter -> S32_opaque_D32_filter_DX_{SSE2,SSSE3} and Fact9 is also for S32_D16_filter_DX_SSE2
reed6c225732014-06-09 19:52:07 -0700312DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
313DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
314DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kBilerp_Flag); )
315DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kBilerp_Flag); )
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000316
Yuqian Li24e963d2017-12-06 11:30:58 -0500317// The following two cases test the performance regression of b/70172912 .
318DEF_BENCH( return new FilterBitmapBench(kRGB_565_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
319DEF_BENCH( return new BitmapBench(kRGB_565_SkColorType, kOpaque_SkAlphaType, false, false, true); )
320
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000321// scale rotate filter -> S32_opaque_D32_filter_DXDY_{SSE2,SSSE3}
reed6c225732014-06-09 19:52:07 -0700322DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
323DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
324DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
325DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
reed@google.comef77ec22013-05-29 15:39:54 +0000326
reed6c225732014-06-09 19:52:07 -0700327DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag | kBicubic_Flag); )
328DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag | kBicubic_Flag); )
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000329
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000330// source alpha tests -> S32A_Opaque_BlitRow32_{arm,neon}
reed6c225732014-06-09 19:52:07 -0700331DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kOpaque_SourceAlpha, kN32_SkColorType); )
332DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTransparent_SourceAlpha, kN32_SkColorType); )
333DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTwoStripes_SourceAlpha, kN32_SkColorType); )
334DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kThreeStripes_SourceAlpha, kN32_SkColorType); )