deprecate odd variants of SkCanvas::readPixels
[platform/upstream/libSkiaSharp.git] / bench / BitmapBench.cpp
1 /*
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  */
7
8 #include "Benchmark.h"
9 #include "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkColorPriv.h"
12 #include "SkPaint.h"
13 #include "SkRandom.h"
14 #include "SkString.h"
15 #include "sk_tool_utils.h"
16
17 static int conv6ToByte(int x) {
18     return x * 0xFF / 5;
19 }
20
21 static int convByteTo6(int x) {
22     return x * 5 / 255;
23 }
24
25 static uint8_t compute666Index(SkPMColor c) {
26     int r = SkGetPackedR32(c);
27     int g = SkGetPackedG32(c);
28     int b = SkGetPackedB32(c);
29
30     return convByteTo6(r) * 36 + convByteTo6(g) * 6 + convByteTo6(b);
31 }
32
33 static void convertToIndex666(const SkBitmap& src, SkBitmap* dst, SkAlphaType aType) {
34     SkPMColor storage[216];
35     SkPMColor* colors = storage;
36     // 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     }
47     dst->allocPixels(SkImageInfo::Make(src.width(), src.height(), kIndex_8_SkColorType, aType),
48                      SkColorTable::Make(storage, 216));
49
50     SkAutoLockPixels alps(src);
51     SkAutoLockPixels alpd(*dst);
52
53     for (int y = 0; y < src.height(); y++) {
54         const SkPMColor* srcP = src.getAddr32(0, y);
55         uint8_t* dstP = dst->getAddr8(0, y);
56         for (int x = src.width() - 1; x >= 0; --x) {
57             *dstP++ = compute666Index(*srcP++);
58         }
59     }
60 }
61
62 /*  Variants for bitmaps
63
64     - src depth (32 w+w/o alpha), 565, 4444, index, a8
65     - paint options: filtering, dither, alpha
66     - matrix options: translate, scale, rotate, persp
67     - tiling: none, repeat, mirror, clamp
68
69  */
70
71 class BitmapBench : public Benchmark {
72     const SkColorType   fColorType;
73     const SkAlphaType   fAlphaType;
74     const bool          fForceUpdate; //bitmap marked as dirty before each draw. forces bitmap to be updated on device cache
75     const bool          fIsVolatile;
76     const bool          fDoScale;
77
78     SkBitmap            fBitmap;
79     SkPaint             fPaint;
80     SkString            fName;
81
82     enum { W = 128 };
83     enum { H = 128 };
84 public:
85     BitmapBench(SkColorType ct, SkAlphaType at, bool forceUpdate, bool isVolatile, bool doScale)
86         : fColorType(ct)
87         , fAlphaType(at)
88         , fForceUpdate(forceUpdate)
89         , fIsVolatile(isVolatile)
90         , fDoScale(doScale)
91     {}
92
93 protected:
94     const char* onGetName() override {
95         fName.set("bitmap");
96         fName.appendf("_%s%s", sk_tool_utils::colortype_name(fColorType),
97                       kOpaque_SkAlphaType == fAlphaType ? "" : "_A");
98         if (fDoScale) {
99             fName.append("_scale");
100         }
101         if (fForceUpdate) {
102             fName.append("_update");
103         }
104         if (fIsVolatile) {
105             fName.append("_volatile");
106         }
107
108         return fName.c_str();
109     }
110
111     void onDelayedSetup() override {
112         SkBitmap bm;
113
114         if (kIndex_8_SkColorType == fColorType) {
115             bm.allocPixels(SkImageInfo::MakeN32(W, H, fAlphaType));
116         } else {
117             bm.allocPixels(SkImageInfo::Make(W, H, fColorType, fAlphaType));
118         }
119         bm.eraseColor(kOpaque_SkAlphaType == fAlphaType ? SK_ColorBLACK : 0);
120
121         this->onDrawIntoBitmap(bm);
122
123         if (kIndex_8_SkColorType == fColorType) {
124             convertToIndex666(bm, &fBitmap, fAlphaType);
125         } else {
126             fBitmap = bm;
127         }
128
129         fBitmap.setIsVolatile(fIsVolatile);
130     }
131
132     void onDraw(int loops, SkCanvas* canvas) override {
133         if (fDoScale) {
134             canvas->scale(.99f, .99f);
135         }
136         SkIPoint dim = this->getSize();
137         SkRandom rand;
138
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);
145
146         for (int i = 0; i < loops; i++) {
147             SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
148             SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
149
150             if (fForceUpdate)
151                 bitmap.notifyPixelsChanged();
152
153             canvas->drawBitmap(bitmap, x, y, &paint);
154         }
155     }
156
157      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
176 private:
177     typedef Benchmark INHERITED;
178 };
179
180 /** Explicitly invoke some filter types to improve coverage of acceleration
181     procs. */
182
183 enum Flags {
184     kScale_Flag             = 1 << 0,
185     kRotate_Flag            = 1 << 1,
186     kBilerp_Flag            = 1 << 2,
187     kBicubic_Flag           = 1 << 3,
188 };
189
190 static bool isBilerp(uint32_t flags) {
191     return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag);
192 }
193
194 static bool isBicubic(uint32_t flags) {
195     return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag | kBicubic_Flag);
196 }
197
198 class FilterBitmapBench : public BitmapBench {
199     uint32_t    fFlags;
200     SkString    fFullName;
201 public:
202     FilterBitmapBench(SkColorType ct, SkAlphaType at,
203                       bool forceUpdate, bool isVolitile, uint32_t flags)
204         : INHERITED(ct, at, forceUpdate, isVolitile, false)
205         , fFlags(flags) {
206     }
207
208 protected:
209     const char* onGetName() override {
210         fFullName.set(INHERITED::onGetName());
211         if (fFlags & kScale_Flag) {
212             fFullName.append("_scale");
213         }
214         if (fFlags & kRotate_Flag) {
215             fFullName.append("_rotate");
216         }
217         if (isBilerp(fFlags)) {
218             fFullName.append("_bilerp");
219         } else if (isBicubic(fFlags)) {
220             fFullName.append("_bicubic");
221         }
222
223         return fFullName.c_str();
224     }
225
226     void onDraw(int loops, SkCanvas* canvas) override {
227         SkISize dim = canvas->getBaseLayerSize();
228         if (fFlags & kScale_Flag) {
229             const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
230             const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
231
232             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         }
237         if (fFlags & kRotate_Flag) {
238             const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
239             const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
240             canvas->rotate(SkIntToScalar(35), x, y);
241         }
242         INHERITED::onDraw(loops, canvas);
243     }
244
245     void setupPaint(SkPaint* paint) override {
246         this->INHERITED::setupPaint(paint);
247
248         int index = 0;
249         if (fFlags & kBilerp_Flag) {
250             index |= 1;
251         }
252         if (fFlags & kBicubic_Flag) {
253             index |= 2;
254         }
255         static const SkFilterQuality gQualitys[] = {
256             kNone_SkFilterQuality,
257             kLow_SkFilterQuality,
258             kMedium_SkFilterQuality,
259             kHigh_SkFilterQuality
260         };
261         paint->setFilterQuality(gQualitys[index]);
262 }
263
264 private:
265     typedef BitmapBench INHERITED;
266 };
267
268 /** Verify optimizations that test source alpha values. */
269
270 class SourceAlphaBitmapBench : public BitmapBench {
271 public:
272     enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha,
273                        kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha};
274 private:
275     SkString    fFullName;
276     SourceAlpha fSourceAlpha;
277 public:
278     SourceAlphaBitmapBench(SourceAlpha alpha, SkColorType ct,
279                 bool forceUpdate = false, bool bitmapVolatile = false)
280         : INHERITED(ct, kPremul_SkAlphaType, forceUpdate, bitmapVolatile, false)
281         , fSourceAlpha(alpha) {
282     }
283
284 protected:
285     const char* onGetName() override {
286         fFullName.set(INHERITED::onGetName());
287
288         if (fSourceAlpha == kOpaque_SourceAlpha) {
289                 fFullName.append("_source_opaque");
290         } else if (fSourceAlpha == kTransparent_SourceAlpha) {
291                 fFullName.append("_source_transparent");
292         } else if (fSourceAlpha == kTwoStripes_SourceAlpha) {
293                 fFullName.append("_source_stripes_two");
294         } else if (fSourceAlpha == kThreeStripes_SourceAlpha) {
295                 fFullName.append("_source_stripes_three");
296         }
297
298         return fFullName.c_str();
299     }
300
301     void onDrawIntoBitmap(const SkBitmap& bm) override {
302         const int w = bm.width();
303         const int h = bm.height();
304
305         if (kOpaque_SourceAlpha == fSourceAlpha) {
306             bm.eraseColor(SK_ColorBLACK);
307         } else if (kTransparent_SourceAlpha == fSourceAlpha) {
308             bm.eraseColor(0);
309         } else if (kTwoStripes_SourceAlpha == fSourceAlpha) {
310             bm.eraseColor(0);
311
312             SkCanvas canvas(bm);
313             SkPaint p;
314             p.setAntiAlias(false);
315             p.setStyle(SkPaint::kFill_Style);
316             p.setColor(SK_ColorRED);
317
318             // Draw red vertical stripes on transparent background
319             SkRect r;
320             for (int x = 0; x < w; x+=2)
321             {
322                 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
323                 canvas.drawRect(r, p);
324             }
325
326         } else if (kThreeStripes_SourceAlpha == fSourceAlpha) {
327             bm.eraseColor(0);
328
329             SkCanvas canvas(bm);
330             SkPaint p;
331             p.setAntiAlias(false);
332             p.setStyle(SkPaint::kFill_Style);
333
334             // Draw vertical stripes on transparent background with a pattern
335             // where the first pixel is fully transparent, the next is semi-transparent
336             // and the third is fully opaque.
337             SkRect r;
338             for (int x = 0; x < w; x++)
339             {
340                 if (x % 3 == 0) {
341                     continue; // Keep transparent
342                 } else if (x % 3 == 1) {
343                     p.setColor(SkColorSetARGB(127, 127, 127, 127)); // Semi-transparent
344                 } else if (x % 3 == 2) {
345                     p.setColor(SK_ColorRED); // Opaque
346                 }
347                 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
348                 canvas.drawRect(r, p);
349             }
350         }
351     }
352
353 private:
354     typedef BitmapBench INHERITED;
355 };
356
357 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, false); )
358 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, false); )
359 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, true); )
360 DEF_BENCH( return new BitmapBench(kRGB_565_SkColorType, kOpaque_SkAlphaType, false, false, false); )
361 DEF_BENCH( return new BitmapBench(kIndex_8_SkColorType, kPremul_SkAlphaType, false, false, false); )
362 DEF_BENCH( return new BitmapBench(kIndex_8_SkColorType, kOpaque_SkAlphaType, false, false, false); )
363 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, false); )
364 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, false); )
365
366 // scale filter -> S32_opaque_D32_filter_DX_{SSE2,SSSE3} and Fact9 is also for S32_D16_filter_DX_SSE2
367 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
368 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
369 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kBilerp_Flag); )
370 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kBilerp_Flag); )
371
372 // scale rotate filter -> S32_opaque_D32_filter_DXDY_{SSE2,SSSE3}
373 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
374 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
375 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
376 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
377
378 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag | kBicubic_Flag); )
379 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag | kBicubic_Flag); )
380
381 // source alpha tests -> S32A_Opaque_BlitRow32_{arm,neon}
382 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kOpaque_SourceAlpha, kN32_SkColorType); )
383 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTransparent_SourceAlpha, kN32_SkColorType); )
384 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTwoStripes_SourceAlpha, kN32_SkColorType); )
385 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kThreeStripes_SourceAlpha, kN32_SkColorType); )