Index: gm/xfermodes3.cpp |
diff --git a/gm/xfermodes3.cpp b/gm/xfermodes3.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c14c7856a995fbf2c0844f4c9569485bdbb87f96 |
--- /dev/null |
+++ b/gm/xfermodes3.cpp |
@@ -0,0 +1,236 @@ |
+ |
+/* |
+ * Copyright 2013 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 "SkBitmap.h" |
+#include "SkGradientShader.h" |
+#include "SkXfermode.h" |
+#include "SkColorPriv.h" |
+ |
+#if SK_SUPPORT_GPU |
+#include "GrContext.h" |
+#include "SkGpuDevice.h" |
+#endif |
+ |
+namespace skiagm { |
+ |
+/** |
+ * This tests drawing device-covering rects with solid colors and bitmap shaders over a |
+ * checkerboard background using different xfermodes. |
+ */ |
+class Xfermodes3GM : public GM { |
+public: |
+ Xfermodes3GM() {} |
+ |
+protected: |
+ virtual SkString onShortName() SK_OVERRIDE { |
+ return SkString("xfermodes3"); |
+ } |
+ |
+ virtual SkISize onISize() SK_OVERRIDE { |
+ return make_isize(630, 620); |
+ } |
+ |
+ virtual void onDrawBackground(SkCanvas* canvas) SK_OVERRIDE { |
+ SkPaint bgPaint; |
+ bgPaint.setColor(0xFF70D0E0); |
+ canvas->drawPaint(bgPaint); |
+ } |
+ |
+ virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { |
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); |
+ |
+ SkPaint labelP; |
+ labelP.setAntiAlias(true); |
+ |
+ static const SkColor kSolidColors[] = { |
+ SK_ColorTRANSPARENT, |
+ SK_ColorBLUE, |
+ 0x80808000 |
+ }; |
+ |
+ static const SkColor kBmpAlphas[] = { |
+ 0xff, |
+ 0x80, |
+ }; |
+ |
+ SkAutoTUnref<SkCanvas> tempCanvas(this->possiblyCreateTempCanvas(canvas, kSize, kSize)); |
+ |
+ int test = 0; |
+ int x = 0, y = 0; |
+ for (size_t m = 0; m <= SkXfermode::kLastMode; ++m) { |
+ SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(m); |
+ canvas->drawText(SkXfermode::ModeName(mode), |
+ strlen(SkXfermode::ModeName(mode)), |
+ SkIntToScalar(x), |
+ SkIntToScalar(y + kSize + 3) + labelP.getTextSize(), |
+ labelP); |
+ for (size_t c = 0; c < SK_ARRAY_COUNT(kSolidColors); ++c) { |
+ SkPaint modePaint; |
+ modePaint.setXfermodeMode(mode); |
+ modePaint.setColor(kSolidColors[c]); |
+ |
+ this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get()); |
+ |
+ ++test; |
+ x += kSize + 10; |
+ if (!(test % kTestsPerRow)) { |
+ x = 0; |
+ y += kSize + 30; |
+ } |
+ } |
+ for (size_t a = 0; a < SK_ARRAY_COUNT(kBmpAlphas); ++a) { |
+ SkPaint modePaint; |
+ modePaint.setXfermodeMode(mode); |
+ modePaint.setAlpha(kBmpAlphas[a]); |
+ modePaint.setShader(fBmpShader); |
+ |
+ this->drawMode(canvas, x, y, kSize, kSize, modePaint, tempCanvas.get()); |
+ |
+ ++test; |
+ x += kSize + 10; |
+ if (!(test % kTestsPerRow)) { |
+ x = 0; |
+ y += kSize + 30; |
+ } |
+ } |
+ } |
+ } |
+ |
+private: |
+ /** |
+ * GrContext has optimizations around full rendertarget draws that can be replaced with clears. |
+ * We are trying to test those. We could use saveLayer() to create small SkGpuDevices but |
+ * saveLayer() uses the texture cache. This means that the actual render target may be larger |
+ * than the layer. Because the clip will contain the layer's bounds, no draws will be full-RT. |
+ * So when running on a GPU canvas we explicitly create a temporary canvas using a texture with |
+ * dimensions exactly matching the layer size. |
+ */ |
+ SkCanvas* possiblyCreateTempCanvas(SkCanvas* baseCanvas, int w, int h) { |
+ SkCanvas* tempCanvas = NULL; |
+#if SK_SUPPORT_GPU |
+ GrRenderTarget* rt = baseCanvas->getDevice()->accessRenderTarget(); |
+ if (NULL != rt) { |
+ GrContext* context = rt->getContext(); |
+ GrTextureDesc desc; |
+ desc.fWidth = w; |
+ desc.fHeight = h; |
+ desc.fConfig = rt->config(); |
+ desc.fFlags = kRenderTarget_GrTextureFlagBit; |
+ SkAutoTUnref<GrSurface> surface(context->createUncachedTexture(desc, NULL, 0)); |
+ SkAutoTUnref<SkDevice> device(SkGpuDevice::Create(surface.get())); |
+ if (NULL != device.get()) { |
+ tempCanvas = SkNEW_ARGS(SkCanvas, (device.get())); |
+ } |
+ } |
+#endif |
+ return tempCanvas; |
+ } |
+ |
+ void drawMode(SkCanvas* canvas, |
+ int x, int y, int w, int h, |
+ const SkPaint& modePaint, SkCanvas* layerCanvas) { |
+ canvas->save(); |
+ |
+ canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); |
+ |
+ SkRect r = SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h)); |
+ |
+ SkCanvas* modeCanvas; |
+ if (NULL == layerCanvas) { |
+ canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag); |
+ modeCanvas = canvas; |
+ } else { |
+ modeCanvas = layerCanvas; |
+ } |
+ |
+ SkPaint bgPaint; |
+ bgPaint.setAntiAlias(false); |
+ bgPaint.setShader(fBGShader); |
+ modeCanvas->drawRect(r, bgPaint); |
+ modeCanvas->drawRect(r, modePaint); |
+ modeCanvas = NULL; |
+ |
+ if (NULL == layerCanvas) { |
+ canvas->restore(); |
+ } else { |
+ SkBitmap bitmap = layerCanvas->getDevice()->accessBitmap(false); |
+ canvas->drawBitmap(bitmap, 0, 0); |
+ } |
+ |
+ r.inset(-SK_ScalarHalf, -SK_ScalarHalf); |
+ SkPaint borderPaint; |
+ borderPaint.setStyle(SkPaint::kStroke_Style); |
+ canvas->drawRect(r, borderPaint); |
+ |
+ canvas->restore(); |
+ } |
+ |
+ virtual void onOnceBeforeDraw() SK_OVERRIDE { |
+ static const uint32_t kCheckData[] = { |
+ SkPackARGB32(0xFF, 0x40, 0x40, 0x40), |
+ SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0), |
+ SkPackARGB32(0xFF, 0xD0, 0xD0, 0xD0), |
+ SkPackARGB32(0xFF, 0x40, 0x40, 0x40) |
+ }; |
+ SkBitmap bg; |
+ bg.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); |
+ bg.allocPixels(); |
+ SkAutoLockPixels bgAlp(bg); |
+ memcpy(bg.getPixels(), kCheckData, sizeof(kCheckData)); |
+ bg.setIsOpaque(true); |
+ |
+ fBGShader.reset(SkShader::CreateBitmapShader(bg, |
+ SkShader::kRepeat_TileMode, |
+ SkShader::kRepeat_TileMode)); |
+ SkMatrix lm; |
+ lm.setScale(SkIntToScalar(kCheckSize), SkIntToScalar(kCheckSize)); |
+ fBGShader->setLocalMatrix(lm); |
+ |
+ SkPaint bmpPaint; |
+ static const SkPoint kCenter = { SkIntToScalar(kSize) / 2, SkIntToScalar(kSize) / 2 }; |
+ static const SkColor kColors[] = { SK_ColorTRANSPARENT, 0x80800000, |
+ 0xF020F060, SK_ColorWHITE }; |
+ bmpPaint.setShader(SkGradientShader::CreateRadial(kCenter, |
+ 3 * SkIntToScalar(kSize) / 4, |
+ kColors, |
+ NULL, |
+ SK_ARRAY_COUNT(kColors), |
+ SkShader::kRepeat_TileMode))->unref(); |
+ |
+ SkBitmap bmp; |
+ bmp.setConfig(SkBitmap::kARGB_8888_Config, kSize, kSize); |
+ bmp.allocPixels(); |
+ SkCanvas bmpCanvas(bmp); |
+ |
+ bmpCanvas.clear(SK_ColorTRANSPARENT); |
+ SkRect rect = { SkIntToScalar(kSize) / 8, SkIntToScalar(kSize) / 8, |
+ 7 * SkIntToScalar(kSize) / 8, 7 * SkIntToScalar(kSize) / 8}; |
+ bmpCanvas.drawRect(rect, bmpPaint); |
+ |
+ fBmpShader.reset(SkShader::CreateBitmapShader(bmp, |
+ SkShader::kClamp_TileMode, |
+ SkShader::kClamp_TileMode)); |
+ } |
+ |
+ enum { |
+ kCheckSize = 8, |
+ kSize = 30, |
+ kTestsPerRow = 15, |
+ }; |
+ |
+ SkAutoTUnref<SkShader> fBGShader; |
+ SkAutoTUnref<SkShader> fBmpShader; |
+ |
+ typedef GM INHERITED; |
+}; |
+ |
+////////////////////////////////////////////////////////////////////////////// |
+ |
+DEF_GM(return new Xfermodes3GM;) |
+ |
+} |