blob: 9b3a6a29dd082cf236a4259c8c743312e27b947e [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
36static void convertToIndex666(const SkBitmap& src, SkBitmap* dst) {
37 SkColorTable* ctable = new SkColorTable(216);
38 SkPMColor* colors = ctable->lockColors();
39 // 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 }
50 ctable->unlockColors(true);
51 dst->setConfig(SkBitmap::kIndex8_Config, src.width(), src.height());
52 dst->allocPixels(ctable);
53 ctable->unref();
rmistry@google.comfbfcd562012-08-23 18:09:54 +000054
reed@android.comf523e252009-01-26 23:15:37 +000055 SkAutoLockPixels alps(src);
56 SkAutoLockPixels alpd(*dst);
57
58 for (int y = 0; y < src.height(); y++) {
59 const SkPMColor* srcP = src.getAddr32(0, y);
60 uint8_t* dstP = dst->getAddr8(0, y);
61 for (int x = src.width() - 1; x >= 0; --x) {
62 *dstP++ = compute666Index(*srcP++);
63 }
64 }
65}
66
67/* Variants for bitmaps
rmistry@google.comfbfcd562012-08-23 18:09:54 +000068
reed@android.comf523e252009-01-26 23:15:37 +000069 - src depth (32 w+w/o alpha), 565, 4444, index, a8
70 - paint options: filtering, dither, alpha
71 - matrix options: translate, scale, rotate, persp
72 - tiling: none, repeat, mirror, clamp
rmistry@google.comfbfcd562012-08-23 18:09:54 +000073
reed@android.comf523e252009-01-26 23:15:37 +000074 */
75
76class BitmapBench : public SkBenchmark {
77 SkBitmap fBitmap;
78 SkPaint fPaint;
reed@android.com11ec1862009-10-19 19:01:45 +000079 bool fIsOpaque;
junov@google.com4ee7ae52011-06-30 17:30:49 +000080 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 +000081 bool fIsVolatile;
82 SkBitmap::Config fConfig;
reed@android.comf523e252009-01-26 23:15:37 +000083 SkString fName;
djsollen@google.comc2532dd2013-04-09 18:06:06 +000084 enum { W = 128 };
85 enum { H = 128 };
reed@android.comf523e252009-01-26 23:15:37 +000086public:
mtklein@google.com410e6e82013-09-13 19:52:27 +000087 BitmapBench(bool isOpaque, SkBitmap::Config c,
reed@google.comef77ec22013-05-29 15:39:54 +000088 bool forceUpdate = false, bool bitmapVolatile = false)
mtklein@google.com410e6e82013-09-13 19:52:27 +000089 : fIsOpaque(isOpaque)
djsollen@google.comc2532dd2013-04-09 18:06:06 +000090 , fForceUpdate(forceUpdate)
djsollen@google.comc2532dd2013-04-09 18:06:06 +000091 , fIsVolatile(bitmapVolatile)
92 , fConfig(c) {
reed@android.comf523e252009-01-26 23:15:37 +000093 }
94
95protected:
96 virtual const char* onGetName() {
97 fName.set("bitmap");
djsollen@google.comc2532dd2013-04-09 18:06:06 +000098 fName.appendf("_%s%s", gConfigName[fConfig],
reed@android.com11ec1862009-10-19 19:01:45 +000099 fIsOpaque ? "" : "_A");
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000100 if (fForceUpdate)
junov@google.com4ee7ae52011-06-30 17:30:49 +0000101 fName.append("_update");
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000102 if (fIsVolatile)
junov@google.com4ee7ae52011-06-30 17:30:49 +0000103 fName.append("_volatile");
104
reed@android.comf523e252009-01-26 23:15:37 +0000105 return fName.c_str();
106 }
107
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000108 virtual void onPreDraw() {
109 SkBitmap bm;
110
111 if (SkBitmap::kIndex8_Config == fConfig) {
112 bm.setConfig(SkBitmap::kARGB_8888_Config, W, H);
113 } else {
114 bm.setConfig(fConfig, W, H);
115 }
116
117 bm.allocPixels();
118 bm.eraseColor(fIsOpaque ? SK_ColorBLACK : 0);
119
120 onDrawIntoBitmap(bm);
121
122 if (SkBitmap::kIndex8_Config == fConfig) {
123 convertToIndex666(bm, &fBitmap);
124 } else {
125 fBitmap = bm;
126 }
127
128 if (fBitmap.getColorTable()) {
129 fBitmap.getColorTable()->setIsOpaque(fIsOpaque);
130 }
131 fBitmap.setIsOpaque(fIsOpaque);
132 fBitmap.setIsVolatile(fIsVolatile);
133 }
134
reed@android.comf523e252009-01-26 23:15:37 +0000135 virtual void onDraw(SkCanvas* canvas) {
136 SkIPoint dim = this->getSize();
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000137 SkRandom rand;
reed@android.comf523e252009-01-26 23:15:37 +0000138
139 SkPaint paint(fPaint);
140 this->setupPaint(&paint);
141
142 const SkBitmap& bitmap = fBitmap;
143 const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2);
144 const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000145
mtklein@google.comc2897432013-09-10 19:23:38 +0000146 for (int i = 0; i < this->getLoops(); i++) {
reed@android.comf523e252009-01-26 23:15:37 +0000147 SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
148 SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
junov@google.com4ee7ae52011-06-30 17:30:49 +0000149
150 if (fForceUpdate)
151 bitmap.notifyPixelsChanged();
152
reed@android.comf523e252009-01-26 23:15:37 +0000153 canvas->drawBitmap(bitmap, x, y, &paint);
154 }
155 }
156
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000157 virtual void onDrawIntoBitmap(const SkBitmap& bm) {
158 const int w = bm.width();
159 const int h = bm.height();
160
161 SkCanvas canvas(bm);
162 SkPaint p;
163 p.setAntiAlias(true);
164 p.setColor(SK_ColorRED);
165 canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2,
166 SkIntToScalar(SkMin32(w, h))*3/8, p);
167
168 SkRect r;
169 r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
170 p.setStyle(SkPaint::kStroke_Style);
171 p.setStrokeWidth(SkIntToScalar(4));
172 p.setColor(SK_ColorBLUE);
173 canvas.drawRect(r, p);
174 }
175
reed@android.comf523e252009-01-26 23:15:37 +0000176private:
177 typedef SkBenchmark INHERITED;
178};
179
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000180/** Explicitly invoke some filter types to improve coverage of acceleration
181 procs. */
182
reed@google.comef77ec22013-05-29 15:39:54 +0000183enum Flags {
184 kScale_Flag = 1 << 0,
185 kRotate_Flag = 1 << 1,
186 kBilerp_Flag = 1 << 2,
187 kBicubic_Flag = 1 << 3,
188};
189
190static bool isBilerp(uint32_t flags) {
191 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag);
192}
193
194static bool isBicubic(uint32_t flags) {
195 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag | kBicubic_Flag);
196}
197
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000198class FilterBitmapBench : public BitmapBench {
reed@google.comef77ec22013-05-29 15:39:54 +0000199 uint32_t fFlags;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000200 SkString fFullName;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000201public:
mtklein@google.com410e6e82013-09-13 19:52:27 +0000202 FilterBitmapBench(bool isOpaque, SkBitmap::Config c,
reed@google.comef77ec22013-05-29 15:39:54 +0000203 bool forceUpdate, bool isVolitile, uint32_t flags)
mtklein@google.com410e6e82013-09-13 19:52:27 +0000204 : INHERITED(isOpaque, c, forceUpdate, isVolitile)
reed@google.comef77ec22013-05-29 15:39:54 +0000205 , fFlags(flags) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000206 }
207
208protected:
209 virtual const char* onGetName() {
210 fFullName.set(INHERITED::onGetName());
reed@google.comef77ec22013-05-29 15:39:54 +0000211 if (fFlags & kScale_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000212 fFullName.append("_scale");
reed@google.comef77ec22013-05-29 15:39:54 +0000213 }
214 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000215 fFullName.append("_rotate");
reed@google.comef77ec22013-05-29 15:39:54 +0000216 }
217 if (isBilerp(fFlags)) {
218 fFullName.append("_bilerp");
219 } else if (isBicubic(fFlags)) {
220 fFullName.append("_bicubic");
221 }
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000222
223 return fFullName.c_str();
224 }
225
226 virtual void onDraw(SkCanvas* canvas) {
227 SkISize dim = canvas->getDeviceSize();
reed@google.comef77ec22013-05-29 15:39:54 +0000228 if (fFlags & kScale_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000229 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
230 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000231
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000232 canvas->translate(x, y);
233 // just enough so we can't take the sprite case
234 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
235 canvas->translate(-x, -y);
236 }
reed@google.comef77ec22013-05-29 15:39:54 +0000237 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000238 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
239 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000240
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000241 canvas->translate(x, y);
242 canvas->rotate(SkIntToScalar(35));
243 canvas->translate(-x, -y);
244 }
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000245 INHERITED::onDraw(canvas);
246 }
247
reed@google.com9cfc83c2013-07-22 17:18:18 +0000248 virtual void setupPaint(SkPaint* paint) SK_OVERRIDE {
249 this->INHERITED::setupPaint(paint);
250
251 int index = 0;
252 if (fFlags & kBilerp_Flag) {
253 index |= 1;
254 }
255 if (fFlags & kBicubic_Flag) {
256 index |= 2;
257 }
258 static const SkPaint::FilterLevel gLevels[] = {
259 SkPaint::kNone_FilterLevel,
260 SkPaint::kLow_FilterLevel,
261 SkPaint::kMedium_FilterLevel,
262 SkPaint::kHigh_FilterLevel
263 };
264 paint->setFilterLevel(gLevels[index]);
265}
266
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000267private:
268 typedef BitmapBench INHERITED;
269};
270
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000271/** Verify optimizations that test source alpha values. */
272
273class SourceAlphaBitmapBench : public BitmapBench {
274public:
275 enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha,
276 kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha};
277private:
278 SkString fFullName;
279 SourceAlpha fSourceAlpha;
280public:
mtklein@google.com410e6e82013-09-13 19:52:27 +0000281 SourceAlphaBitmapBench(SourceAlpha alpha, SkBitmap::Config c,
reed@google.comef77ec22013-05-29 15:39:54 +0000282 bool forceUpdate = false, bool bitmapVolatile = false)
mtklein@google.com410e6e82013-09-13 19:52:27 +0000283 : INHERITED(false, c, forceUpdate, bitmapVolatile)
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000284 , fSourceAlpha(alpha) {
285 }
286
287protected:
288 virtual const char* onGetName() {
289 fFullName.set(INHERITED::onGetName());
290
291 if (fSourceAlpha == kOpaque_SourceAlpha) {
292 fFullName.append("_source_opaque");
293 } else if (fSourceAlpha == kTransparent_SourceAlpha) {
294 fFullName.append("_source_transparent");
295 } else if (fSourceAlpha == kTwoStripes_SourceAlpha) {
296 fFullName.append("_source_stripes_two");
297 } else if (fSourceAlpha == kThreeStripes_SourceAlpha) {
298 fFullName.append("_source_stripes_three");
299 }
300
301 return fFullName.c_str();
302 }
303
304 virtual void onDrawIntoBitmap(const SkBitmap& bm) SK_OVERRIDE {
305 const int w = bm.width();
306 const int h = bm.height();
307
308 if (kOpaque_SourceAlpha == fSourceAlpha) {
309 bm.eraseColor(SK_ColorBLACK);
310 } else if (kTransparent_SourceAlpha == fSourceAlpha) {
311 bm.eraseColor(0);
312 } else if (kTwoStripes_SourceAlpha == fSourceAlpha) {
313 bm.eraseColor(0);
314
315 SkCanvas canvas(bm);
316 SkPaint p;
317 p.setAntiAlias(false);
318 p.setStyle(SkPaint::kFill_Style);
319 p.setColor(SK_ColorRED);
320
321 // Draw red vertical stripes on transparent background
322 SkRect r;
323 for (int x = 0; x < w; x+=2)
324 {
325 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
326 canvas.drawRect(r, p);
327 }
328
329 } else if (kThreeStripes_SourceAlpha == fSourceAlpha) {
330 bm.eraseColor(0);
331
332 SkCanvas canvas(bm);
333 SkPaint p;
334 p.setAntiAlias(false);
335 p.setStyle(SkPaint::kFill_Style);
336
337 // Draw vertical stripes on transparent background with a pattern
338 // where the first pixel is fully transparent, the next is semi-transparent
339 // and the third is fully opaque.
340 SkRect r;
341 for (int x = 0; x < w; x++)
342 {
343 if (x % 3 == 0) {
344 continue; // Keep transparent
345 } else if (x % 3 == 1) {
346 p.setColor(SkColorSetARGB(127, 127, 127, 127)); // Semi-transparent
347 } else if (x % 3 == 2) {
348 p.setColor(SK_ColorRED); // Opaque
349 }
350 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
351 canvas.drawRect(r, p);
352 }
353 }
354 }
355
356private:
357 typedef BitmapBench INHERITED;
358};
reed@google.com2ece2872013-05-28 20:48:14 +0000359
mtklein@google.com410e6e82013-09-13 19:52:27 +0000360DEF_BENCH( return new BitmapBench(false, SkBitmap::kARGB_8888_Config); )
361DEF_BENCH( return new BitmapBench(true, SkBitmap::kARGB_8888_Config); )
362DEF_BENCH( return new BitmapBench(true, SkBitmap::kRGB_565_Config); )
363DEF_BENCH( return new BitmapBench(false, SkBitmap::kIndex8_Config); )
364DEF_BENCH( return new BitmapBench(true, SkBitmap::kIndex8_Config); )
365DEF_BENCH( return new BitmapBench(true, SkBitmap::kARGB_8888_Config, true, true); )
366DEF_BENCH( return new BitmapBench(true, SkBitmap::kARGB_8888_Config, true, false); )
reed@android.comf523e252009-01-26 23:15:37 +0000367
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000368// 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 +0000369DEF_BENCH( return new FilterBitmapBench(false, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kBilerp_Flag); )
370DEF_BENCH( return new FilterBitmapBench(true, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kBilerp_Flag); )
371DEF_BENCH( return new FilterBitmapBench(true, SkBitmap::kARGB_8888_Config, true, true, kScale_Flag | kBilerp_Flag); )
372DEF_BENCH( return new FilterBitmapBench(true, SkBitmap::kARGB_8888_Config, true, false, kScale_Flag | kBilerp_Flag); )
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000373
374// scale rotate filter -> S32_opaque_D32_filter_DXDY_{SSE2,SSSE3}
mtklein@google.com410e6e82013-09-13 19:52:27 +0000375DEF_BENCH( return new FilterBitmapBench(false, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
376DEF_BENCH( return new FilterBitmapBench(true, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
377DEF_BENCH( return new FilterBitmapBench(true, SkBitmap::kARGB_8888_Config, true, true, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
378DEF_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 +0000379
mtklein@google.com410e6e82013-09-13 19:52:27 +0000380DEF_BENCH( return new FilterBitmapBench(false, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kBilerp_Flag | kBicubic_Flag); )
381DEF_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 +0000382
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000383// source alpha tests -> S32A_Opaque_BlitRow32_{arm,neon}
mtklein@google.com410e6e82013-09-13 19:52:27 +0000384DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kOpaque_SourceAlpha, SkBitmap::kARGB_8888_Config); )
385DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTransparent_SourceAlpha, SkBitmap::kARGB_8888_Config); )
386DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTwoStripes_SourceAlpha, SkBitmap::kARGB_8888_Config); )
387DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kThreeStripes_SourceAlpha, SkBitmap::kARGB_8888_Config); )