blob: e9ba1dcb918d1488575ee353f0933a1538936cac [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 SkColorTable* ctable = new SkColorTable(storage, 216, aType);
48 dst->allocPixels(SkImageInfo::Make(src.width(), src.height(), kIndex_8_SkColorType, aType),
49 NULL, ctable);
reed@android.comf523e252009-01-26 23:15:37 +000050 ctable->unref();
rmistry@google.comfbfcd562012-08-23 18:09:54 +000051
reed@android.comf523e252009-01-26 23:15:37 +000052 SkAutoLockPixels alps(src);
53 SkAutoLockPixels alpd(*dst);
54
55 for (int y = 0; y < src.height(); y++) {
56 const SkPMColor* srcP = src.getAddr32(0, y);
57 uint8_t* dstP = dst->getAddr8(0, y);
58 for (int x = src.width() - 1; x >= 0; --x) {
59 *dstP++ = compute666Index(*srcP++);
60 }
61 }
62}
63
64/* Variants for bitmaps
rmistry@google.comfbfcd562012-08-23 18:09:54 +000065
reed@android.comf523e252009-01-26 23:15:37 +000066 - src depth (32 w+w/o alpha), 565, 4444, index, a8
67 - paint options: filtering, dither, alpha
68 - matrix options: translate, scale, rotate, persp
69 - tiling: none, repeat, mirror, clamp
rmistry@google.comfbfcd562012-08-23 18:09:54 +000070
reed@android.comf523e252009-01-26 23:15:37 +000071 */
72
tfarinaf168b862014-06-19 12:32:29 -070073class BitmapBench : public Benchmark {
reed6c225732014-06-09 19:52:07 -070074 const SkColorType fColorType;
75 const SkAlphaType fAlphaType;
76 const bool fForceUpdate; //bitmap marked as dirty before each draw. forces bitmap to be updated on device cache
77 const bool fIsVolatile;
78
79 SkBitmap fBitmap;
80 SkPaint fPaint;
81 SkString fName;
82
djsollen@google.comc2532dd2013-04-09 18:06:06 +000083 enum { W = 128 };
84 enum { H = 128 };
reed@android.comf523e252009-01-26 23:15:37 +000085public:
reed6c225732014-06-09 19:52:07 -070086 BitmapBench(SkColorType ct, SkAlphaType at, bool forceUpdate = false, bool isVolatile = false)
87 : fColorType(ct)
88 , fAlphaType(at)
djsollen@google.comc2532dd2013-04-09 18:06:06 +000089 , fForceUpdate(forceUpdate)
reed6c225732014-06-09 19:52:07 -070090 , fIsVolatile(isVolatile)
91 {}
reed@android.comf523e252009-01-26 23:15:37 +000092
93protected:
94 virtual const char* onGetName() {
95 fName.set("bitmap");
reed6c225732014-06-09 19:52:07 -070096 fName.appendf("_%s%s", sk_tool_utils::colortype_name(fColorType),
97 kOpaque_SkAlphaType == fAlphaType ? "" : "_A");
rmistry@google.comfbfcd562012-08-23 18:09:54 +000098 if (fForceUpdate)
junov@google.com4ee7ae52011-06-30 17:30:49 +000099 fName.append("_update");
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000100 if (fIsVolatile)
junov@google.com4ee7ae52011-06-30 17:30:49 +0000101 fName.append("_volatile");
102
reed@android.comf523e252009-01-26 23:15:37 +0000103 return fName.c_str();
104 }
105
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000106 virtual void onPreDraw() {
107 SkBitmap bm;
108
reed6c225732014-06-09 19:52:07 -0700109 if (kIndex_8_SkColorType == fColorType) {
reedbae704b2014-06-28 14:26:35 -0700110 bm.allocPixels(SkImageInfo::MakeN32(W, H, fAlphaType));
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000111 } else {
reedbae704b2014-06-28 14:26:35 -0700112 bm.allocPixels(SkImageInfo::Make(W, H, fColorType, fAlphaType));
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000113 }
reed6c225732014-06-09 19:52:07 -0700114 bm.eraseColor(kOpaque_SkAlphaType == fAlphaType ? SK_ColorBLACK : 0);
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000115
116 onDrawIntoBitmap(bm);
117
reed6c225732014-06-09 19:52:07 -0700118 if (kIndex_8_SkColorType == fColorType) {
119 convertToIndex666(bm, &fBitmap, fAlphaType);
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000120 } else {
121 fBitmap = bm;
122 }
123
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000124 fBitmap.setIsVolatile(fIsVolatile);
125 }
126
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000127 virtual void onDraw(const int loops, SkCanvas* canvas) {
reed@android.comf523e252009-01-26 23:15:37 +0000128 SkIPoint dim = this->getSize();
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000129 SkRandom rand;
reed@android.comf523e252009-01-26 23:15:37 +0000130
131 SkPaint paint(fPaint);
132 this->setupPaint(&paint);
133
134 const SkBitmap& bitmap = fBitmap;
135 const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2);
136 const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000137
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000138 for (int i = 0; i < loops; i++) {
reed@android.comf523e252009-01-26 23:15:37 +0000139 SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
140 SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
junov@google.com4ee7ae52011-06-30 17:30:49 +0000141
142 if (fForceUpdate)
143 bitmap.notifyPixelsChanged();
144
reed@android.comf523e252009-01-26 23:15:37 +0000145 canvas->drawBitmap(bitmap, x, y, &paint);
146 }
147 }
148
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000149 virtual void onDrawIntoBitmap(const SkBitmap& bm) {
150 const int w = bm.width();
151 const int h = bm.height();
152
153 SkCanvas canvas(bm);
154 SkPaint p;
155 p.setAntiAlias(true);
156 p.setColor(SK_ColorRED);
157 canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2,
158 SkIntToScalar(SkMin32(w, h))*3/8, p);
159
160 SkRect r;
161 r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
162 p.setStyle(SkPaint::kStroke_Style);
163 p.setStrokeWidth(SkIntToScalar(4));
164 p.setColor(SK_ColorBLUE);
165 canvas.drawRect(r, p);
166 }
167
reed@android.comf523e252009-01-26 23:15:37 +0000168private:
tfarinaf168b862014-06-19 12:32:29 -0700169 typedef Benchmark INHERITED;
reed@android.comf523e252009-01-26 23:15:37 +0000170};
171
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000172/** Explicitly invoke some filter types to improve coverage of acceleration
173 procs. */
174
reed@google.comef77ec22013-05-29 15:39:54 +0000175enum Flags {
176 kScale_Flag = 1 << 0,
177 kRotate_Flag = 1 << 1,
178 kBilerp_Flag = 1 << 2,
179 kBicubic_Flag = 1 << 3,
180};
181
182static bool isBilerp(uint32_t flags) {
183 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag);
184}
185
186static bool isBicubic(uint32_t flags) {
187 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag | kBicubic_Flag);
188}
189
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000190class FilterBitmapBench : public BitmapBench {
reed@google.comef77ec22013-05-29 15:39:54 +0000191 uint32_t fFlags;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000192 SkString fFullName;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000193public:
reed6c225732014-06-09 19:52:07 -0700194 FilterBitmapBench(SkColorType ct, SkAlphaType at,
reed@google.comef77ec22013-05-29 15:39:54 +0000195 bool forceUpdate, bool isVolitile, uint32_t flags)
reed6c225732014-06-09 19:52:07 -0700196 : INHERITED(ct, at, forceUpdate, isVolitile)
reed@google.comef77ec22013-05-29 15:39:54 +0000197 , fFlags(flags) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000198 }
199
200protected:
201 virtual const char* onGetName() {
202 fFullName.set(INHERITED::onGetName());
reed@google.comef77ec22013-05-29 15:39:54 +0000203 if (fFlags & kScale_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000204 fFullName.append("_scale");
reed@google.comef77ec22013-05-29 15:39:54 +0000205 }
206 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000207 fFullName.append("_rotate");
reed@google.comef77ec22013-05-29 15:39:54 +0000208 }
209 if (isBilerp(fFlags)) {
210 fFullName.append("_bilerp");
211 } else if (isBicubic(fFlags)) {
212 fFullName.append("_bicubic");
213 }
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000214
215 return fFullName.c_str();
216 }
217
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000218 virtual void onDraw(const int loops, SkCanvas* canvas) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000219 SkISize dim = canvas->getDeviceSize();
reed@google.comef77ec22013-05-29 15:39:54 +0000220 if (fFlags & kScale_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000221 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
222 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000223
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000224 canvas->translate(x, y);
225 // just enough so we can't take the sprite case
226 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
227 canvas->translate(-x, -y);
228 }
reed@google.comef77ec22013-05-29 15:39:54 +0000229 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000230 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
231 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000232
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000233 canvas->translate(x, y);
234 canvas->rotate(SkIntToScalar(35));
235 canvas->translate(-x, -y);
236 }
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000237 INHERITED::onDraw(loops, canvas);
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000238 }
239
reed@google.com9cfc83c2013-07-22 17:18:18 +0000240 virtual void setupPaint(SkPaint* paint) SK_OVERRIDE {
241 this->INHERITED::setupPaint(paint);
242
243 int index = 0;
244 if (fFlags & kBilerp_Flag) {
245 index |= 1;
246 }
247 if (fFlags & kBicubic_Flag) {
248 index |= 2;
249 }
250 static const SkPaint::FilterLevel gLevels[] = {
251 SkPaint::kNone_FilterLevel,
252 SkPaint::kLow_FilterLevel,
253 SkPaint::kMedium_FilterLevel,
254 SkPaint::kHigh_FilterLevel
255 };
256 paint->setFilterLevel(gLevels[index]);
257}
258
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000259private:
260 typedef BitmapBench INHERITED;
261};
262
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000263/** Verify optimizations that test source alpha values. */
264
265class SourceAlphaBitmapBench : public BitmapBench {
266public:
267 enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha,
268 kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha};
269private:
270 SkString fFullName;
271 SourceAlpha fSourceAlpha;
272public:
reed6c225732014-06-09 19:52:07 -0700273 SourceAlphaBitmapBench(SourceAlpha alpha, SkColorType ct,
reed@google.comef77ec22013-05-29 15:39:54 +0000274 bool forceUpdate = false, bool bitmapVolatile = false)
reed6c225732014-06-09 19:52:07 -0700275 : INHERITED(ct, kPremul_SkAlphaType, forceUpdate, bitmapVolatile)
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000276 , fSourceAlpha(alpha) {
277 }
278
279protected:
280 virtual const char* onGetName() {
281 fFullName.set(INHERITED::onGetName());
282
283 if (fSourceAlpha == kOpaque_SourceAlpha) {
284 fFullName.append("_source_opaque");
285 } else if (fSourceAlpha == kTransparent_SourceAlpha) {
286 fFullName.append("_source_transparent");
287 } else if (fSourceAlpha == kTwoStripes_SourceAlpha) {
288 fFullName.append("_source_stripes_two");
289 } else if (fSourceAlpha == kThreeStripes_SourceAlpha) {
290 fFullName.append("_source_stripes_three");
291 }
292
293 return fFullName.c_str();
294 }
295
296 virtual void onDrawIntoBitmap(const SkBitmap& bm) SK_OVERRIDE {
297 const int w = bm.width();
298 const int h = bm.height();
299
300 if (kOpaque_SourceAlpha == fSourceAlpha) {
301 bm.eraseColor(SK_ColorBLACK);
302 } else if (kTransparent_SourceAlpha == fSourceAlpha) {
303 bm.eraseColor(0);
304 } else if (kTwoStripes_SourceAlpha == fSourceAlpha) {
305 bm.eraseColor(0);
306
307 SkCanvas canvas(bm);
308 SkPaint p;
309 p.setAntiAlias(false);
310 p.setStyle(SkPaint::kFill_Style);
311 p.setColor(SK_ColorRED);
312
313 // Draw red vertical stripes on transparent background
314 SkRect r;
315 for (int x = 0; x < w; x+=2)
316 {
317 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
318 canvas.drawRect(r, p);
319 }
320
321 } else if (kThreeStripes_SourceAlpha == fSourceAlpha) {
322 bm.eraseColor(0);
323
324 SkCanvas canvas(bm);
325 SkPaint p;
326 p.setAntiAlias(false);
327 p.setStyle(SkPaint::kFill_Style);
328
329 // Draw vertical stripes on transparent background with a pattern
330 // where the first pixel is fully transparent, the next is semi-transparent
331 // and the third is fully opaque.
332 SkRect r;
333 for (int x = 0; x < w; x++)
334 {
335 if (x % 3 == 0) {
336 continue; // Keep transparent
337 } else if (x % 3 == 1) {
338 p.setColor(SkColorSetARGB(127, 127, 127, 127)); // Semi-transparent
339 } else if (x % 3 == 2) {
340 p.setColor(SK_ColorRED); // Opaque
341 }
342 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
343 canvas.drawRect(r, p);
344 }
345 }
346 }
347
348private:
349 typedef BitmapBench INHERITED;
350};
reed@google.com2ece2872013-05-28 20:48:14 +0000351
reed6c225732014-06-09 19:52:07 -0700352DEF_BENCH( return new BitmapBench(kN32_SkColorType, kPremul_SkAlphaType); )
353DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType); )
354DEF_BENCH( return new BitmapBench(kRGB_565_SkColorType, kOpaque_SkAlphaType); )
355DEF_BENCH( return new BitmapBench(kIndex_8_SkColorType, kPremul_SkAlphaType); )
356DEF_BENCH( return new BitmapBench(kIndex_8_SkColorType, kOpaque_SkAlphaType); )
357DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true); )
358DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false); )
reed@android.comf523e252009-01-26 23:15:37 +0000359
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000360// 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 -0700361DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
362DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
363DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kBilerp_Flag); )
364DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kBilerp_Flag); )
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000365
366// scale rotate filter -> S32_opaque_D32_filter_DXDY_{SSE2,SSSE3}
reed6c225732014-06-09 19:52:07 -0700367DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
368DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
369DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
370DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
reed@google.comef77ec22013-05-29 15:39:54 +0000371
reed6c225732014-06-09 19:52:07 -0700372DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag | kBicubic_Flag); )
373DEF_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 +0000374
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000375// source alpha tests -> S32A_Opaque_BlitRow32_{arm,neon}
reed6c225732014-06-09 19:52:07 -0700376DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kOpaque_SourceAlpha, kN32_SkColorType); )
377DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTransparent_SourceAlpha, kN32_SkColorType); )
378DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTwoStripes_SourceAlpha, kN32_SkColorType); )
379DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kThreeStripes_SourceAlpha, kN32_SkColorType); )