blob: 2fd480bb7ab0213875f7fb58e2e413f358218356 [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
tfarinaf168b862014-06-19 12:32:29 -07008#include "Benchmark.h"
reed@android.comf523e252009-01-26 23:15:37 +00009#include "SkBitmap.h"
reed@android.comf523e252009-01-26 23:15:37 +000010#include "SkCanvas.h"
11#include "SkColorPriv.h"
tfarinaf168b862014-06-19 12:32:29 -070012#include "SkPaint.h"
reed@android.comf523e252009-01-26 23:15:37 +000013#include "SkRandom.h"
14#include "SkString.h"
reed6c225732014-06-09 19:52:07 -070015#include "sk_tool_utils.h"
reed@android.comf523e252009-01-26 23:15:37 +000016
reed@android.comf523e252009-01-26 23:15:37 +000017static int conv6ToByte(int x) {
18 return x * 0xFF / 5;
19}
20
21static int convByteTo6(int x) {
22 return x * 5 / 255;
23}
24
25static uint8_t compute666Index(SkPMColor c) {
26 int r = SkGetPackedR32(c);
27 int g = SkGetPackedG32(c);
28 int b = SkGetPackedB32(c);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000029
reed@android.comf523e252009-01-26 23:15:37 +000030 return convByteTo6(r) * 36 + convByteTo6(g) * 6 + convByteTo6(b);
31}
32
reed6c225732014-06-09 19:52:07 -070033static void convertToIndex666(const SkBitmap& src, SkBitmap* dst, SkAlphaType aType) {
reed@google.com0a6151d2013-10-10 14:44:56 +000034 SkPMColor storage[216];
35 SkPMColor* colors = storage;
reed@android.comf523e252009-01-26 23:15:37 +000036 // rrr ggg bbb
37 for (int r = 0; r < 6; r++) {
38 int rr = conv6ToByte(r);
39 for (int g = 0; g < 6; g++) {
40 int gg = conv6ToByte(g);
41 for (int b = 0; b < 6; b++) {
42 int bb = conv6ToByte(b);
43 *colors++ = SkPreMultiplyARGB(0xFF, rr, gg, bb);
44 }
45 }
46 }
reed6c225732014-06-09 19:52:07 -070047 dst->allocPixels(SkImageInfo::Make(src.width(), src.height(), kIndex_8_SkColorType, aType),
Mike Reed6b3155c2017-04-03 14:41:44 -040048 SkColorTable::Make(storage, 216));
rmistry@google.comfbfcd562012-08-23 18:09:54 +000049
reed@android.comf523e252009-01-26 23:15:37 +000050 for (int y = 0; y < src.height(); y++) {
51 const SkPMColor* srcP = src.getAddr32(0, y);
52 uint8_t* dstP = dst->getAddr8(0, y);
53 for (int x = src.width() - 1; x >= 0; --x) {
54 *dstP++ = compute666Index(*srcP++);
55 }
56 }
57}
58
59/* Variants for bitmaps
rmistry@google.comfbfcd562012-08-23 18:09:54 +000060
reed@android.comf523e252009-01-26 23:15:37 +000061 - src depth (32 w+w/o alpha), 565, 4444, index, a8
62 - paint options: filtering, dither, alpha
63 - matrix options: translate, scale, rotate, persp
64 - tiling: none, repeat, mirror, clamp
rmistry@google.comfbfcd562012-08-23 18:09:54 +000065
reed@android.comf523e252009-01-26 23:15:37 +000066 */
67
tfarinaf168b862014-06-19 12:32:29 -070068class BitmapBench : public Benchmark {
reed6c225732014-06-09 19:52:07 -070069 const SkColorType fColorType;
70 const SkAlphaType fAlphaType;
71 const bool fForceUpdate; //bitmap marked as dirty before each draw. forces bitmap to be updated on device cache
72 const bool fIsVolatile;
mtklein14e4d392014-10-23 14:35:01 -070073 const bool fDoScale;
reed6c225732014-06-09 19:52:07 -070074
75 SkBitmap fBitmap;
76 SkPaint fPaint;
77 SkString fName;
78
djsollen@google.comc2532dd2013-04-09 18:06:06 +000079 enum { W = 128 };
80 enum { H = 128 };
reed@android.comf523e252009-01-26 23:15:37 +000081public:
mtklein14e4d392014-10-23 14:35:01 -070082 BitmapBench(SkColorType ct, SkAlphaType at, bool forceUpdate, bool isVolatile, bool doScale)
reed6c225732014-06-09 19:52:07 -070083 : fColorType(ct)
84 , fAlphaType(at)
djsollen@google.comc2532dd2013-04-09 18:06:06 +000085 , fForceUpdate(forceUpdate)
reed6c225732014-06-09 19:52:07 -070086 , fIsVolatile(isVolatile)
mtklein14e4d392014-10-23 14:35:01 -070087 , fDoScale(doScale)
reed6c225732014-06-09 19:52:07 -070088 {}
reed@android.comf523e252009-01-26 23:15:37 +000089
90protected:
mtkleinf0599002015-07-13 06:18:39 -070091 const char* onGetName() override {
reed@android.comf523e252009-01-26 23:15:37 +000092 fName.set("bitmap");
reed6c225732014-06-09 19:52:07 -070093 fName.appendf("_%s%s", sk_tool_utils::colortype_name(fColorType),
94 kOpaque_SkAlphaType == fAlphaType ? "" : "_A");
mtklein14e4d392014-10-23 14:35:01 -070095 if (fDoScale) {
96 fName.append("_scale");
97 }
98 if (fForceUpdate) {
junov@google.com4ee7ae52011-06-30 17:30:49 +000099 fName.append("_update");
mtklein14e4d392014-10-23 14:35:01 -0700100 }
101 if (fIsVolatile) {
junov@google.com4ee7ae52011-06-30 17:30:49 +0000102 fName.append("_volatile");
mtklein14e4d392014-10-23 14:35:01 -0700103 }
junov@google.com4ee7ae52011-06-30 17:30:49 +0000104
reed@android.comf523e252009-01-26 23:15:37 +0000105 return fName.c_str();
106 }
107
joshualitt8a6697a2015-09-30 12:11:07 -0700108 void onDelayedSetup() override {
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000109 SkBitmap bm;
110
reed6c225732014-06-09 19:52:07 -0700111 if (kIndex_8_SkColorType == fColorType) {
reedbae704b2014-06-28 14:26:35 -0700112 bm.allocPixels(SkImageInfo::MakeN32(W, H, fAlphaType));
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000113 } else {
reedbae704b2014-06-28 14:26:35 -0700114 bm.allocPixels(SkImageInfo::Make(W, H, fColorType, fAlphaType));
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000115 }
reed6c225732014-06-09 19:52:07 -0700116 bm.eraseColor(kOpaque_SkAlphaType == fAlphaType ? SK_ColorBLACK : 0);
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000117
mtkleinf0599002015-07-13 06:18:39 -0700118 this->onDrawIntoBitmap(bm);
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000119
reed6c225732014-06-09 19:52:07 -0700120 if (kIndex_8_SkColorType == fColorType) {
121 convertToIndex666(bm, &fBitmap, fAlphaType);
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000122 } else {
123 fBitmap = bm;
124 }
125
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000126 fBitmap.setIsVolatile(fIsVolatile);
127 }
128
mtkleina1ebeb22015-10-01 09:43:39 -0700129 void onDraw(int loops, SkCanvas* canvas) override {
mtklein14e4d392014-10-23 14:35:01 -0700130 if (fDoScale) {
131 canvas->scale(.99f, .99f);
132 }
reed@android.comf523e252009-01-26 23:15:37 +0000133 SkIPoint dim = this->getSize();
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000134 SkRandom rand;
reed@android.comf523e252009-01-26 23:15:37 +0000135
136 SkPaint paint(fPaint);
137 this->setupPaint(&paint);
138
139 const SkBitmap& bitmap = fBitmap;
140 const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2);
141 const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000142
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000143 for (int i = 0; i < loops; i++) {
reed@android.comf523e252009-01-26 23:15:37 +0000144 SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
145 SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
junov@google.com4ee7ae52011-06-30 17:30:49 +0000146
147 if (fForceUpdate)
148 bitmap.notifyPixelsChanged();
149
reed@android.comf523e252009-01-26 23:15:37 +0000150 canvas->drawBitmap(bitmap, x, y, &paint);
151 }
152 }
153
mtkleinf0599002015-07-13 06:18:39 -0700154 virtual void onDrawIntoBitmap(const SkBitmap& bm) {
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000155 const int w = bm.width();
156 const int h = bm.height();
157
158 SkCanvas canvas(bm);
159 SkPaint p;
160 p.setAntiAlias(true);
161 p.setColor(SK_ColorRED);
162 canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2,
163 SkIntToScalar(SkMin32(w, h))*3/8, p);
164
165 SkRect r;
166 r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
167 p.setStyle(SkPaint::kStroke_Style);
168 p.setStrokeWidth(SkIntToScalar(4));
169 p.setColor(SK_ColorBLUE);
170 canvas.drawRect(r, p);
171 }
172
reed@android.comf523e252009-01-26 23:15:37 +0000173private:
tfarinaf168b862014-06-19 12:32:29 -0700174 typedef Benchmark INHERITED;
reed@android.comf523e252009-01-26 23:15:37 +0000175};
176
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000177/** Explicitly invoke some filter types to improve coverage of acceleration
178 procs. */
179
reed@google.comef77ec22013-05-29 15:39:54 +0000180enum Flags {
181 kScale_Flag = 1 << 0,
182 kRotate_Flag = 1 << 1,
183 kBilerp_Flag = 1 << 2,
184 kBicubic_Flag = 1 << 3,
185};
186
187static bool isBilerp(uint32_t flags) {
188 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag);
189}
190
191static bool isBicubic(uint32_t flags) {
192 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag | kBicubic_Flag);
193}
194
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000195class FilterBitmapBench : public BitmapBench {
reed@google.comef77ec22013-05-29 15:39:54 +0000196 uint32_t fFlags;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000197 SkString fFullName;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000198public:
reed6c225732014-06-09 19:52:07 -0700199 FilterBitmapBench(SkColorType ct, SkAlphaType at,
reed@google.comef77ec22013-05-29 15:39:54 +0000200 bool forceUpdate, bool isVolitile, uint32_t flags)
mtklein14e4d392014-10-23 14:35:01 -0700201 : INHERITED(ct, at, forceUpdate, isVolitile, false)
reed@google.comef77ec22013-05-29 15:39:54 +0000202 , fFlags(flags) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000203 }
204
205protected:
mtkleinf0599002015-07-13 06:18:39 -0700206 const char* onGetName() override {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000207 fFullName.set(INHERITED::onGetName());
reed@google.comef77ec22013-05-29 15:39:54 +0000208 if (fFlags & kScale_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000209 fFullName.append("_scale");
reed@google.comef77ec22013-05-29 15:39:54 +0000210 }
211 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000212 fFullName.append("_rotate");
reed@google.comef77ec22013-05-29 15:39:54 +0000213 }
214 if (isBilerp(fFlags)) {
215 fFullName.append("_bilerp");
216 } else if (isBicubic(fFlags)) {
217 fFullName.append("_bicubic");
218 }
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000219
220 return fFullName.c_str();
221 }
222
mtkleina1ebeb22015-10-01 09:43:39 -0700223 void onDraw(int loops, SkCanvas* canvas) override {
Mike Reed3661bc92017-02-22 13:21:42 -0500224 SkISize dim = canvas->getBaseLayerSize();
reed@google.comef77ec22013-05-29 15:39:54 +0000225 if (fFlags & kScale_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000226 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
227 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000228
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000229 canvas->translate(x, y);
230 // just enough so we can't take the sprite case
231 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
232 canvas->translate(-x, -y);
233 }
reed@google.comef77ec22013-05-29 15:39:54 +0000234 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000235 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
236 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
bungeman7438bfc2016-07-12 15:01:19 -0700237 canvas->rotate(SkIntToScalar(35), x, y);
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000238 }
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000239 INHERITED::onDraw(loops, canvas);
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000240 }
241
mtklein36352bf2015-03-25 18:17:31 -0700242 void setupPaint(SkPaint* paint) override {
reed@google.com9cfc83c2013-07-22 17:18:18 +0000243 this->INHERITED::setupPaint(paint);
244
245 int index = 0;
246 if (fFlags & kBilerp_Flag) {
247 index |= 1;
248 }
249 if (fFlags & kBicubic_Flag) {
250 index |= 2;
251 }
reed93a12152015-03-16 10:08:34 -0700252 static const SkFilterQuality gQualitys[] = {
253 kNone_SkFilterQuality,
254 kLow_SkFilterQuality,
255 kMedium_SkFilterQuality,
256 kHigh_SkFilterQuality
reed@google.com9cfc83c2013-07-22 17:18:18 +0000257 };
reed93a12152015-03-16 10:08:34 -0700258 paint->setFilterQuality(gQualitys[index]);
reed@google.com9cfc83c2013-07-22 17:18:18 +0000259}
260
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000261private:
262 typedef BitmapBench INHERITED;
263};
264
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000265/** Verify optimizations that test source alpha values. */
266
267class SourceAlphaBitmapBench : public BitmapBench {
268public:
269 enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha,
270 kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha};
271private:
272 SkString fFullName;
273 SourceAlpha fSourceAlpha;
274public:
reed6c225732014-06-09 19:52:07 -0700275 SourceAlphaBitmapBench(SourceAlpha alpha, SkColorType ct,
reed@google.comef77ec22013-05-29 15:39:54 +0000276 bool forceUpdate = false, bool bitmapVolatile = false)
mtklein14e4d392014-10-23 14:35:01 -0700277 : INHERITED(ct, kPremul_SkAlphaType, forceUpdate, bitmapVolatile, false)
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000278 , fSourceAlpha(alpha) {
279 }
280
281protected:
mtkleinf0599002015-07-13 06:18:39 -0700282 const char* onGetName() override {
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000283 fFullName.set(INHERITED::onGetName());
284
285 if (fSourceAlpha == kOpaque_SourceAlpha) {
286 fFullName.append("_source_opaque");
287 } else if (fSourceAlpha == kTransparent_SourceAlpha) {
288 fFullName.append("_source_transparent");
289 } else if (fSourceAlpha == kTwoStripes_SourceAlpha) {
290 fFullName.append("_source_stripes_two");
291 } else if (fSourceAlpha == kThreeStripes_SourceAlpha) {
292 fFullName.append("_source_stripes_three");
293 }
294
295 return fFullName.c_str();
296 }
297
mtklein36352bf2015-03-25 18:17:31 -0700298 void onDrawIntoBitmap(const SkBitmap& bm) override {
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000299 const int w = bm.width();
300 const int h = bm.height();
301
302 if (kOpaque_SourceAlpha == fSourceAlpha) {
303 bm.eraseColor(SK_ColorBLACK);
304 } else if (kTransparent_SourceAlpha == fSourceAlpha) {
305 bm.eraseColor(0);
306 } else if (kTwoStripes_SourceAlpha == fSourceAlpha) {
307 bm.eraseColor(0);
308
309 SkCanvas canvas(bm);
310 SkPaint p;
311 p.setAntiAlias(false);
312 p.setStyle(SkPaint::kFill_Style);
313 p.setColor(SK_ColorRED);
314
315 // Draw red vertical stripes on transparent background
316 SkRect r;
317 for (int x = 0; x < w; x+=2)
318 {
319 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
320 canvas.drawRect(r, p);
321 }
322
323 } else if (kThreeStripes_SourceAlpha == fSourceAlpha) {
324 bm.eraseColor(0);
325
326 SkCanvas canvas(bm);
327 SkPaint p;
328 p.setAntiAlias(false);
329 p.setStyle(SkPaint::kFill_Style);
330
331 // Draw vertical stripes on transparent background with a pattern
332 // where the first pixel is fully transparent, the next is semi-transparent
333 // and the third is fully opaque.
334 SkRect r;
335 for (int x = 0; x < w; x++)
336 {
337 if (x % 3 == 0) {
338 continue; // Keep transparent
339 } else if (x % 3 == 1) {
340 p.setColor(SkColorSetARGB(127, 127, 127, 127)); // Semi-transparent
341 } else if (x % 3 == 2) {
342 p.setColor(SK_ColorRED); // Opaque
343 }
344 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
345 canvas.drawRect(r, p);
346 }
347 }
348 }
349
350private:
351 typedef BitmapBench INHERITED;
352};
reed@google.com2ece2872013-05-28 20:48:14 +0000353
mtklein14e4d392014-10-23 14:35:01 -0700354DEF_BENCH( return new BitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, false); )
355DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, false); )
356DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, true); )
357DEF_BENCH( return new BitmapBench(kRGB_565_SkColorType, kOpaque_SkAlphaType, false, false, false); )
358DEF_BENCH( return new BitmapBench(kIndex_8_SkColorType, kPremul_SkAlphaType, false, false, false); )
359DEF_BENCH( return new BitmapBench(kIndex_8_SkColorType, kOpaque_SkAlphaType, false, false, false); )
360DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, false); )
361DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, false); )
reed@android.comf523e252009-01-26 23:15:37 +0000362
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000363// 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 -0700364DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
365DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
366DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kBilerp_Flag); )
367DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kBilerp_Flag); )
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000368
369// scale rotate filter -> S32_opaque_D32_filter_DXDY_{SSE2,SSSE3}
reed6c225732014-06-09 19:52:07 -0700370DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
371DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
372DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
373DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
reed@google.comef77ec22013-05-29 15:39:54 +0000374
reed6c225732014-06-09 19:52:07 -0700375DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag | kBicubic_Flag); )
376DEF_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 +0000377
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000378// source alpha tests -> S32A_Opaque_BlitRow32_{arm,neon}
reed6c225732014-06-09 19:52:07 -0700379DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kOpaque_SourceAlpha, kN32_SkColorType); )
380DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTransparent_SourceAlpha, kN32_SkColorType); )
381DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTwoStripes_SourceAlpha, kN32_SkColorType); )
382DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kThreeStripes_SourceAlpha, kN32_SkColorType); )