2 * Copyright 2011 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
11 #include "SkColorPriv.h"
15 #include "sk_tool_utils.h"
17 static int conv6ToByte(int x) {
21 static int convByteTo6(int x) {
25 static uint8_t compute666Index(SkPMColor c) {
26 int r = SkGetPackedR32(c);
27 int g = SkGetPackedG32(c);
28 int b = SkGetPackedB32(c);
30 return convByteTo6(r) * 36 + convByteTo6(g) * 6 + convByteTo6(b);
33 static void convertToIndex666(const SkBitmap& src, SkBitmap* dst, SkAlphaType aType) {
34 SkPMColor storage[216];
35 SkPMColor* colors = storage;
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);
47 dst->allocPixels(SkImageInfo::Make(src.width(), src.height(), kIndex_8_SkColorType, aType),
48 SkColorTable::Make(storage, 216));
50 SkAutoLockPixels alps(src);
51 SkAutoLockPixels alpd(*dst);
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++);
62 /* Variants for bitmaps
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
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;
85 BitmapBench(SkColorType ct, SkAlphaType at, bool forceUpdate, bool isVolatile, bool doScale)
88 , fForceUpdate(forceUpdate)
89 , fIsVolatile(isVolatile)
94 const char* onGetName() override {
96 fName.appendf("_%s%s", sk_tool_utils::colortype_name(fColorType),
97 kOpaque_SkAlphaType == fAlphaType ? "" : "_A");
99 fName.append("_scale");
102 fName.append("_update");
105 fName.append("_volatile");
108 return fName.c_str();
111 void onDelayedSetup() override {
114 if (kIndex_8_SkColorType == fColorType) {
115 bm.allocPixels(SkImageInfo::MakeN32(W, H, fAlphaType));
117 bm.allocPixels(SkImageInfo::Make(W, H, fColorType, fAlphaType));
119 bm.eraseColor(kOpaque_SkAlphaType == fAlphaType ? SK_ColorBLACK : 0);
121 this->onDrawIntoBitmap(bm);
123 if (kIndex_8_SkColorType == fColorType) {
124 convertToIndex666(bm, &fBitmap, fAlphaType);
129 fBitmap.setIsVolatile(fIsVolatile);
132 void onDraw(int loops, SkCanvas* canvas) override {
134 canvas->scale(.99f, .99f);
136 SkIPoint dim = this->getSize();
139 SkPaint paint(fPaint);
140 this->setupPaint(&paint);
142 const SkBitmap& bitmap = fBitmap;
143 const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2);
144 const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2);
146 for (int i = 0; i < loops; i++) {
147 SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
148 SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
151 bitmap.notifyPixelsChanged();
153 canvas->drawBitmap(bitmap, x, y, &paint);
157 virtual void onDrawIntoBitmap(const SkBitmap& bm) {
158 const int w = bm.width();
159 const int h = bm.height();
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);
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);
177 typedef Benchmark INHERITED;
180 /** Explicitly invoke some filter types to improve coverage of acceleration
184 kScale_Flag = 1 << 0,
185 kRotate_Flag = 1 << 1,
186 kBilerp_Flag = 1 << 2,
187 kBicubic_Flag = 1 << 3,
190 static bool isBilerp(uint32_t flags) {
191 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag);
194 static bool isBicubic(uint32_t flags) {
195 return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag | kBicubic_Flag);
198 class FilterBitmapBench : public BitmapBench {
202 FilterBitmapBench(SkColorType ct, SkAlphaType at,
203 bool forceUpdate, bool isVolitile, uint32_t flags)
204 : INHERITED(ct, at, forceUpdate, isVolitile, false)
209 const char* onGetName() override {
210 fFullName.set(INHERITED::onGetName());
211 if (fFlags & kScale_Flag) {
212 fFullName.append("_scale");
214 if (fFlags & kRotate_Flag) {
215 fFullName.append("_rotate");
217 if (isBilerp(fFlags)) {
218 fFullName.append("_bilerp");
219 } else if (isBicubic(fFlags)) {
220 fFullName.append("_bicubic");
223 return fFullName.c_str();
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;
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);
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);
242 INHERITED::onDraw(loops, canvas);
245 void setupPaint(SkPaint* paint) override {
246 this->INHERITED::setupPaint(paint);
249 if (fFlags & kBilerp_Flag) {
252 if (fFlags & kBicubic_Flag) {
255 static const SkFilterQuality gQualitys[] = {
256 kNone_SkFilterQuality,
257 kLow_SkFilterQuality,
258 kMedium_SkFilterQuality,
259 kHigh_SkFilterQuality
261 paint->setFilterQuality(gQualitys[index]);
265 typedef BitmapBench INHERITED;
268 /** Verify optimizations that test source alpha values. */
270 class SourceAlphaBitmapBench : public BitmapBench {
272 enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha,
273 kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha};
276 SourceAlpha fSourceAlpha;
278 SourceAlphaBitmapBench(SourceAlpha alpha, SkColorType ct,
279 bool forceUpdate = false, bool bitmapVolatile = false)
280 : INHERITED(ct, kPremul_SkAlphaType, forceUpdate, bitmapVolatile, false)
281 , fSourceAlpha(alpha) {
285 const char* onGetName() override {
286 fFullName.set(INHERITED::onGetName());
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");
298 return fFullName.c_str();
301 void onDrawIntoBitmap(const SkBitmap& bm) override {
302 const int w = bm.width();
303 const int h = bm.height();
305 if (kOpaque_SourceAlpha == fSourceAlpha) {
306 bm.eraseColor(SK_ColorBLACK);
307 } else if (kTransparent_SourceAlpha == fSourceAlpha) {
309 } else if (kTwoStripes_SourceAlpha == fSourceAlpha) {
314 p.setAntiAlias(false);
315 p.setStyle(SkPaint::kFill_Style);
316 p.setColor(SK_ColorRED);
318 // Draw red vertical stripes on transparent background
320 for (int x = 0; x < w; x+=2)
322 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
323 canvas.drawRect(r, p);
326 } else if (kThreeStripes_SourceAlpha == fSourceAlpha) {
331 p.setAntiAlias(false);
332 p.setStyle(SkPaint::kFill_Style);
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.
338 for (int x = 0; x < w; x++)
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
347 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
348 canvas.drawRect(r, p);
354 typedef BitmapBench INHERITED;
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); )
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); )
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); )
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); )
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); )