diff options
Diffstat (limited to 'bench')
-rw-r--r-- | bench/Android.mk | 30 | ||||
-rw-r--r-- | bench/BitmapBench.cpp | 164 | ||||
-rw-r--r-- | bench/Makefile.am | 19 | ||||
-rw-r--r-- | bench/RectBench.cpp | 133 | ||||
-rw-r--r-- | bench/SkBenchmark.cpp | 33 | ||||
-rw-r--r-- | bench/SkBenchmark.h | 54 | ||||
-rw-r--r-- | bench/TextBench.cpp | 175 | ||||
-rw-r--r-- | bench/benchmain.cpp | 365 |
8 files changed, 973 insertions, 0 deletions
diff --git a/bench/Android.mk b/bench/Android.mk new file mode 100644 index 0000000..117fb38 --- /dev/null +++ b/bench/Android.mk @@ -0,0 +1,30 @@ + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + BitmapBench.cpp \ + RectBench.cpp \ + TextBench.cpp \ + SkBenchmark.cpp \ + benchmain.cpp + +# additional optional class for this tool +LOCAL_SRC_FILES += \ + ../src/utils/SkNWayCanvas.cpp + +LOCAL_SHARED_LIBRARIES := libcutils libskia +LOCAL_C_INCLUDES := \ + external/skia/include/config \ + external/skia/include/core \ + external/skia/include/images \ + external/skia/include/utils \ + external/skia/include/effects + +#LOCAL_CFLAGS := + +LOCAL_MODULE := skia_bench + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_EXECUTABLE) diff --git a/bench/BitmapBench.cpp b/bench/BitmapBench.cpp new file mode 100644 index 0000000..22c0a01 --- /dev/null +++ b/bench/BitmapBench.cpp @@ -0,0 +1,164 @@ +#include "SkBenchmark.h" +#include "SkBitmap.h" +#include "SkPaint.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkRandom.h" +#include "SkString.h" + +static const char* gTileName[] = { + "clamp", "repeat", "mirror" +}; + +static const char* gConfigName[] = { + "ERROR", "a1", "a8", "index8", "565", "4444", "8888" +}; + +static void drawIntoBitmap(const SkBitmap& bm) { + const int w = bm.width(); + const int h = bm.height(); + + SkCanvas canvas(bm); + SkPaint p; + p.setAntiAlias(true); + p.setColor(SK_ColorRED); + canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2, + SkIntToScalar(SkMin32(w, h))*3/8, p); + + SkRect r; + r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h)); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(SkIntToScalar(4)); + p.setColor(SK_ColorBLUE); + canvas.drawRect(r, p); +} + +static int conv6ToByte(int x) { + return x * 0xFF / 5; +} + +static int convByteTo6(int x) { + return x * 5 / 255; +} + +static uint8_t compute666Index(SkPMColor c) { + int r = SkGetPackedR32(c); + int g = SkGetPackedG32(c); + int b = SkGetPackedB32(c); + + return convByteTo6(r) * 36 + convByteTo6(g) * 6 + convByteTo6(b); +} + +static void convertToIndex666(const SkBitmap& src, SkBitmap* dst) { + SkColorTable* ctable = new SkColorTable(216); + SkPMColor* colors = ctable->lockColors(); + // rrr ggg bbb + for (int r = 0; r < 6; r++) { + int rr = conv6ToByte(r); + for (int g = 0; g < 6; g++) { + int gg = conv6ToByte(g); + for (int b = 0; b < 6; b++) { + int bb = conv6ToByte(b); + *colors++ = SkPreMultiplyARGB(0xFF, rr, gg, bb); + } + } + } + ctable->unlockColors(true); + dst->setConfig(SkBitmap::kIndex8_Config, src.width(), src.height()); + dst->allocPixels(ctable); + ctable->unref(); + + SkAutoLockPixels alps(src); + SkAutoLockPixels alpd(*dst); + + for (int y = 0; y < src.height(); y++) { + const SkPMColor* srcP = src.getAddr32(0, y); + uint8_t* dstP = dst->getAddr8(0, y); + for (int x = src.width() - 1; x >= 0; --x) { + *dstP++ = compute666Index(*srcP++); + } + } +} + +/* Variants for bitmaps + + - src depth (32 w+w/o alpha), 565, 4444, index, a8 + - paint options: filtering, dither, alpha + - matrix options: translate, scale, rotate, persp + - tiling: none, repeat, mirror, clamp + + */ + +class BitmapBench : public SkBenchmark { + SkBitmap fBitmap; + SkPaint fPaint; + int fTileX, fTileY; // -1 means don't use shader + SkString fName; + enum { N = 300 }; +public: + BitmapBench(SkBitmap::Config c, int tx = -1, int ty = -1) : fTileX(tx), fTileY(ty) { + const int w = 128; + const int h = 128; + SkBitmap bm; + + if (SkBitmap::kIndex8_Config == c) { + bm.setConfig(SkBitmap::kARGB_8888_Config, w, h); + } else { + bm.setConfig(c, w, h); + } + bm.allocPixels(); + bm.eraseColor(0); + + drawIntoBitmap(bm); + + if (SkBitmap::kIndex8_Config == c) { + convertToIndex666(bm, &fBitmap); + } else { + fBitmap = bm; + } + } + +protected: + virtual const char* onGetName() { + fName.set("bitmap"); + if (fTileX >= 0) { + fName.appendf("_%s", gTileName[fTileX]); + if (fTileY != fTileX) { + fName.appendf("_%s", gTileName[fTileY]); + } + } + fName.appendf("_%s", gConfigName[fBitmap.config()]); + return fName.c_str(); + } + + virtual void onDraw(SkCanvas* canvas) { + SkIPoint dim = this->getSize(); + SkRandom rand; + + SkPaint paint(fPaint); + this->setupPaint(&paint); + + const SkBitmap& bitmap = fBitmap; + const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2); + const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2); + + for (int i = 0; i < N; i++) { + SkScalar x = x0 + rand.nextUScalar1() * dim.fX; + SkScalar y = y0 + rand.nextUScalar1() * dim.fY; + canvas->drawBitmap(bitmap, x, y, &paint); + } + } + +private: + typedef SkBenchmark INHERITED; +}; + +static SkBenchmark* Fact0(void*) { return new BitmapBench(SkBitmap::kARGB_8888_Config); } +static SkBenchmark* Fact1(void*) { return new BitmapBench(SkBitmap::kRGB_565_Config); } +static SkBenchmark* Fact2(void*) { return new BitmapBench(SkBitmap::kARGB_4444_Config); } +static SkBenchmark* Fact3(void*) { return new BitmapBench(SkBitmap::kIndex8_Config); } + +static BenchRegistry gReg0(Fact0); +static BenchRegistry gReg1(Fact1); +static BenchRegistry gReg2(Fact2); +static BenchRegistry gReg3(Fact3); diff --git a/bench/Makefile.am b/bench/Makefile.am new file mode 100644 index 0000000..be0ebdb --- /dev/null +++ b/bench/Makefile.am @@ -0,0 +1,19 @@ +AM_CPPFLAGS = -I$(top_builddir)/include/core -I$(top_builddir)/include/images +AM_LDFLAGS = -lpng -lpthread + +bin_PROGRAMS = Bench +Bench_SOURCES = RectBench.cpp \ + SkBenchmark.cpp \ + BenchTool/main.cpp \ + $(top_builddir)/src/images/SkImageDecoder.cpp \ + $(top_builddir)/src/images/SkImageDecoder_libpng.cpp \ + $(top_builddir)/src/images/SkScaledBitmapSampler.cpp \ + $(top_builddir)/src/ports/SkGlobals_global.cpp \ + $(top_builddir)/src/ports/SkOSFile_stdio.cpp \ + $(top_builddir)/src/ports/SkThread_pthread.cpp \ + $(top_builddir)/src/ports/SkTime_Unix.cpp \ + $(top_builddir)/src/ports/SkFontHost_none.cpp + + +Bench_LDADD = $(top_builddir)/src/core/libskia.a + diff --git a/bench/RectBench.cpp b/bench/RectBench.cpp new file mode 100644 index 0000000..69e0b00 --- /dev/null +++ b/bench/RectBench.cpp @@ -0,0 +1,133 @@ +#include "SkBenchmark.h" +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkString.h" + +class RectBench : public SkBenchmark { +public: + int fShift; + enum { + W = 640, + H = 480, + N = 300 + }; + SkRect fRects[N]; + SkColor fColors[N]; + + RectBench(int shift) : fShift(shift) { + SkRandom rand; + for (int i = 0; i < N; i++) { + int x = rand.nextU() % W; + int y = rand.nextU() % H; + int w = rand.nextU() % W; + int h = rand.nextU() % H; + w >>= shift; + h >>= shift; + x -= w/2; + y -= h/2; + fRects[i].set(SkIntToScalar(x), SkIntToScalar(y), + SkIntToScalar(x+w), SkIntToScalar(y+h)); + fColors[i] = rand.nextU() | 0xFF808080; + } + } + + SkString fName; + const char* computeName(const char root[]) { + fName.set(root); + fName.appendS32(fShift); + return fName.c_str(); + } + +protected: + virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) { + c->drawRect(r, p); + } + + virtual const char* onGetName() { return computeName("rects"); } + virtual void onDraw(SkCanvas* canvas) { + SkPaint paint; + for (int i = 0; i < N; i++) { + paint.setColor(fColors[i]); + this->setupPaint(&paint); + this->drawThisRect(canvas, fRects[i], paint); + } + } +}; + +class OvalBench : public RectBench { +public: + OvalBench(int shift) : RectBench(shift) {} +protected: + virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) { + c->drawOval(r, p); + } + virtual const char* onGetName() { return computeName("ovals"); } +}; + +class RRectBench : public RectBench { +public: + RRectBench(int shift) : RectBench(shift) {} +protected: + virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) { + c->drawRoundRect(r, r.width() / 4, r.height() / 4, p); + } + virtual const char* onGetName() { return computeName("rrects"); } +}; + +class PointsBench : public RectBench { +public: + SkCanvas::PointMode fMode; + const char* fName; + + PointsBench(SkCanvas::PointMode mode, const char* name) : + RectBench(2), fMode(mode) { + fName = name; + } + +protected: + virtual void onDraw(SkCanvas* canvas) { + static const SkScalar gSizes[] = { + SkIntToScalar(7), 0 + }; + + SkPaint paint; + paint.setStrokeCap(SkPaint::kRound_Cap); + + for (size_t i = 0; i < SK_ARRAY_COUNT(gSizes); i++) { + paint.setStrokeWidth(gSizes[i]); + this->setupPaint(&paint); + canvas->drawPoints(fMode, N * 2, + reinterpret_cast<const SkPoint*>(fRects), paint); + paint.setColor(fColors[i]); + } + } + virtual const char* onGetName() { return fName; } +}; + +static SkBenchmark* RectFactory1(void*) { return SkNEW_ARGS(RectBench, (1)); } +static SkBenchmark* RectFactory2(void*) { return SkNEW_ARGS(RectBench, (3)); } +static SkBenchmark* OvalFactory1(void*) { return SkNEW_ARGS(OvalBench, (1)); } +static SkBenchmark* OvalFactory2(void*) { return SkNEW_ARGS(OvalBench, (3)); } +static SkBenchmark* RRectFactory1(void*) { return SkNEW_ARGS(RRectBench, (1)); } +static SkBenchmark* RRectFactory2(void*) { return SkNEW_ARGS(RRectBench, (3)); } +static SkBenchmark* PointsFactory(void*) { + return SkNEW_ARGS(PointsBench, (SkCanvas::kPoints_PointMode, "points")); +} +static SkBenchmark* LinesFactory(void*) { + return SkNEW_ARGS(PointsBench, (SkCanvas::kLines_PointMode, "lines")); +} +static SkBenchmark* PolygonFactory(void*) { + return SkNEW_ARGS(PointsBench, (SkCanvas::kPolygon_PointMode, "polygon")); +} + +static BenchRegistry gRectReg1(RectFactory1); +static BenchRegistry gRectReg2(RectFactory2); +static BenchRegistry gOvalReg1(OvalFactory1); +static BenchRegistry gOvalReg2(OvalFactory2); +static BenchRegistry gRRectReg1(RRectFactory1); +static BenchRegistry gRRectReg2(RRectFactory2); +static BenchRegistry gPointsReg(PointsFactory); +static BenchRegistry gLinesReg(LinesFactory); +static BenchRegistry gPolygonReg(PolygonFactory); + diff --git a/bench/SkBenchmark.cpp b/bench/SkBenchmark.cpp new file mode 100644 index 0000000..7bc87ee --- /dev/null +++ b/bench/SkBenchmark.cpp @@ -0,0 +1,33 @@ +#include "SkBenchmark.h" +#include "SkPaint.h" + +template BenchRegistry* BenchRegistry::gHead; + +SkBenchmark::SkBenchmark() { + fForceAlpha = 0xFF; + fForceAA = true; +} + +const char* SkBenchmark::getName() { + return this->onGetName(); +} + +SkIPoint SkBenchmark::getSize() { + return this->onGetSize(); +} + +void SkBenchmark::draw(SkCanvas* canvas) { + this->onDraw(canvas); +} + +void SkBenchmark::setupPaint(SkPaint* paint) { + paint->setAlpha(fForceAlpha); + paint->setAntiAlias(fForceAA); + paint->setFilterBitmap(fForceFilter); +} + +/////////////////////////////////////////////////////////////////////////////// + +SkIPoint SkBenchmark::onGetSize() { + return SkMakeIPoint(640, 480); +} diff --git a/bench/SkBenchmark.h b/bench/SkBenchmark.h new file mode 100644 index 0000000..2058251 --- /dev/null +++ b/bench/SkBenchmark.h @@ -0,0 +1,54 @@ +#ifndef SkBenchmark_DEFINED +#define SkBenchmark_DEFINED + +#include "SkRefCnt.h" +#include "SkPoint.h" +#include "SkTRegistry.h" + +class SkCanvas; +class SkPaint; + +class SkBenchmark : public SkRefCnt { +public: + SkBenchmark(); + + const char* getName(); + SkIPoint getSize(); + void draw(SkCanvas*); + + void setForceAlpha(int alpha) { + fForceAlpha = alpha; + } + + void setForceAA(bool aa) { + fForceAA = aa; + } + + void setForceFilter(bool filter) { + fForceFilter = filter; + } + +protected: + void setupPaint(SkPaint* paint); + + virtual const char* onGetName() = 0; + virtual void onDraw(SkCanvas*) = 0; + + virtual SkIPoint onGetSize(); + +private: + int fForceAlpha; + bool fForceAA; + bool fForceFilter; +}; + +static inline SkIPoint SkMakeIPoint(int x, int y) { + SkIPoint p; + p.set(x, y); + return p; +} + +typedef SkTRegistry<SkBenchmark*, void*> BenchRegistry; + +#endif + diff --git a/bench/TextBench.cpp b/bench/TextBench.cpp new file mode 100644 index 0000000..67cd766 --- /dev/null +++ b/bench/TextBench.cpp @@ -0,0 +1,175 @@ +#include "SkBenchmark.h" +#include "SkCanvas.h" +#include "SkFontHost.h" +#include "SkPaint.h" +#include "SkRandom.h" +#include "SkSfntUtils.h" +#include "SkString.h" +#include "SkTemplates.h" + +static void dump_font(const char name[], SkFontID fontID) { + SkDebugf("Font \"%s\" %x\n", name, fontID); + int count = SkFontHost::CountTables(fontID); + SkAutoTArray<SkFontTableTag> storage(count); + SkFontTableTag* tags = storage.get(); + SkFontHost::GetTableTags(fontID, tags); + for (int i = 0; i < count; i++) { + uint32_t tag = tags[i]; + uint8_t data[4]; + size_t size = SkFontHost::GetTableSize(fontID, tag); + size_t bytes = SkFontHost::GetTableData(fontID, tag, + 0, sizeof(data), data); + SkDebugf(" tag=%c%c%c%c size=%d bytes=%d %x %x %x %x\n", + uint8_t(tag>>24), uint8_t(tag>>16), uint8_t(tag>>8), uint8_t(tag), + size, bytes, data[0], data[1], data[2], data[3]); + } + + SkSfntTable_head head; + if (SkSfntUtils::ReadTable_head(fontID, &head)) { + SkDebugf("--- head: version=%x magic=%x upem=%d style=%x\n", head.fVersion, + head.fMagicNumber, head.fUnitsPerEm, head.fMacStyle); + } else { + SkDebugf("------- head wasn't read\n"); + } + + SkSfntTable_maxp maxp; + if (SkSfntUtils::ReadTable_maxp(fontID, &maxp)) { + SkDebugf("--- maxp: version=%x glyphs=%d points=%d ctrs=%d\n", maxp.fVersion, + maxp.fNumGlyphs, maxp.fMaxPoints, maxp.fMaxContours); + } else { + SkDebugf("------- maxp wasn't read\n"); + } +} + +static void test_tables() { + static bool gOnce; + if (gOnce) { + return; + } + gOnce = true; + + static const char* gNames[] = { + "Arial", "Times", "Courier" + }; + + for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); i++) { + SkTypeface* tf = SkTypeface::CreateFromName(gNames[i], SkTypeface::kNormal); + if (tf) { + SkFontID fontID = tf->uniqueID(); + dump_font(gNames[i], fontID); + tf->unref(); + } + } +} + +/* Some considerations for performance: + short -vs- long strings (measuring overhead) + tiny -vs- large pointsize (measure blit -vs- overhead) + 1 -vs- many point sizes (measure cache lookup) + normal -vs- subpixel -vs- lineartext (minor) + force purge after each draw to measure scaler + textencoding? + text -vs- postext - pathtext + */ +class TextBench : public SkBenchmark { + SkPaint fPaint; + int fCount; + SkPoint* fPos; + SkString fText; + SkString fName; + enum { N = 300 }; +public: + TextBench(const char text[], int ps, bool linearText, bool posText) { + if (false) { + test_tables(); + } + + fText.set(text); + + fPaint.setAntiAlias(true); + fPaint.setTextSize(SkIntToScalar(ps)); + fPaint.setLinearText(linearText); + + if (posText) { + SkAutoTArray<SkScalar> storage(fText.size()); + SkScalar* widths = storage.get(); + fCount = fPaint.getTextWidths(fText.c_str(), fText.size(), widths); + fPos = new SkPoint[fCount]; + SkScalar x = 0; + for (int i = 0; i < fCount; i++) { + fPos[i].set(x, 0); + x += widths[i]; + } + } else { + fCount = 0; + fPos = NULL; + } + } + + virtual ~TextBench() { + delete[] fPos; + } + +protected: + virtual const char* onGetName() { + fName.printf("text_%g", SkScalarToFloat(fPaint.getTextSize())); + if (fPaint.isLinearText()) { + fName.append("_linear"); + } + if (fPos) { + fName.append("_pos"); + } + return fName.c_str(); + } + + virtual void onDraw(SkCanvas* canvas) { + const SkIPoint dim = this->getSize(); + SkRandom rand; + + SkPaint paint(fPaint); + this->setupPaint(&paint); + + const SkScalar x0 = SkIntToScalar(-10); + const SkScalar y0 = SkIntToScalar(-10); + + for (int i = 0; i < N; i++) { + SkScalar x = x0 + rand.nextUScalar1() * dim.fX; + SkScalar y = y0 + rand.nextUScalar1() * dim.fY; + if (fPos) { + canvas->save(SkCanvas::kMatrix_SaveFlag); + canvas->translate(x, y); + canvas->drawPosText(fText.c_str(), fText.size(), fPos, paint); + canvas->restore(); + } else { + canvas->drawText(fText.c_str(), fText.size(), x, y, paint); + } + } + } + +private: + typedef SkBenchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +#define STR "Hamburgefons" +#define SMALL 9 +#define BIG 48 + +static SkBenchmark* Fact0(void*) { return new TextBench(STR, SMALL, false, false); } +static SkBenchmark* Fact1(void*) { return new TextBench(STR, SMALL, false, true); } +static SkBenchmark* Fact2(void*) { return new TextBench(STR, SMALL, true, false); } +static SkBenchmark* Fact3(void*) { return new TextBench(STR, SMALL, true, true); } +static SkBenchmark* Fact4(void*) { return new TextBench(STR, BIG, false, false); } +static SkBenchmark* Fact5(void*) { return new TextBench(STR, BIG, false, true); } +static SkBenchmark* Fact6(void*) { return new TextBench(STR, BIG, true, false); } +static SkBenchmark* Fact7(void*) { return new TextBench(STR, BIG, true, true); } + +static BenchRegistry gReg0(Fact0); +static BenchRegistry gReg1(Fact1); +static BenchRegistry gReg2(Fact2); +static BenchRegistry gReg3(Fact3); +static BenchRegistry gReg4(Fact4); +static BenchRegistry gReg5(Fact5); +static BenchRegistry gReg6(Fact6); +static BenchRegistry gReg7(Fact7); diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp new file mode 100644 index 0000000..501e86a --- /dev/null +++ b/bench/benchmain.cpp @@ -0,0 +1,365 @@ +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkGraphics.h" +#include "SkImageEncoder.h" +#include "SkNWayCanvas.h" +#include "SkPicture.h" +#include "SkString.h" +#include "SkTime.h" + +#include "SkBenchmark.h" + +#ifdef ANDROID +static void log_error(const char msg[]) { SkDebugf("%s", msg); } +static void log_progress(const char msg[]) { SkDebugf("%s", msg); } +#else +static void log_error(const char msg[]) { fprintf(stderr, "%s", msg); } +static void log_progress(const char msg[]) { printf("%s", msg); } +#endif + +static void log_error(const SkString& str) { log_error(str.c_str()); } +static void log_progress(const SkString& str) { log_progress(str.c_str()); } + +/////////////////////////////////////////////////////////////////////////////// + +static void erase(SkBitmap& bm) { + if (bm.config() == SkBitmap::kA8_Config) { + bm.eraseColor(0); + } else { + bm.eraseColor(SK_ColorWHITE); + } +} + +static bool equal(const SkBitmap& bm1, const SkBitmap& bm2) { + if (bm1.width() != bm2.width() || + bm1.height() != bm2.height() || + bm1.config() != bm2.config()) { + return false; + } + + size_t pixelBytes = bm1.width() * bm1.bytesPerPixel(); + for (int y = 0; y < bm1.height(); y++) { + if (memcmp(bm1.getAddr(0, y), bm2.getAddr(0, y), pixelBytes)) { + return false; + } + } + + return true; +} + +class Iter { +public: + Iter() { + fBench = BenchRegistry::Head(); + } + + SkBenchmark* next() { + if (fBench) { + BenchRegistry::Factory f = fBench->factory(); + fBench = fBench->next(); + return f(0); + } + return NULL; + } + +private: + const BenchRegistry* fBench; +}; + +static void make_filename(const char name[], SkString* path) { + path->set(name); + for (int i = 0; name[i]; i++) { + switch (name[i]) { + case '/': + case '\\': + case ' ': + case ':': + path->writable_str()[i] = '-'; + break; + default: + break; + } + } +} + +static void saveFile(const char name[], const char config[], const char dir[], + const SkBitmap& bm) { + SkBitmap copy; + if (!bm.copyTo(©, SkBitmap::kARGB_8888_Config)) { + return; + } + + if (bm.config() == SkBitmap::kA8_Config) { + // turn alpha into gray-scale + size_t size = copy.getSize() >> 2; + SkPMColor* p = copy.getAddr32(0, 0); + for (size_t i = 0; i < size; i++) { + int c = (*p >> SK_A32_SHIFT) & 0xFF; + c = 255 - c; + c |= (c << 24) | (c << 16) | (c << 8); + *p++ = c | (SK_A32_MASK << SK_A32_SHIFT); + } + } + + SkString str; + make_filename(name, &str); + str.appendf("_%s.png", config); + str.prepend(dir); + ::remove(str.c_str()); + SkImageEncoder::EncodeFile(str.c_str(), copy, SkImageEncoder::kPNG_Type, + 100); +} + +static void performClip(SkCanvas* canvas, int w, int h) { + SkRect r; + + r.set(SkIntToScalar(10), SkIntToScalar(10), + SkIntToScalar(w*2/3), SkIntToScalar(h*2/3)); + canvas->clipRect(r, SkRegion::kIntersect_Op); + + r.set(SkIntToScalar(w/3), SkIntToScalar(h/3), + SkIntToScalar(w-10), SkIntToScalar(h-10)); + canvas->clipRect(r, SkRegion::kXOR_Op); +} + +static void performRotate(SkCanvas* canvas, int w, int h) { + const SkScalar x = SkIntToScalar(w) / 2; + const SkScalar y = SkIntToScalar(h) / 2; + + canvas->translate(x, y); + canvas->rotate(SkIntToScalar(35)); + canvas->translate(-x, -y); +} + +static void performScale(SkCanvas* canvas, int w, int h) { + const SkScalar x = SkIntToScalar(w) / 2; + const SkScalar y = SkIntToScalar(h) / 2; + + canvas->translate(x, y); + // just enough so we can't take the sprite case + canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); + canvas->translate(-x, -y); +} + +static void compare_pict_to_bitmap(SkPicture* pict, const SkBitmap& bm) { + SkBitmap bm2; + + bm2.setConfig(bm.config(), bm.width(), bm.height()); + bm2.allocPixels(); + erase(bm2); + + SkCanvas canvas(bm2); + canvas.drawPicture(*pict); + + if (!equal(bm, bm2)) { + SkDebugf("----- compare_pict_to_bitmap failed\n"); + } +} + +static bool parse_bool_arg(char * const* argv, char* const* stop, bool* var) { + if (argv < stop) { + *var = atoi(*argv) != 0; + return true; + } + return false; +} + +static const struct { + SkBitmap::Config fConfig; + const char* fName; +} gConfigs[] = { + { SkBitmap::kARGB_8888_Config, "8888" }, + { SkBitmap::kRGB_565_Config, "565", }, + { SkBitmap::kARGB_4444_Config, "4444", }, + { SkBitmap::kA8_Config, "A8", } +}; + +static int findConfig(const char config[]) { + for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) { + if (!strcmp(config, gConfigs[i].fName)) { + return i; + } + } + return -1; +} + +int main (int argc, char * const argv[]) { + SkAutoGraphics ag; + + int repeatDraw = 1; + int forceAlpha = 0xFF; + bool forceAA = true; + bool forceFilter = false; + bool doScale = false; + bool doRotate = false; + bool doClip = false; + bool doPict = false; + const char* matchStr = NULL; + + SkString outDir; + SkBitmap::Config outConfig = SkBitmap::kNo_Config; + const char* configName = ""; + int configCount = SK_ARRAY_COUNT(gConfigs); + + char* const* stop = argv + argc; + for (++argv; argv < stop; ++argv) { + if (strcmp(*argv, "-o") == 0) { + argv++; + if (argv < stop && **argv) { + outDir.set(*argv); + if (outDir.c_str()[outDir.size() - 1] != '/') { + outDir.append("/"); + } + } + } else if (strcmp(*argv, "-pict") == 0) { + doPict = true; + } else if (strcmp(*argv, "-repeat") == 0) { + argv++; + if (argv < stop) { + repeatDraw = atoi(*argv); + if (repeatDraw < 1) { + repeatDraw = 1; + } + } else { + log_error("missing arg for -repeat\n"); + return -1; + } + } else if (!strcmp(*argv, "-rotate")) { + doRotate = true; + } else if (!strcmp(*argv, "-scale")) { + doScale = true; + } else if (!strcmp(*argv, "-clip")) { + doClip = true; + } else if (strcmp(*argv, "-forceAA") == 0) { + if (!parse_bool_arg(++argv, stop, &forceAA)) { + log_error("missing arg for -forceAA\n"); + return -1; + } + } else if (strcmp(*argv, "-forceFilter") == 0) { + if (!parse_bool_arg(++argv, stop, &forceFilter)) { + log_error("missing arg for -forceFilter\n"); + return -1; + } + } else if (strcmp(*argv, "-forceBlend") == 0) { + bool wantAlpha = false; + if (!parse_bool_arg(++argv, stop, &wantAlpha)) { + log_error("missing arg for -forceBlend\n"); + return -1; + } + forceAlpha = wantAlpha ? 0x80 : 0xFF; + } else if (strcmp(*argv, "-match") == 0) { + argv++; + if (argv < stop) { + matchStr = *argv; + } else { + log_error("missing arg for -match\n"); + return -1; + } + } else if (strcmp(*argv, "-config") == 0) { + argv++; + if (argv < stop) { + int index = findConfig(*argv); + if (index >= 0) { + outConfig = gConfigs[index].fConfig; + configName = gConfigs[index].fName; + configCount = 1; + } else { + SkString str; + str.printf("unrecognized config %s\n", *argv); + log_error(str); + return -1; + } + } else { + log_error("missing arg for -config\n"); + return -1; + } + } else { + SkString str; + str.printf("unrecognized arg %s\n", *argv); + log_error(str); + return -1; + } + } + + Iter iter; + SkBenchmark* bench; + while ((bench = iter.next()) != NULL) { + SkIPoint dim = bench->getSize(); + if (dim.fX <= 0 || dim.fY <= 0) { + continue; + } + + bench->setForceAlpha(forceAlpha); + bench->setForceAA(forceAA); + bench->setForceFilter(forceFilter); + + // only run benchmarks if their name contains matchStr + if (matchStr && strstr(bench->getName(), matchStr) == NULL) { + continue; + } + + { + SkString str; + str.printf("running bench %16s", bench->getName()); + log_progress(str); + } + + for (int configIndex = 0; configIndex < configCount; configIndex++) { + if (configCount > 1) { + outConfig = gConfigs[configIndex].fConfig; + configName = gConfigs[configIndex].fName; + } + + SkBitmap bm; + bm.setConfig(outConfig, dim.fX, dim.fY); + bm.allocPixels(); + erase(bm); + + SkCanvas canvas(bm); + + if (doClip) { + performClip(&canvas, dim.fX, dim.fY); + } + if (doScale) { + performScale(&canvas, dim.fX, dim.fY); + } + if (doRotate) { + performRotate(&canvas, dim.fX, dim.fY); + } + + SkMSec now = SkTime::GetMSecs(); + for (int i = 0; i < repeatDraw; i++) { + SkCanvas* c = &canvas; + + SkNWayCanvas nway; + SkPicture* pict = NULL; + if (doPict) { + pict = new SkPicture; + nway.addCanvas(pict->beginRecording(bm.width(), bm.height())); + nway.addCanvas(&canvas); + c = &nway; + } + + SkAutoCanvasRestore acr(c, true); + bench->draw(c); + + if (pict) { + compare_pict_to_bitmap(pict, bm); + pict->unref(); + } + } + if (repeatDraw > 1) { + SkString str; + str.printf(" %4s:%7.2f", configName, + (SkTime::GetMSecs() - now) / (double)repeatDraw); + log_progress(str); + } + if (outDir.size() > 0) { + saveFile(bench->getName(), configName, outDir.c_str(), bm); + } + } + log_progress("\n"); + } + + return 0; +} |