Added GM test to stress test the texture unit/sampler allocation

http://codereview.appspot.com/6134058/



git-svn-id: http://skia.googlecode.com/svn/trunk@3814 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/samplerstress.cpp b/gm/samplerstress.cpp
new file mode 100644
index 0000000..64abeec
--- /dev/null
+++ b/gm/samplerstress.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkShader.h"
+#include "SkMaskFilter.h"
+
+namespace skiagm {
+
+
+/**
+ * Simple MaskFilter that creates a screen door stipple pattern
+ */
+class SkStippleMaskFilter : public SkMaskFilter {
+public:
+    SkStippleMaskFilter() : INHERITED() {
+    }
+
+    virtual ~SkStippleMaskFilter() {
+    }
+
+    virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
+                            SkIPoint* margin) SK_OVERRIDE {
+
+        if (src.fFormat != SkMask::kA8_Format) {
+            return false;
+        }
+
+        dst->fBounds = src.fBounds;
+        dst->fRowBytes = dst->fBounds.width();
+        dst->fFormat = SkMask::kA8_Format;
+        dst->fImage = NULL;
+
+        if (NULL != src.fImage) {
+            size_t dstSize = dst->computeImageSize();
+            if (0 == dstSize) {
+                return false;   // too big to allocate, abort
+            }
+
+            dst->fImage = SkMask::AllocImage(dstSize);
+
+            uint8_t* srcScanLine = src.fImage;
+            uint8_t* scanline = dst->fImage;
+
+            for (int y = 0; y < src.fBounds.height(); ++y) {
+                for (int x = 0; x < src.fBounds.width(); ++x) {
+                    SkASSERT(unsigned int(scanline - dst->fImage) < dstSize);
+                    scanline[x] = srcScanLine[x] && ((x+y) % 2) ? 0xFF : 0x00;
+                }
+                scanline += dst->fRowBytes;
+                srcScanLine += src.fRowBytes;
+            }
+        }
+
+        return true;
+    }
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+        return SkNEW(SkStippleMaskFilter);
+    }
+
+    virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {}
+
+    // getFactory is from SkFlattenable
+    virtual Factory getFactory() SK_OVERRIDE {
+        return CreateProc;
+    }
+
+    // getFormat is from SkMaskFilter
+    virtual SkMask::Format getFormat() SK_OVERRIDE {
+        return SkMask::kA8_Format;
+    }
+protected:
+
+private:
+    typedef SkMaskFilter INHERITED;
+};
+
+/** 
+ * Stress test the samplers by rendering a textured glyph with a mask and
+ * an AA clip
+ */
+class SamplerStressGM : public GM {
+public:
+    SamplerStressGM() 
+    : fTextureCreated(false)
+    , fShader(NULL)
+    , fMaskFilter(NULL) {
+    }
+
+    virtual ~SamplerStressGM() {
+    }
+
+protected:
+    virtual SkString onShortName() {
+        return SkString("samplerstress");
+    }
+
+    virtual SkISize onISize() {
+        return make_isize(640, 480);
+    }
+
+    /**
+     * Create a red & green stripes on black texture
+     */
+    void createTexture() {
+        if (fTextureCreated) {
+            return;
+        }
+
+        static const int xSize = 16;
+        static const int ySize = 16;
+
+        fTexture.setConfig(SkBitmap::kARGB_8888_Config, 
+                           xSize,
+                           ySize,
+                           xSize*sizeof(SkColor));
+
+        fTexture.allocPixels();
+        fTexture.lockPixels();
+        SkPMColor* addr = fTexture.getAddr32(0, 0);
+
+        for (int y = 0; y < ySize; ++y) {
+            for (int x = 0; x < xSize; ++x) {
+                addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorBLACK);
+
+                if ((y % 5) == 0) {
+                    addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorRED);
+                }
+                if ((x % 7) == 0) {
+                    addr[y*xSize+x] = SkPreMultiplyColor(SK_ColorGREEN);
+                }
+            }
+        }
+
+        fTexture.unlockPixels();
+
+        fTextureCreated = true;
+    }
+
+    void createShader() {
+        if (NULL != fShader.get()) {
+            return;
+        }
+
+        createTexture();
+
+        fShader.reset(SkShader::CreateBitmapShader(fTexture,
+                                                   SkShader::kRepeat_TileMode,
+                                                   SkShader::kRepeat_TileMode));
+    }
+
+    void createMaskFilter() {
+        if (NULL != fMaskFilter.get()) {
+            return;
+        }
+
+        fMaskFilter.reset(SkNEW(SkStippleMaskFilter));
+    }
+
+    virtual void onDraw(SkCanvas* canvas) {
+
+        createShader();
+        createMaskFilter();
+
+        canvas->save();
+
+        // draw a letter "M" with a green & red striped texture and a
+        // stipple mask with a round rect soft clip
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setTextSize(72);
+        paint.setShader(fShader.get());
+        paint.setMaskFilter(fMaskFilter.get());
+
+        SkRect temp;
+        temp.set(SkIntToScalar(115),
+                 SkIntToScalar(75),
+                 SkIntToScalar(144),
+                 SkIntToScalar(110));
+
+        SkPath path;
+        path.addRoundRect(temp, SkIntToScalar(5), SkIntToScalar(5));
+
+        canvas->clipPath(path, SkRegion::kReplace_Op, true); // AA is on
+
+        canvas->drawText("M", 1,
+                         SkIntToScalar(100), SkIntToScalar(100),
+                         paint);
+
+        canvas->restore();
+
+        // Now draw stroked versions of the "M" and the round rect so we can
+        // see what is going on
+        SkPaint paint2;
+        paint2.setColor(SK_ColorBLACK);
+        paint2.setAntiAlias(true);
+        paint2.setTextSize(72);
+        paint2.setStyle(SkPaint::kStroke_Style);
+        paint2.setStrokeWidth(1);
+        canvas->drawText("M", 1,
+                         SkIntToScalar(100), SkIntToScalar(100),
+                         paint2);
+
+        paint2.setColor(SK_ColorGRAY);
+
+        canvas->drawPath(path, paint2);
+    }
+
+private:
+    SkBitmap      fTexture;
+    bool          fTextureCreated;
+    SkAutoTUnref<SkShader>     fShader;
+    SkAutoTUnref<SkMaskFilter> fMaskFilter;
+
+    typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new SamplerStressGM; }
+static GMRegistry reg(MyFactory);
+
+}