blob: 698a680e9cb76ce21e079b199258e12858f0e594 [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:
reed@android.com11ec1862009-10-19 19:01:45 +000087 BitmapBench(void* param, bool isOpaque, SkBitmap::Config c,
reed@google.comef77ec22013-05-29 15:39:54 +000088 bool forceUpdate = false, bool bitmapVolatile = false)
djsollen@google.comc2532dd2013-04-09 18:06:06 +000089 : INHERITED(param)
90 , fIsOpaque(isOpaque)
91 , 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) {
124 convertToIndex666(bm, &fBitmap);
125 } else {
126 fBitmap = bm;
127 }
128
129 if (fBitmap.getColorTable()) {
130 fBitmap.getColorTable()->setIsOpaque(fIsOpaque);
131 }
132 fBitmap.setIsOpaque(fIsOpaque);
133 fBitmap.setIsVolatile(fIsVolatile);
134 }
135
reed@android.comf523e252009-01-26 23:15:37 +0000136 virtual void onDraw(SkCanvas* canvas) {
137 SkIPoint dim = this->getSize();
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000138 SkRandom rand;
reed@android.comf523e252009-01-26 23:15:37 +0000139
140 SkPaint paint(fPaint);
141 this->setupPaint(&paint);
142
143 const SkBitmap& bitmap = fBitmap;
144 const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2);
145 const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000146
mtklein@google.comc2897432013-09-10 19:23:38 +0000147 for (int i = 0; i < this->getLoops(); i++) {
reed@android.comf523e252009-01-26 23:15:37 +0000148 SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
149 SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
junov@google.com4ee7ae52011-06-30 17:30:49 +0000150
151 if (fForceUpdate)
152 bitmap.notifyPixelsChanged();
153
reed@android.comf523e252009-01-26 23:15:37 +0000154 canvas->drawBitmap(bitmap, x, y, &paint);
155 }
156 }
157
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000158 virtual void onDrawIntoBitmap(const SkBitmap& bm) {
159 const int w = bm.width();
160 const int h = bm.height();
161
162 SkCanvas canvas(bm);
163 SkPaint p;
164 p.setAntiAlias(true);
165 p.setColor(SK_ColorRED);
166 canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2,
167 SkIntToScalar(SkMin32(w, h))*3/8, p);
168
169 SkRect r;
170 r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
171 p.setStyle(SkPaint::kStroke_Style);
172 p.setStrokeWidth(SkIntToScalar(4));
173 p.setColor(SK_ColorBLUE);
174 canvas.drawRect(r, p);
175 }
176
reed@android.comf523e252009-01-26 23:15:37 +0000177private:
178 typedef SkBenchmark INHERITED;
179};
180
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000181/** Explicitly invoke some filter types to improve coverage of acceleration
182 procs. */
183
reed@google.comef77ec22013-05-29 15:39:54 +0000184enum Flags {
185 kScale_Flag = 1 << 0,
186 kRotate_Flag = 1 << 1,
187 kBilerp_Flag = 1 << 2,
188 kBicubic_Flag = 1 << 3,
189};
190
191static bool isBilerp(uint32_t flags) {
192 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag);
193}
194
195static bool isBicubic(uint32_t flags) {
196 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag | kBicubic_Flag);
197}
198
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000199class FilterBitmapBench : public BitmapBench {
reed@google.comef77ec22013-05-29 15:39:54 +0000200 uint32_t fFlags;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000201 SkString fFullName;
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000202public:
203 FilterBitmapBench(void* param, bool isOpaque, SkBitmap::Config c,
reed@google.comef77ec22013-05-29 15:39:54 +0000204 bool forceUpdate, bool isVolitile, uint32_t flags)
205 : INHERITED(param, isOpaque, c, forceUpdate, isVolitile)
206 , fFlags(flags) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000207 }
208
209protected:
210 virtual const char* onGetName() {
211 fFullName.set(INHERITED::onGetName());
reed@google.comef77ec22013-05-29 15:39:54 +0000212 if (fFlags & kScale_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000213 fFullName.append("_scale");
reed@google.comef77ec22013-05-29 15:39:54 +0000214 }
215 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000216 fFullName.append("_rotate");
reed@google.comef77ec22013-05-29 15:39:54 +0000217 }
218 if (isBilerp(fFlags)) {
219 fFullName.append("_bilerp");
220 } else if (isBicubic(fFlags)) {
221 fFullName.append("_bicubic");
222 }
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000223
224 return fFullName.c_str();
225 }
226
227 virtual void onDraw(SkCanvas* canvas) {
228 SkISize dim = canvas->getDeviceSize();
reed@google.comef77ec22013-05-29 15:39:54 +0000229 if (fFlags & kScale_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 // just enough so we can't take the sprite case
235 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
236 canvas->translate(-x, -y);
237 }
reed@google.comef77ec22013-05-29 15:39:54 +0000238 if (fFlags & kRotate_Flag) {
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000239 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
240 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000241
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000242 canvas->translate(x, y);
243 canvas->rotate(SkIntToScalar(35));
244 canvas->translate(-x, -y);
245 }
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000246 INHERITED::onDraw(canvas);
247 }
248
reed@google.com9cfc83c2013-07-22 17:18:18 +0000249 virtual void setupPaint(SkPaint* paint) SK_OVERRIDE {
250 this->INHERITED::setupPaint(paint);
251
252 int index = 0;
253 if (fFlags & kBilerp_Flag) {
254 index |= 1;
255 }
256 if (fFlags & kBicubic_Flag) {
257 index |= 2;
258 }
259 static const SkPaint::FilterLevel gLevels[] = {
260 SkPaint::kNone_FilterLevel,
261 SkPaint::kLow_FilterLevel,
262 SkPaint::kMedium_FilterLevel,
263 SkPaint::kHigh_FilterLevel
264 };
265 paint->setFilterLevel(gLevels[index]);
266}
267
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000268private:
269 typedef BitmapBench INHERITED;
270};
271
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000272/** Verify optimizations that test source alpha values. */
273
274class SourceAlphaBitmapBench : public BitmapBench {
275public:
276 enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha,
277 kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha};
278private:
279 SkString fFullName;
280 SourceAlpha fSourceAlpha;
281public:
282 SourceAlphaBitmapBench(void* param, SourceAlpha alpha, SkBitmap::Config c,
reed@google.comef77ec22013-05-29 15:39:54 +0000283 bool forceUpdate = false, bool bitmapVolatile = false)
284 : INHERITED(param, false, c, forceUpdate, bitmapVolatile)
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000285 , fSourceAlpha(alpha) {
286 }
287
288protected:
289 virtual const char* onGetName() {
290 fFullName.set(INHERITED::onGetName());
291
292 if (fSourceAlpha == kOpaque_SourceAlpha) {
293 fFullName.append("_source_opaque");
294 } else if (fSourceAlpha == kTransparent_SourceAlpha) {
295 fFullName.append("_source_transparent");
296 } else if (fSourceAlpha == kTwoStripes_SourceAlpha) {
297 fFullName.append("_source_stripes_two");
298 } else if (fSourceAlpha == kThreeStripes_SourceAlpha) {
299 fFullName.append("_source_stripes_three");
300 }
301
302 return fFullName.c_str();
303 }
304
305 virtual void onDrawIntoBitmap(const SkBitmap& bm) SK_OVERRIDE {
306 const int w = bm.width();
307 const int h = bm.height();
308
309 if (kOpaque_SourceAlpha == fSourceAlpha) {
310 bm.eraseColor(SK_ColorBLACK);
311 } else if (kTransparent_SourceAlpha == fSourceAlpha) {
312 bm.eraseColor(0);
313 } else if (kTwoStripes_SourceAlpha == fSourceAlpha) {
314 bm.eraseColor(0);
315
316 SkCanvas canvas(bm);
317 SkPaint p;
318 p.setAntiAlias(false);
319 p.setStyle(SkPaint::kFill_Style);
320 p.setColor(SK_ColorRED);
321
322 // Draw red vertical stripes on transparent background
323 SkRect r;
324 for (int x = 0; x < w; x+=2)
325 {
326 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
327 canvas.drawRect(r, p);
328 }
329
330 } else if (kThreeStripes_SourceAlpha == fSourceAlpha) {
331 bm.eraseColor(0);
332
333 SkCanvas canvas(bm);
334 SkPaint p;
335 p.setAntiAlias(false);
336 p.setStyle(SkPaint::kFill_Style);
337
338 // Draw vertical stripes on transparent background with a pattern
339 // where the first pixel is fully transparent, the next is semi-transparent
340 // and the third is fully opaque.
341 SkRect r;
342 for (int x = 0; x < w; x++)
343 {
344 if (x % 3 == 0) {
345 continue; // Keep transparent
346 } else if (x % 3 == 1) {
347 p.setColor(SkColorSetARGB(127, 127, 127, 127)); // Semi-transparent
348 } else if (x % 3 == 2) {
349 p.setColor(SK_ColorRED); // Opaque
350 }
351 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
352 canvas.drawRect(r, p);
353 }
354 }
355 }
356
357private:
358 typedef BitmapBench INHERITED;
359};
reed@google.com2ece2872013-05-28 20:48:14 +0000360
361DEF_BENCH( return new BitmapBench(p, false, SkBitmap::kARGB_8888_Config); )
362DEF_BENCH( return new BitmapBench(p, true, SkBitmap::kARGB_8888_Config); )
363DEF_BENCH( return new BitmapBench(p, true, SkBitmap::kRGB_565_Config); )
reed@google.com2ece2872013-05-28 20:48:14 +0000364DEF_BENCH( return new BitmapBench(p, false, SkBitmap::kIndex8_Config); )
365DEF_BENCH( return new BitmapBench(p, true, SkBitmap::kIndex8_Config); )
366DEF_BENCH( return new BitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, true); )
367DEF_BENCH( return new BitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, false); )
reed@android.comf523e252009-01-26 23:15:37 +0000368
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000369// scale filter -> S32_opaque_D32_filter_DX_{SSE2,SSSE3} and Fact9 is also for S32_D16_filter_DX_SSE2
reed@google.comef77ec22013-05-29 15:39:54 +0000370DEF_BENCH( return new FilterBitmapBench(p, false, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kBilerp_Flag); )
371DEF_BENCH( return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kBilerp_Flag); )
372DEF_BENCH( return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, true, kScale_Flag | kBilerp_Flag); )
373DEF_BENCH( return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, false, kScale_Flag | kBilerp_Flag); )
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000374
375// scale rotate filter -> S32_opaque_D32_filter_DXDY_{SSE2,SSSE3}
reed@google.comef77ec22013-05-29 15:39:54 +0000376DEF_BENCH( return new FilterBitmapBench(p, false, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
377DEF_BENCH( return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
378DEF_BENCH( return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, true, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
379DEF_BENCH( return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
380
381DEF_BENCH( return new FilterBitmapBench(p, false, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kBilerp_Flag | kBicubic_Flag); )
382DEF_BENCH( return new FilterBitmapBench(p, false, SkBitmap::kARGB_8888_Config, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag | kBicubic_Flag); )
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000383
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000384// source alpha tests -> S32A_Opaque_BlitRow32_{arm,neon}
reed@google.com2ece2872013-05-28 20:48:14 +0000385DEF_BENCH( return new SourceAlphaBitmapBench(p, SourceAlphaBitmapBench::kOpaque_SourceAlpha, SkBitmap::kARGB_8888_Config); )
386DEF_BENCH( return new SourceAlphaBitmapBench(p, SourceAlphaBitmapBench::kTransparent_SourceAlpha, SkBitmap::kARGB_8888_Config); )
387DEF_BENCH( return new SourceAlphaBitmapBench(p, SourceAlphaBitmapBench::kTwoStripes_SourceAlpha, SkBitmap::kARGB_8888_Config); )
388DEF_BENCH( return new SourceAlphaBitmapBench(p, SourceAlphaBitmapBench::kThreeStripes_SourceAlpha, SkBitmap::kARGB_8888_Config); )