Add atlasing option to GameBench bench

https://codereview.chromium.org/15660012/



git-svn-id: http://skia.googlecode.com/svn/trunk@9363 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/bench/GameBench.cpp b/bench/GameBench.cpp
index 4998bd8..ba7f765 100644
--- a/bench/GameBench.cpp
+++ b/bench/GameBench.cpp
@@ -11,7 +11,6 @@
 #include "SkRandom.h"
 #include "SkString.h"
 
-
 // This bench simulates the calls Skia sees from various HTML5 canvas
 // game bench marks
 class GameBench : public SkBenchmark {
@@ -22,11 +21,18 @@
         kRotate_Type
     };
 
-    GameBench(void* param, Type type, bool partialClear, bool aligned = false)
+    enum Clear {
+        kFull_Clear,
+        kPartial_Clear
+    };
+
+    GameBench(void* param, Type type, Clear clear, 
+               bool aligned = false, bool useAtlas = false)
         : INHERITED(param)
         , fType(type)
-        , fPartialClear(partialClear)
+        , fClear(clear)
         , fAligned(aligned)
+        , fUseAtlas(useAtlas)
         , fName("game")
         , fNumSaved(0)
         , fInitialized(false) {
@@ -47,24 +53,29 @@
             fName.append("_aligned");
         }
 
-        if (partialClear) {
+        if (kPartial_Clear == clear) {
             fName.append("_partial");
         } else {
             fName.append("_full");
         }
 
+        if (useAtlas) {
+            fName.append("_atlas");
+        }
+
         // It's HTML 5 canvas, so always AA
         fName.append("_aa");
     }
 
 protected:
     virtual const char* onGetName() SK_OVERRIDE {
-        return fName.c_str();;
+        return fName.c_str();
     }
 
     virtual void onPreDraw() SK_OVERRIDE {
         if (!fInitialized) {
             this->makeCheckerboard();
+            this->makeAtlas();
             fInitialized = true;
         }
     }
@@ -74,6 +85,15 @@
         static SkMWCRandom transRand;
         static SkMWCRandom rotRand;
 
+        int width, height;
+        if (fUseAtlas) {
+            width = kAtlasCellWidth;
+            height = kAtlasCellHeight;
+        } else {
+            width = kCheckerboardWidth;
+            height = kCheckerboardHeight;
+        }
+
         SkPaint clearPaint;
         clearPaint.setColor(0xFF000000);
         clearPaint.setAntiAlias(true);
@@ -83,23 +103,22 @@
         SkScalar maxTransX, maxTransY;
 
         if (kScale_Type == fType) {
-            maxTransX = size.fWidth  - (1.5f * kCheckerboardWidth);
-            maxTransY = size.fHeight - (1.5f * kCheckerboardHeight);
+            maxTransX = size.fWidth  - (1.5f * width);
+            maxTransY = size.fHeight - (1.5f * height);
         } else if (kTranslate_Type == fType) {
-            maxTransX = SkIntToScalar(size.fWidth  - kCheckerboardWidth);
-            maxTransY = SkIntToScalar(size.fHeight - kCheckerboardHeight);
+            maxTransX = SkIntToScalar(size.fWidth  - width);
+            maxTransY = SkIntToScalar(size.fHeight - height);
         } else {
             SkASSERT(kRotate_Type == fType);
             // Yes, some rotations will be off the top and left sides
-            maxTransX = size.fWidth  - SK_ScalarSqrt2 * kCheckerboardHeight;
-            maxTransY = size.fHeight - SK_ScalarSqrt2 * kCheckerboardHeight;
+            maxTransX = size.fWidth  - SK_ScalarSqrt2 * height;
+            maxTransY = size.fHeight - SK_ScalarSqrt2 * height;
         }
 
         SkMatrix mat;
-        SkIRect src = { 0, 0, kCheckerboardWidth, kCheckerboardHeight };
-        SkRect dst = { 0, 0, kCheckerboardWidth, kCheckerboardHeight };
-        SkRect clearRect = { -1.0f, -1.0f,
-                             kCheckerboardWidth+1.0f, kCheckerboardHeight+1.0f };
+        SkIRect src = { 0, 0, width, height };
+        SkRect dst = { 0, 0, SkIntToScalar(width), SkIntToScalar(height) };
+        SkRect clearRect = { -1.0f, -1.0f, width+1.0f, height+1.0f };
 
         SkPaint p;
         p.setColor(0xFF000000);
@@ -108,7 +127,7 @@
         for (int i = 0; i < kNumRects; ++i, ++fNumSaved) {
 
             if (0 == i % kNumBeforeClear) {
-                if (fPartialClear) {
+                if (kPartial_Clear == fClear) {
                     for (int j = 0; j < fNumSaved; ++j) {
                         canvas->setMatrix(SkMatrix::I());
                         mat.setTranslate(fSaved[j][0], fSaved[j][1]);
@@ -152,13 +171,31 @@
             }
 
             canvas->concat(mat);
-            canvas->drawBitmapRect(fCheckerboard, &src, dst, &p);
+            if (fUseAtlas) { 
+                static int curCell = 0;
+                src = fAtlasRects[curCell % (kNumAtlasedX)][curCell / (kNumAtlasedX)];
+                curCell = (curCell + 1) % (kNumAtlasedX*kNumAtlasedY);
+                canvas->drawBitmapRect(fAtlas, &src, dst, &p);
+            } else {
+                canvas->drawBitmapRect(fCheckerboard, &src, dst, &p);
+            }
         }
     }
 
 private:
     static const int kCheckerboardWidth = 64;
     static const int kCheckerboardHeight = 128;
+
+    static const int kAtlasCellWidth = 48;
+    static const int kAtlasCellHeight = 36;
+    static const int kNumAtlasedX = 5;
+    static const int kNumAtlasedY = 5;
+    static const int kAtlasSpacer = 2;
+    static const int kTotAtlasWidth  = kNumAtlasedX * kAtlasCellWidth +
+                                       (kNumAtlasedX+1) * kAtlasSpacer;
+    static const int kTotAtlasHeight = kNumAtlasedY * kAtlasCellHeight +
+                                       (kNumAtlasedY+1) * kAtlasSpacer;
+
 #ifdef SK_DEBUG
     static const int kNumRects = 100;
     static const int kNumBeforeClear = 10;
@@ -169,15 +206,19 @@
 
 
     Type     fType;
-    bool     fPartialClear;
+    Clear    fClear;
     bool     fAligned;
+    bool     fUseAtlas;
     SkString fName;
     int      fNumSaved; // num draws stored in 'fSaved'
     bool     fInitialized;
 
     // 0 & 1 are always x & y translate. 2 is either scale or rotate.
     SkScalar fSaved[kNumBeforeClear][3];
+
     SkBitmap fCheckerboard;
+    SkBitmap fAtlas;
+    SkIRect  fAtlasRects[kNumAtlasedX][kNumAtlasedY];
 
     // Note: the resulting checker board has transparency
     void makeCheckerboard() {
@@ -202,17 +243,70 @@
         }
     }
 
+    // Note: the resulting atlas has transparency
+    void makeAtlas() {
+        SkMWCRandom rand;
+
+        SkColor colors[kNumAtlasedX][kNumAtlasedY];
+
+        for (int y = 0; y < kNumAtlasedY; ++y) {
+            for (int x = 0; x < kNumAtlasedX; ++x) {
+                colors[x][y] = rand.nextU() | 0xff000000;
+                fAtlasRects[x][y] = SkIRect::MakeXYWH(kAtlasSpacer + x * (kAtlasCellWidth + kAtlasSpacer),
+                                                      kAtlasSpacer + y * (kAtlasCellHeight + kAtlasSpacer),
+                                                      kAtlasCellWidth,
+                                                      kAtlasCellHeight);
+            }
+        }
+
+
+        fAtlas.setConfig(SkBitmap::kARGB_8888_Config, kTotAtlasWidth, kTotAtlasHeight);
+        fAtlas.allocPixels();
+        SkAutoLockPixels lock(fAtlas);
+
+        for (int y = 0; y < kTotAtlasHeight; ++y) {
+            int colorY = y / (kAtlasCellHeight + kAtlasSpacer);
+            bool inColorY = (y % (kAtlasCellHeight + kAtlasSpacer)) >= kAtlasSpacer;
+
+            SkPMColor* scanline = fAtlas.getAddr32(0, y);
+
+            for (int x = 0; x < kTotAtlasWidth; ++x, ++scanline) {
+                int colorX = x / (kAtlasCellWidth + kAtlasSpacer);
+                bool inColorX = (x % (kAtlasCellWidth + kAtlasSpacer)) >= kAtlasSpacer;
+
+                if (inColorX && inColorY) {
+                    SkASSERT(colorX < kNumAtlasedX && colorY < kNumAtlasedY);
+                    *scanline = colors[colorX][colorY];
+                } else {
+                    *scanline = 0x00000000;
+                }
+            }
+        }
+    }
+
     typedef SkBenchmark INHERITED;
 };
 
 // Partial clear
-DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kScale_Type, false)); )
-DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, false)); )
-DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, false, true)); )
-DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kRotate_Type, false)); )
+DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kScale_Type, 
+                                            GameBench::kPartial_Clear)); )
+DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, 
+                                            GameBench::kPartial_Clear)); )
+DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, 
+                                            GameBench::kPartial_Clear, true)); )
+DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kRotate_Type, 
+                                            GameBench::kPartial_Clear)); )
 
 // Full clear
-DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kScale_Type, true)); )
-DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, true)); )
-DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, true, true)); )
-DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kRotate_Type, true)); )
+DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kScale_Type, 
+                                            GameBench::kFull_Clear)); )
+DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, 
+                                            GameBench::kFull_Clear)); )
+DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, 
+                                            GameBench::kFull_Clear, true)); )
+DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kRotate_Type, 
+                                            GameBench::kFull_Clear)); )
+
+// Atlased
+DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, 
+                                            GameBench::kFull_Clear, false, true)); )