blob: bd2ba685f22109842569299250c0166c4140f692 [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
16static const char* gTileName[] = {
17 "clamp", "repeat", "mirror"
18};
19
20static const char* gConfigName[] = {
21 "ERROR", "a1", "a8", "index8", "565", "4444", "8888"
22};
23
reed@android.comf523e252009-01-26 23:15:37 +000024static int conv6ToByte(int x) {
25 return x * 0xFF / 5;
26}
27
28static int convByteTo6(int x) {
29 return x * 5 / 255;
30}
31
32static uint8_t compute666Index(SkPMColor c) {
33 int r = SkGetPackedR32(c);
34 int g = SkGetPackedG32(c);
35 int b = SkGetPackedB32(c);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000036
reed@android.comf523e252009-01-26 23:15:37 +000037 return convByteTo6(r) * 36 + convByteTo6(g) * 6 + convByteTo6(b);
38}
39
40static void convertToIndex666(const SkBitmap& src, SkBitmap* dst) {
41 SkColorTable* ctable = new SkColorTable(216);
42 SkPMColor* colors = ctable->lockColors();
43 // rrr ggg bbb
44 for (int r = 0; r < 6; r++) {
45 int rr = conv6ToByte(r);
46 for (int g = 0; g < 6; g++) {
47 int gg = conv6ToByte(g);
48 for (int b = 0; b < 6; b++) {
49 int bb = conv6ToByte(b);
50 *colors++ = SkPreMultiplyARGB(0xFF, rr, gg, bb);
51 }
52 }
53 }
54 ctable->unlockColors(true);
55 dst->setConfig(SkBitmap::kIndex8_Config, src.width(), src.height());
56 dst->allocPixels(ctable);
57 ctable->unref();
rmistry@google.comfbfcd562012-08-23 18:09:54 +000058
reed@android.comf523e252009-01-26 23:15:37 +000059 SkAutoLockPixels alps(src);
60 SkAutoLockPixels alpd(*dst);
61
62 for (int y = 0; y < src.height(); y++) {
63 const SkPMColor* srcP = src.getAddr32(0, y);
64 uint8_t* dstP = dst->getAddr8(0, y);
65 for (int x = src.width() - 1; x >= 0; --x) {
66 *dstP++ = compute666Index(*srcP++);
67 }
68 }
69}
70
71/* Variants for bitmaps
rmistry@google.comfbfcd562012-08-23 18:09:54 +000072
reed@android.comf523e252009-01-26 23:15:37 +000073 - src depth (32 w+w/o alpha), 565, 4444, index, a8
74 - paint options: filtering, dither, alpha
75 - matrix options: translate, scale, rotate, persp
76 - tiling: none, repeat, mirror, clamp
rmistry@google.comfbfcd562012-08-23 18:09:54 +000077
reed@android.comf523e252009-01-26 23:15:37 +000078 */
79
80class BitmapBench : public SkBenchmark {
81 SkBitmap fBitmap;
82 SkPaint fPaint;
reed@android.com11ec1862009-10-19 19:01:45 +000083 bool fIsOpaque;
junov@google.com4ee7ae52011-06-30 17:30:49 +000084 bool fForceUpdate; //bitmap marked as dirty before each draw. forces bitmap to be updated on device cache
reed@android.comf523e252009-01-26 23:15:37 +000085 int fTileX, fTileY; // -1 means don't use shader
djsollen@google.comc2532dd2013-04-09 18:06:06 +000086 bool fIsVolatile;
87 SkBitmap::Config fConfig;
reed@android.comf523e252009-01-26 23:15:37 +000088 SkString fName;
tomhudson@google.comca529d32011-10-28 15:34:49 +000089 enum { N = SkBENCHLOOP(300) };
djsollen@google.comc2532dd2013-04-09 18:06:06 +000090 enum { W = 128 };
91 enum { H = 128 };
reed@android.comf523e252009-01-26 23:15:37 +000092public:
reed@android.com11ec1862009-10-19 19:01:45 +000093 BitmapBench(void* param, bool isOpaque, SkBitmap::Config c,
rmistry@google.comfbfcd562012-08-23 18:09:54 +000094 bool forceUpdate = false, bool bitmapVolatile = false,
reed@android.com11ec1862009-10-19 19:01:45 +000095 int tx = -1, int ty = -1)
djsollen@google.comc2532dd2013-04-09 18:06:06 +000096 : INHERITED(param)
97 , fIsOpaque(isOpaque)
98 , fForceUpdate(forceUpdate)
99 , fTileX(tx)
100 , fTileY(ty)
101 , fIsVolatile(bitmapVolatile)
102 , fConfig(c) {
reed@android.comf523e252009-01-26 23:15:37 +0000103 }
104
105protected:
106 virtual const char* onGetName() {
107 fName.set("bitmap");
108 if (fTileX >= 0) {
109 fName.appendf("_%s", gTileName[fTileX]);
110 if (fTileY != fTileX) {
111 fName.appendf("_%s", gTileName[fTileY]);
112 }
113 }
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000114 fName.appendf("_%s%s", gConfigName[fConfig],
reed@android.com11ec1862009-10-19 19:01:45 +0000115 fIsOpaque ? "" : "_A");
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000116 if (fForceUpdate)
junov@google.com4ee7ae52011-06-30 17:30:49 +0000117 fName.append("_update");
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000118 if (fIsVolatile)
junov@google.com4ee7ae52011-06-30 17:30:49 +0000119 fName.append("_volatile");
120
reed@android.comf523e252009-01-26 23:15:37 +0000121 return fName.c_str();
122 }
123
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000124 virtual void onPreDraw() {
125 SkBitmap bm;
126
127 if (SkBitmap::kIndex8_Config == fConfig) {
128 bm.setConfig(SkBitmap::kARGB_8888_Config, W, H);
129 } else {
130 bm.setConfig(fConfig, W, H);
131 }
132
133 bm.allocPixels();
134 bm.eraseColor(fIsOpaque ? SK_ColorBLACK : 0);
135
136 onDrawIntoBitmap(bm);
137
138 if (SkBitmap::kIndex8_Config == fConfig) {
139 convertToIndex666(bm, &fBitmap);
140 } else {
141 fBitmap = bm;
142 }
143
144 if (fBitmap.getColorTable()) {
145 fBitmap.getColorTable()->setIsOpaque(fIsOpaque);
146 }
147 fBitmap.setIsOpaque(fIsOpaque);
148 fBitmap.setIsVolatile(fIsVolatile);
149 }
150
reed@android.comf523e252009-01-26 23:15:37 +0000151 virtual void onDraw(SkCanvas* canvas) {
152 SkIPoint dim = this->getSize();
153 SkRandom rand;
154
155 SkPaint paint(fPaint);
156 this->setupPaint(&paint);
157
158 const SkBitmap& bitmap = fBitmap;
159 const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2);
160 const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000161
reed@android.comf523e252009-01-26 23:15:37 +0000162 for (int i = 0; i < N; i++) {
163 SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
164 SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
junov@google.com4ee7ae52011-06-30 17:30:49 +0000165
166 if (fForceUpdate)
167 bitmap.notifyPixelsChanged();
168
reed@android.comf523e252009-01-26 23:15:37 +0000169 canvas->drawBitmap(bitmap, x, y, &paint);
170 }
171 }
172
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000173 virtual void onDrawIntoBitmap(const SkBitmap& bm) {
174 const int w = bm.width();
175 const int h = bm.height();
176
177 SkCanvas canvas(bm);
178 SkPaint p;
179 p.setAntiAlias(true);
180 p.setColor(SK_ColorRED);
181 canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2,
182 SkIntToScalar(SkMin32(w, h))*3/8, p);
183
184 SkRect r;
185 r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
186 p.setStyle(SkPaint::kStroke_Style);
187 p.setStrokeWidth(SkIntToScalar(4));
188 p.setColor(SK_ColorBLUE);
189 canvas.drawRect(r, p);
190 }
191
reed@android.comf523e252009-01-26 23:15:37 +0000192private:
193 typedef SkBenchmark INHERITED;
194};
195
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000196/** Explicitly invoke some filter types to improve coverage of acceleration
197 procs. */
198
199class FilterBitmapBench : public BitmapBench {
200 bool fScale;
201 bool fRotate;
202 bool fFilter;
203 SkString fFullName;
204 enum { N = SkBENCHLOOP(300) };
205public:
206 FilterBitmapBench(void* param, bool isOpaque, SkBitmap::Config c,
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000207 bool forceUpdate = false, bool bitmapVolatile = false,
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000208 int tx = -1, int ty = -1, bool addScale = false,
209 bool addRotate = false, bool addFilter = false)
210 : INHERITED(param, isOpaque, c, forceUpdate, bitmapVolatile, tx, ty)
211 , fScale(addScale), fRotate(addRotate), fFilter(addFilter) {
212
213 }
214
215protected:
216 virtual const char* onGetName() {
217 fFullName.set(INHERITED::onGetName());
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000218 if (fScale)
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000219 fFullName.append("_scale");
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000220 if (fRotate)
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000221 fFullName.append("_rotate");
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000222 if (fFilter)
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000223 fFullName.append("_filter");
224
225 return fFullName.c_str();
226 }
227
228 virtual void onDraw(SkCanvas* canvas) {
229 SkISize dim = canvas->getDeviceSize();
230 if (fScale) {
231 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
232 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000233
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000234 canvas->translate(x, y);
235 // just enough so we can't take the sprite case
236 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
237 canvas->translate(-x, -y);
238 }
239 if (fRotate) {
240 const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
241 const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000242
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000243 canvas->translate(x, y);
244 canvas->rotate(SkIntToScalar(35));
245 canvas->translate(-x, -y);
246 }
247
248 this->setForceFilter(fFilter);
249 INHERITED::onDraw(canvas);
250 }
251
252private:
253 typedef BitmapBench INHERITED;
254};
255
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000256/** Verify optimizations that test source alpha values. */
257
258class SourceAlphaBitmapBench : public BitmapBench {
259public:
260 enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha,
261 kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha};
262private:
263 SkString fFullName;
264 SourceAlpha fSourceAlpha;
265public:
266 SourceAlphaBitmapBench(void* param, SourceAlpha alpha, SkBitmap::Config c,
267 bool forceUpdate = false, bool bitmapVolatile = false,
268 int tx = -1, int ty = -1)
269 : INHERITED(param, false, c, forceUpdate, bitmapVolatile, tx, ty)
270 , fSourceAlpha(alpha) {
271 }
272
273protected:
274 virtual const char* onGetName() {
275 fFullName.set(INHERITED::onGetName());
276
277 if (fSourceAlpha == kOpaque_SourceAlpha) {
278 fFullName.append("_source_opaque");
279 } else if (fSourceAlpha == kTransparent_SourceAlpha) {
280 fFullName.append("_source_transparent");
281 } else if (fSourceAlpha == kTwoStripes_SourceAlpha) {
282 fFullName.append("_source_stripes_two");
283 } else if (fSourceAlpha == kThreeStripes_SourceAlpha) {
284 fFullName.append("_source_stripes_three");
285 }
286
287 return fFullName.c_str();
288 }
289
290 virtual void onDrawIntoBitmap(const SkBitmap& bm) SK_OVERRIDE {
291 const int w = bm.width();
292 const int h = bm.height();
293
294 if (kOpaque_SourceAlpha == fSourceAlpha) {
295 bm.eraseColor(SK_ColorBLACK);
296 } else if (kTransparent_SourceAlpha == fSourceAlpha) {
297 bm.eraseColor(0);
298 } else if (kTwoStripes_SourceAlpha == fSourceAlpha) {
299 bm.eraseColor(0);
300
301 SkCanvas canvas(bm);
302 SkPaint p;
303 p.setAntiAlias(false);
304 p.setStyle(SkPaint::kFill_Style);
305 p.setColor(SK_ColorRED);
306
307 // Draw red vertical stripes on transparent background
308 SkRect r;
309 for (int x = 0; x < w; x+=2)
310 {
311 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
312 canvas.drawRect(r, p);
313 }
314
315 } else if (kThreeStripes_SourceAlpha == fSourceAlpha) {
316 bm.eraseColor(0);
317
318 SkCanvas canvas(bm);
319 SkPaint p;
320 p.setAntiAlias(false);
321 p.setStyle(SkPaint::kFill_Style);
322
323 // Draw vertical stripes on transparent background with a pattern
324 // where the first pixel is fully transparent, the next is semi-transparent
325 // and the third is fully opaque.
326 SkRect r;
327 for (int x = 0; x < w; x++)
328 {
329 if (x % 3 == 0) {
330 continue; // Keep transparent
331 } else if (x % 3 == 1) {
332 p.setColor(SkColorSetARGB(127, 127, 127, 127)); // Semi-transparent
333 } else if (x % 3 == 2) {
334 p.setColor(SK_ColorRED); // Opaque
335 }
336 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
337 canvas.drawRect(r, p);
338 }
339 }
340 }
341
342private:
343 typedef BitmapBench INHERITED;
344};
reed@android.com11ec1862009-10-19 19:01:45 +0000345static SkBenchmark* Fact0(void* p) { return new BitmapBench(p, false, SkBitmap::kARGB_8888_Config); }
346static SkBenchmark* Fact1(void* p) { return new BitmapBench(p, true, SkBitmap::kARGB_8888_Config); }
347static SkBenchmark* Fact2(void* p) { return new BitmapBench(p, true, SkBitmap::kRGB_565_Config); }
348static SkBenchmark* Fact3(void* p) { return new BitmapBench(p, false, SkBitmap::kARGB_4444_Config); }
349static SkBenchmark* Fact4(void* p) { return new BitmapBench(p, true, SkBitmap::kARGB_4444_Config); }
350static SkBenchmark* Fact5(void* p) { return new BitmapBench(p, false, SkBitmap::kIndex8_Config); }
351static SkBenchmark* Fact6(void* p) { return new BitmapBench(p, true, SkBitmap::kIndex8_Config); }
junov@google.com4ee7ae52011-06-30 17:30:49 +0000352static SkBenchmark* Fact7(void* p) { return new BitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, true); }
353static SkBenchmark* Fact8(void* p) { return new BitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, false); }
reed@android.comf523e252009-01-26 23:15:37 +0000354
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000355// scale filter -> S32_opaque_D32_filter_DX_{SSE2,SSSE3} and Fact9 is also for S32_D16_filter_DX_SSE2
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000356static SkBenchmark* Fact9(void* p) { return new FilterBitmapBench(p, false, SkBitmap::kARGB_8888_Config, false, false, -1, -1, true, false, true); }
357static SkBenchmark* Fact10(void* p) { return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, false, false, -1, -1, true, false, true); }
358static SkBenchmark* Fact11(void* p) { return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, true, -1, -1, true, false, true); }
359static SkBenchmark* Fact12(void* p) { return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, false, -1, -1, true, false, true); }
360
361// scale rotate filter -> S32_opaque_D32_filter_DXDY_{SSE2,SSSE3}
362static SkBenchmark* Fact13(void* p) { return new FilterBitmapBench(p, false, SkBitmap::kARGB_8888_Config, false, false, -1, -1, true, true, true); }
363static SkBenchmark* Fact14(void* p) { return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, false, false, -1, -1, true, true, true); }
364static SkBenchmark* Fact15(void* p) { return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, true, -1, -1, true, true, true); }
365static SkBenchmark* Fact16(void* p) { return new FilterBitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, false, -1, -1, true, true, true); }
366
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000367// source alpha tests -> S32A_Opaque_BlitRow32_{arm,neon}
368static SkBenchmark* Fact17(void* p) { return new SourceAlphaBitmapBench(p, SourceAlphaBitmapBench::kOpaque_SourceAlpha, SkBitmap::kARGB_8888_Config); }
369static SkBenchmark* Fact18(void* p) { return new SourceAlphaBitmapBench(p, SourceAlphaBitmapBench::kTransparent_SourceAlpha, SkBitmap::kARGB_8888_Config); }
370static SkBenchmark* Fact19(void* p) { return new SourceAlphaBitmapBench(p, SourceAlphaBitmapBench::kTwoStripes_SourceAlpha, SkBitmap::kARGB_8888_Config); }
371static SkBenchmark* Fact20(void* p) { return new SourceAlphaBitmapBench(p, SourceAlphaBitmapBench::kThreeStripes_SourceAlpha, SkBitmap::kARGB_8888_Config); }
372
reed@android.comf523e252009-01-26 23:15:37 +0000373static BenchRegistry gReg0(Fact0);
374static BenchRegistry gReg1(Fact1);
375static BenchRegistry gReg2(Fact2);
376static BenchRegistry gReg3(Fact3);
reed@android.com11ec1862009-10-19 19:01:45 +0000377static BenchRegistry gReg4(Fact4);
378static BenchRegistry gReg5(Fact5);
379static BenchRegistry gReg6(Fact6);
junov@google.com4ee7ae52011-06-30 17:30:49 +0000380static BenchRegistry gReg7(Fact7);
381static BenchRegistry gReg8(Fact8);
tomhudson@google.comc3be34d2012-05-15 20:09:33 +0000382
383static BenchRegistry gReg9(Fact9);
384static BenchRegistry gReg10(Fact10);
385static BenchRegistry gReg11(Fact11);
386static BenchRegistry gReg12(Fact12);
387
388static BenchRegistry gReg13(Fact13);
389static BenchRegistry gReg14(Fact14);
390static BenchRegistry gReg15(Fact15);
391static BenchRegistry gReg16(Fact16);
djsollen@google.comc2532dd2013-04-09 18:06:06 +0000392
393static BenchRegistry gReg17(Fact17);
394static BenchRegistry gReg18(Fact18);
395static BenchRegistry gReg19(Fact19);
396static BenchRegistry gReg20(Fact20);