add BitmapBench



git-svn-id: http://skia.googlecode.com/svn/trunk@83 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/Makefile b/Makefile
index 5ad305b..d3a95f3 100644
--- a/Makefile
+++ b/Makefile
@@ -68,7 +68,7 @@
 	$(HIDE)$(AR) ru $@ $(OBJ_LIST)
 	$(HIDE)ranlib $@
 
-BENCH_SRCS := RectBench.cpp SkBenchmark.cpp main.cpp
+BENCH_SRCS := RectBench.cpp SkBenchmark.cpp main.cpp BitmapBench.cpp
 BENCH_SRCS := $(addprefix bench/, $(BENCH_SRCS))
 
 # add any optional codecs for this app
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/RectBench.cpp b/bench/RectBench.cpp
index ba01375..69e0b00 100644
--- a/bench/RectBench.cpp
+++ b/bench/RectBench.cpp
@@ -3,7 +3,6 @@
 #include "SkPaint.h"
 #include "SkRandom.h"
 #include "SkString.h"
-#include "SkTRegistry.h"
 
 class RectBench : public SkBenchmark {
 public:
@@ -46,7 +45,6 @@
     }
 
     virtual const char* onGetName() { return computeName("rects"); }
-    virtual SkIPoint onGetSize() { return SkMakeIPoint(640, 480); }
     virtual void onDraw(SkCanvas* canvas) {
         SkPaint paint;
         for (int i = 0; i < N; i++) {
@@ -123,13 +121,13 @@
     return SkNEW_ARGS(PointsBench, (SkCanvas::kPolygon_PointMode, "polygon"));
 }
 
-static SkTRegistry<SkBenchmark*, void*> gRectReg1(RectFactory1);
-static SkTRegistry<SkBenchmark*, void*> gRectReg2(RectFactory2);
-static SkTRegistry<SkBenchmark*, void*> gOvalReg1(OvalFactory1);
-static SkTRegistry<SkBenchmark*, void*> gOvalReg2(OvalFactory2);
-static SkTRegistry<SkBenchmark*, void*> gRRectReg1(RRectFactory1);
-static SkTRegistry<SkBenchmark*, void*> gRRectReg2(RRectFactory2);
-static SkTRegistry<SkBenchmark*, void*> gPointsReg(PointsFactory);
-static SkTRegistry<SkBenchmark*, void*> gLinesReg(LinesFactory);
-static SkTRegistry<SkBenchmark*, void*> gPolygonReg(PolygonFactory);
+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
index 5d22b70..853afb3 100644
--- a/bench/SkBenchmark.cpp
+++ b/bench/SkBenchmark.cpp
@@ -1,6 +1,8 @@
 #include "SkBenchmark.h"
 #include "SkPaint.h"
 
+template BenchRegistry* BenchRegistry::gHead;
+
 SkBenchmark::SkBenchmark() {
     fForceAlpha = 0xFF;
     fForceAA = true;
@@ -23,4 +25,8 @@
     paint->setAntiAlias(fForceAA);
 }
 
+///////////////////////////////////////////////////////////////////////////////
 
+SkIPoint SkBenchmark::onGetSize() {
+    return SkMakeIPoint(640, 480);
+}
diff --git a/bench/SkBenchmark.h b/bench/SkBenchmark.h
index 87bf67a..27009d9 100644
--- a/bench/SkBenchmark.h
+++ b/bench/SkBenchmark.h
@@ -3,6 +3,7 @@
 
 #include "SkRefCnt.h"
 #include "SkPoint.h"
+#include "SkTRegistry.h"
 
 class SkCanvas;
 class SkPaint;
@@ -27,9 +28,10 @@
     void setupPaint(SkPaint* paint);
 
     virtual const char* onGetName() = 0;
-    virtual SkIPoint onGetSize() = 0;
     virtual void onDraw(SkCanvas*) = 0;
-    
+
+    virtual SkIPoint onGetSize();
+
 private:
     int     fForceAlpha;
     bool    fForceAA;
@@ -41,5 +43,7 @@
     return p;
 }
 
+typedef SkTRegistry<SkBenchmark*, void*> BenchRegistry;
+
 #endif
 
diff --git a/bench/main.cpp b/bench/main.cpp
index 25ab73a..8891154 100644
--- a/bench/main.cpp
+++ b/bench/main.cpp
@@ -1,13 +1,11 @@
 #include "SkCanvas.h"
+#include "SkColorPriv.h"
 #include "SkImageEncoder.h"
 #include "SkString.h"
 #include "SkTime.h"
-#include "SkTRegistry.h"
 
 #include "SkBenchmark.h"
 
-typedef SkTRegistry<SkBenchmark*, void*> BenchRegistry;
-
 class Iter {
 public:
     Iter() {
@@ -49,6 +47,18 @@
     if (!bm.copyTo(&copy, 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);
@@ -164,7 +174,7 @@
         bench->setForceAlpha(forceAlpha);
         bench->setForceAA(forceAA);
 
-        printf("running bench %8s", bench->getName());
+        printf("running bench %16s", bench->getName());
 
         for (int configIndex = 0; configIndex < configCount; configIndex++) {
             if (configCount > 1) {
@@ -176,9 +186,14 @@
             bm.setConfig(outConfig, dim.fX, dim.fY);
             bm.allocPixels();
             
+            if (bm.config() == SkBitmap::kA8_Config) {
+                bm.eraseColor(0);
+            } else {
+                bm.eraseColor(SK_ColorWHITE);
+            }
+
             SkCanvas canvas(bm);
-            canvas.drawColor(SK_ColorWHITE);
-            
+
             if (doClip) {
                 performClip(&canvas, dim.fX, dim.fY);
             }
diff --git a/include/core/SkTRegistry.h b/include/core/SkTRegistry.h
index 83c08de..f0f427c 100644
--- a/include/core/SkTRegistry.h
+++ b/include/core/SkTRegistry.h
@@ -45,6 +45,7 @@
     static SkTRegistry* gHead;
 };
 
+// The caller still needs to declare an instance of this somewhere
 template <typename T, typename P> SkTRegistry<T, P>* SkTRegistry<T, P>::gHead;
 
 #endif
diff --git a/src/utils/SkInterpolator.cpp b/src/utils/SkInterpolator.cpp
index e4ecd95..c5bb448 100644
--- a/src/utils/SkInterpolator.cpp
+++ b/src/utils/SkInterpolator.cpp
@@ -80,7 +80,7 @@
     SkASSERT(fFrameCount > 0);
     Result  result = kNormal_Result;
     if (fRepeat != SK_Scalar1) {
-        SkMSec startTime, endTime;
+        SkMSec startTime = 0, endTime = 0;  // initialize to avoid warning
         this->getDuration(&startTime, &endTime);
         SkMSec totalTime = endTime - startTime;
         SkMSec offsetTime = time - startTime;