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