blob: 2b0cabfc37f7583b8986fbf9479dab0a9ab6bc54 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@android.comf523e252009-01-26 23:15:37 +00008#include "SkBenchmark.h"
9#include "SkBitmap.h"
10#include "SkPaint.h"
11#include "SkCanvas.h"
12#include "SkColorPriv.h"
13#include "SkRandom.h"
14#include "SkString.h"
15
reed@android.comf523e252009-01-26 23:15:37 +000016static const char* gConfigName[] = {
17 "ERROR", "a1", "a8", "index8", "565", "4444", "8888"
18};
19
reed@android.comf523e252009-01-26 23:15:37 +000020static int conv6ToByte(int x) {
21 return x * 0xFF / 5;
22}
23
24static int convByteTo6(int x) {
25 return x * 5 / 255;
26}
27
28static uint8_t compute666Index(SkPMColor c) {
29 int r = SkGetPackedR32(c);
30 int g = SkGetPackedG32(c);
31 int b = SkGetPackedB32(c);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000032
reed@android.comf523e252009-01-26 23:15:37 +000033 return convByteTo6(r) * 36 + convByteTo6(g) * 6 + convByteTo6(b);
34}
35
reed@google.com0a6151d2013-10-10 14:44:56 +000036static void convertToIndex666(const SkBitmap& src, SkBitmap* dst, bool isOpaque) {
37 SkPMColor storage[216];
38 SkPMColor* colors = storage;
reed@android.comf523e252009-01-26 23:15:37 +000039 // rrr ggg bbb
40 for (int r = 0; r < 6; r++) {
41 int rr = conv6ToByte(r);
42 for (int g = 0; g < 6; g++) {
43 int gg = conv6ToByte(g);
44 for (int b = 0; b < 6; b++) {
45 int bb = conv6ToByte(b);
46 *colors++ = SkPreMultiplyARGB(0xFF, rr, gg, bb);
47 }
48 }
49 }
reed@google.com0a6151d2013-10-10 14:44:56 +000050 SkColorTable* ctable = new SkColorTable(storage, 216,
51 isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
reed@android.comf523e252009-01-26 23:15:37 +000052 dst->setConfig(SkBitmap::kIndex8_Config, src.width(), src.height());
53 dst->allocPixels(ctable);
54 ctable->unref();
rmistry@google.comfbfcd562012-08-23 18:09:54 +000055
reed@android.comf523e252009-01-26 23:15:37 +000056 SkAutoLockPixels alps(src);
57 SkAutoLockPixels alpd(*dst);
58
59 for (int y = 0; y < src.height(); y++) {
60 const SkPMColor* srcP = src.getAddr32(0, y);
61 uint8_t* dstP = dst->getAddr8(0, y);
62 for (int x = src.width() - 1; x >= 0; --x) {
63 *dstP++ = compute666Index(*srcP++);
64 }
65 }
66}
67
68/* Variants for bitmaps
rmistry@google.comfbfcd562012-08-23 18:09:54 +000069
reed@android.comf523e252009-01-26 23:15:37 +000070 - src depth (32 w+w/o alpha), 565, 4444, index, a8
71 - paint options: filtering, dither, alpha
72 - matrix options: translate, scale, rotate, persp
73 - tiling: none, repeat, mirror, clamp
rmistry@google.comfbfcd562012-08-23 18:09:54 +000074
reed@android.comf523e252009-01-26 23:15:37 +000075 */
76
77class BitmapBench : public SkBenchmark {
78 SkBitmap fBitmap;
79 SkPaint fPaint;
reed@android.com11ec1862009-10-19 19:01:45 +000080 bool fIsOpaque;
junov@google.com4ee7ae52011-06-30 17:30:49 +000081 bool fForceUpdate; //bitmap marked as dirty before each draw. forces bitmap to be updated on device cache
djsollen@google.comc2532dd2013-04-09 18:06:06 +000082 bool fIsVolatile;
83 SkBitmap::Config fConfig;
reed@android.comf523e252009-01-26 23:15:37 +000084 SkString fName;
djsollen@google.comc2532dd2013-04-09 18:06:06 +000085 enum { W = 128 };
86 enum { H = 128 };
reed@android.comf523e252009-01-26 23:15:37 +000087public:
mtklein@google.com410e6e82013-09-13 19:52:27 +000088 BitmapBench(bool isOpaque, SkBitmap::Config c,
reed@google.comef77ec22013-05-29 15:39:54 +000089 bool forceUpdate = false, bool bitmapVolatile = false)
mtklein@google.com410e6e82013-09-13 19:52:27 +000090 : fIsOpaque(isOpaque)
djsollen@google.comc2532dd2013-04-09 18:06:06 +000091 , fForceUpdate(forceUpdate)
djsollen@google.comc2532dd2013-04-09 18:06:06 +000092 , fIsVolatile(bitmapVolatile)
93 , fConfig(c) {
reed@android.comf523e252009-01-26 23:15:37 +000094 }
95
96protected:
97 virtual const char* onGetName() {
98 fName.set("bitmap");
djsollen@google.comc2532dd2013-04-09 18:06:06 +000099 fName.appendf("_%s%s", gConfigName[fConfig],
reed@android.com11ec1862009-10-19 19:01:45 +0000100 fIsOpaque ? "" : "_A");
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000101 if (fForceUpdate)
junov@google.com4ee7ae52011-06-30 17:30:49 +0000102 fName.append("_update");
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000103 if (fIsVolatile)
junov@google.com4ee7ae52011-06-30 17:30:49 +0000104 fName.append("_volatile");
105
reed@android.comf523e252009-01-26 23:15:37 +0000106 return fName.c_str();
107 }
108
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000109 virtual void onPreDraw() {
110 SkBitmap bm;
111
112 if (SkBitmap::kIndex8_Config == fConfig) {
113 bm.setConfig(SkBitmap::kARGB_8888_Config, W, H);
114 } else {
115 bm.setConfig(fConfig, W, H);
116 }
117
118 bm.allocPixels();
119 bm.eraseColor(fIsOpaque ? SK_ColorBLACK : 0);
120
121 onDrawIntoBitmap(bm);
122
123 if (SkBitmap::kIndex8_Config == fConfig) {
reed@google.com0a6151d2013-10-10 14:44:56 +0000124 convertToIndex666(bm, &fBitmap, fIsOpaque);
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000125 } else {
126 fBitmap = bm;
127 }
128
reed@google.com383a6972013-10-21 14:00:07 +0000129 fBitmap.setAlphaType(fIsOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000130 fBitmap.setIsVolatile(fIsVolatile);
131 }
132
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000133 virtual void onDraw(const int loops, SkCanvas* canvas) {
reed@android.comf523e252009-01-26 23:15:37 +0000134 SkIPoint dim = this->getSize();
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000135 SkRandom rand;
reed@android.comf523e252009-01-26 23:15:37 +0000136
137 SkPaint paint(fPaint);
138 this->setupPaint(&paint);
139
140 const SkBitmap& bitmap = fBitmap;
141 const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2);
142 const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000143
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000144 for (int i = 0; i < loops; i++) {
reed@android.comf523e252009-01-26 23:15:37 +0000145 SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
146 SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
junov@google.com4ee7ae52011-06-30 17:30:49 +0000147
148 if (fForceUpdate)
149 bitmap.notifyPixelsChanged();
150
reed@android.comf523e252009-01-26 23:15:37 +0000151 canvas->drawBitmap(bitmap, x, y, &paint);
152 }
153 }
154
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000155 virtual void onDrawIntoBitmap(const SkBitmap& bm) {
156 const int w = bm.width();
157 const int h = bm.height();
158
159 SkCanvas canvas(bm);
160 SkPaint p;
161 p.setAntiAlias(true);
162 p.setColor(SK_ColorRED);
163 canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2,
164 SkIntToScalar(SkMin32(w, h))*3/8, p);
165
166 SkRect r;
167 r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
168 p.setStyle(SkPaint::kStroke_Style);
169 p.setStrokeWidth(SkIntToScalar(4));
170 p.setColor(SK_ColorBLUE);
171 canvas.drawRect(r, p);
172 }
173
reed@android.comf523e252009-01-26 23:15:37 +0000174private:
175 typedef SkBenchmark INHERITED;
176};
177
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000178/** Explicitly invoke some filter types to improve coverage of acceleration
179 procs. */
180
reed@google.comef77ec22013-05-29 15:39:54 +0000181enum Flags {
182 kScale_Flag = 1 << 0,
183 kRotate_Flag = 1 << 1,
184 kBilerp_Flag = 1 << 2,
185 kBicubic_Flag = 1 << 3,
186};
187
188static bool isBilerp(uint32_t flags) {
189 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag);
190}
191
192static bool isBicubic(uint32_t flags) {
193 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag | kBicubic_Flag);
194}
195
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000196class FilterBitmapBench : public BitmapBench {
reed@google.comef77ec22013-05-29 15:39:54 +0000197 uint32_t fFlags;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000198 SkString fFullName;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000199public:
mtklein@google.com410e6e82013-09-13 19:52:27 +0000200 FilterBitmapBench(bool isOpaque, SkBitmap::Config c,
reed@google.comef77ec22013-05-29 15:39:54 +0000201 bool forceUpdate, bool isVolitile, uint32_t flags)
mtklein@google.com410e6e82013-09-13 19:52:27 +0000202 : INHERITED(isOpaque, c, forceUpdate, isVolitile)
reed@google.comef77ec22013-05-29 15:39:54 +0000203 , fFlags(flags) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000204 }
205
206protected:
207 virtual const char* onGetName() {
208 fFullName.set(INHERITED::onGetName());
reed@google.comef77ec22013-05-29 15:39:54 +0000209 if (fFlags & kScale_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000210 fFullName.append("_scale");
reed@google.comef77ec22013-05-29 15:39:54 +0000211 }
212 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000213 fFullName.append("_rotate");
reed@google.comef77ec22013-05-29 15:39:54 +0000214 }
215 if (isBilerp(fFlags)) {
216 fFullName.append("_bilerp");
217 } else if (isBicubic(fFlags)) {
218 fFullName.append("_bicubic");
219 }
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000220
221 return fFullName.c_str();
222 }
223
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000224 virtual void onDraw(const int loops, SkCanvas* canvas) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000225 SkISize dim = canvas->getDeviceSize();
reed@google.comef77ec22013-05-29 15:39:54 +0000226 if (fFlags & kScale_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000227 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
228 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000229
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000230 canvas->translate(x, y);
231 // just enough so we can't take the sprite case
232 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
233 canvas->translate(-x, -y);
234 }
reed@google.comef77ec22013-05-29 15:39:54 +0000235 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000236 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
237 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000238
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000239 canvas->translate(x, y);
240 canvas->rotate(SkIntToScalar(35));
241 canvas->translate(-x, -y);
242 }
commit-bot@chromium.org33614712013-12-03 18:17:16 +0000243 INHERITED::onDraw(loops, canvas);
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000244 }
245
reed@google.com9cfc83c2013-07-22 17:18:18 +0000246 virtual void setupPaint(SkPaint* paint) SK_OVERRIDE {
247 this->INHERITED::setupPaint(paint);
248
249 int index = 0;
250 if (fFlags & kBilerp_Flag) {
251 index |= 1;
252 }
253 if (fFlags & kBicubic_Flag) {
254 index |= 2;
255 }
256 static const SkPaint::FilterLevel gLevels[] = {
257 SkPaint::kNone_FilterLevel,
258 SkPaint::kLow_FilterLevel,
259 SkPaint::kMedium_FilterLevel,
260 SkPaint::kHigh_FilterLevel
261 };
262 paint->setFilterLevel(gLevels[index]);
263}
264
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000265private:
266 typedef BitmapBench INHERITED;
267};
268
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000269/** Verify optimizations that test source alpha values. */
270
271class SourceAlphaBitmapBench : public BitmapBench {
272public:
273 enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha,
274 kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha};
275private:
276 SkString fFullName;
277 SourceAlpha fSourceAlpha;
278public:
mtklein@google.com410e6e82013-09-13 19:52:27 +0000279 SourceAlphaBitmapBench(SourceAlpha alpha, SkBitmap::Config c,
reed@google.comef77ec22013-05-29 15:39:54 +0000280 bool forceUpdate = false, bool bitmapVolatile = false)
mtklein@google.com410e6e82013-09-13 19:52:27 +0000281 : INHERITED(false, c, forceUpdate, bitmapVolatile)
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000282 , fSourceAlpha(alpha) {
283 }
284
285protected:
286 virtual const char* onGetName() {
287 fFullName.set(INHERITED::onGetName());
288
289 if (fSourceAlpha == kOpaque_SourceAlpha) {
290 fFullName.append("_source_opaque");
291 } else if (fSourceAlpha == kTransparent_SourceAlpha) {
292 fFullName.append("_source_transparent");
293 } else if (fSourceAlpha == kTwoStripes_SourceAlpha) {
294 fFullName.append("_source_stripes_two");
295 } else if (fSourceAlpha == kThreeStripes_SourceAlpha) {
296 fFullName.append("_source_stripes_three");
297 }
298
299 return fFullName.c_str();
300 }
301
302 virtual void onDrawIntoBitmap(const SkBitmap& bm) SK_OVERRIDE {
303 const int w = bm.width();
304 const int h = bm.height();
305
306 if (kOpaque_SourceAlpha == fSourceAlpha) {
307 bm.eraseColor(SK_ColorBLACK);
308 } else if (kTransparent_SourceAlpha == fSourceAlpha) {
309 bm.eraseColor(0);
310 } else if (kTwoStripes_SourceAlpha == fSourceAlpha) {
311 bm.eraseColor(0);
312
313 SkCanvas canvas(bm);
314 SkPaint p;
315 p.setAntiAlias(false);
316 p.setStyle(SkPaint::kFill_Style);
317 p.setColor(SK_ColorRED);
318
319 // Draw red vertical stripes on transparent background
320 SkRect r;
321 for (int x = 0; x < w; x+=2)
322 {
323 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
324 canvas.drawRect(r, p);
325 }
326
327 } else if (kThreeStripes_SourceAlpha == fSourceAlpha) {
328 bm.eraseColor(0);
329
330 SkCanvas canvas(bm);
331 SkPaint p;
332 p.setAntiAlias(false);
333 p.setStyle(SkPaint::kFill_Style);
334
335 // Draw vertical stripes on transparent background with a pattern
336 // where the first pixel is fully transparent, the next is semi-transparent
337 // and the third is fully opaque.
338 SkRect r;
339 for (int x = 0; x < w; x++)
340 {
341 if (x % 3 == 0) {
342 continue; // Keep transparent
343 } else if (x % 3 == 1) {
344 p.setColor(SkColorSetARGB(127, 127, 127, 127)); // Semi-transparent
345 } else if (x % 3 == 2) {
346 p.setColor(SK_ColorRED); // Opaque
347 }
348 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
349 canvas.drawRect(r, p);
350 }
351 }
352 }
353
354private:
355 typedef BitmapBench INHERITED;
356};
reed@google.com2ece2872013-05-28 20:48:14 +0000357
mtklein@google.com410e6e82013-09-13 19:52:27 +0000358DEF_BENCH( return new BitmapBench(false, SkBitmap::kARGB_8888_Config); )
359DEF_BENCH( return new BitmapBench(true, SkBitmap::kARGB_8888_Config); )
360DEF_BENCH( return new BitmapBench(true, SkBitmap::kRGB_565_Config); )
361DEF_BENCH( return new BitmapBench(false, SkBitmap::kIndex8_Config); )
362DEF_BENCH( return new BitmapBench(true, SkBitmap::kIndex8_Config); )
363DEF_BENCH( return new BitmapBench(true, SkBitmap::kARGB_8888_Config, true, true); )
364DEF_BENCH( return new BitmapBench(true, SkBitmap::kARGB_8888_Config, true, false); )
reed@android.comf523e252009-01-26 23:15:37 +0000365
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000366// scale filter -> S32_opaque_D32_filter_DX_{SSE2,SSSE3} and Fact9 is also for S32_D16_filter_DX_SSE2
mtklein@google.com410e6e82013-09-13 19:52:27 +0000367DEF_BENCH( return new FilterBitmapBench(false, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kBilerp_Flag); )
368DEF_BENCH( return new FilterBitmapBench(true, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kBilerp_Flag); )
369DEF_BENCH( return new FilterBitmapBench(true, SkBitmap::kARGB_8888_Config, true, true, kScale_Flag | kBilerp_Flag); )
370DEF_BENCH( return new FilterBitmapBench(true, SkBitmap::kARGB_8888_Config, true, false, kScale_Flag | kBilerp_Flag); )
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000371
372// scale rotate filter -> S32_opaque_D32_filter_DXDY_{SSE2,SSSE3}
mtklein@google.com410e6e82013-09-13 19:52:27 +0000373DEF_BENCH( return new FilterBitmapBench(false, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
374DEF_BENCH( return new FilterBitmapBench(true, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
375DEF_BENCH( return new FilterBitmapBench(true, SkBitmap::kARGB_8888_Config, true, true, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
376DEF_BENCH( return new FilterBitmapBench(true, SkBitmap::kARGB_8888_Config, true, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
reed@google.comef77ec22013-05-29 15:39:54 +0000377
mtklein@google.com410e6e82013-09-13 19:52:27 +0000378DEF_BENCH( return new FilterBitmapBench(false, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kBilerp_Flag | kBicubic_Flag); )
379DEF_BENCH( return new FilterBitmapBench(false, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag | kBicubic_Flag); )
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000380
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000381// source alpha tests -> S32A_Opaque_BlitRow32_{arm,neon}
mtklein@google.com410e6e82013-09-13 19:52:27 +0000382DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kOpaque_SourceAlpha, SkBitmap::kARGB_8888_Config); )
383DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTransparent_SourceAlpha, SkBitmap::kARGB_8888_Config); )
384DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTwoStripes_SourceAlpha, SkBitmap::kARGB_8888_Config); )
385DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kThreeStripes_SourceAlpha, SkBitmap::kARGB_8888_Config); )