disable GPU blur on small paths

Change originally by Guanqun.Lu@gmail.com with minor edits and sample added by me

COULD POSSIBLY CHANGE GPU RESULTS OF GM SLIDES WITH BLUR, WILL REBASILINE IF SO.

Review URL: https://codereview.appspot.com/5940045/



git-svn-id: http://skia.googlecode.com/svn/trunk@3514 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/SampleApp.gyp b/gyp/SampleApp.gyp
index bdd46ed..3d79c3d 100644
--- a/gyp/SampleApp.gyp
+++ b/gyp/SampleApp.gyp
@@ -28,6 +28,7 @@
         '../samplecode/SampleAARectModes.cpp',
         '../samplecode/SampleAll.cpp',
         '../samplecode/SampleAnimator.cpp',
+        '../samplecode/SampleAnimBlur.cpp',
         '../samplecode/SampleApp.cpp',
         '../samplecode/SampleArc.cpp',
         '../samplecode/SampleAvoid.cpp',
diff --git a/samplecode/SampleAnimBlur.cpp b/samplecode/SampleAnimBlur.cpp
new file mode 100644
index 0000000..74f8811
--- /dev/null
+++ b/samplecode/SampleAnimBlur.cpp
@@ -0,0 +1,70 @@
+
+/*
+ * 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 "SampleCode.h"
+#include "SkBlurMaskFilter.h"
+#include "SkColorPriv.h"
+#include "SkCanvas.h"
+#include "SkRandom.h"
+
+class AnimBlurView : public SampleView {
+public:
+    AnimBlurView() {
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "AnimBlur");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    virtual void onDrawContent(SkCanvas* canvas) {
+
+        SkScalar blurRadius = SampleCode::GetAnimSinScalar(100 * SK_Scalar1,
+                                                           4 * SK_Scalar1,
+                                                           5 * SK_Scalar1);
+
+        SkScalar circleRadius = 3 * SK_Scalar1 +
+                                SampleCode::GetAnimSinScalar(150 * SK_Scalar1,
+                                                             25 * SK_Scalar1,
+                                                             3 * SK_Scalar1);
+
+        static const SkBlurMaskFilter::BlurStyle gStyles[] = {
+            SkBlurMaskFilter::kNormal_BlurStyle,
+            SkBlurMaskFilter::kInner_BlurStyle,
+            SkBlurMaskFilter::kSolid_BlurStyle,
+            SkBlurMaskFilter::kOuter_BlurStyle,
+        };
+        SkRandom random;
+
+        for (int i = 0; i < SK_ARRAY_COUNT(gStyles); ++i) {
+            SkMaskFilter* mf = SkBlurMaskFilter::Create(blurRadius,
+                                       gStyles[i],
+                                       SkBlurMaskFilter::kHighQuality_BlurFlag);
+            SkPaint paint;
+            paint.setMaskFilter(mf)->unref();
+            paint.setColor(random.nextU() | 0xff000000);
+            canvas->drawCircle(200 * SK_Scalar1 + 400 * (i % 2) * SK_Scalar1,
+                               200 * SK_Scalar1 + i / 2 * 400 * SK_Scalar1,
+                               circleRadius, paint);
+        }
+        this->inval(NULL);
+    }
+
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new AnimBlurView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index b2af16a..ddd33ed 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -520,6 +520,18 @@
     return SkDoubleToScalar(value);
 }
 
+SkScalar SampleCode::GetAnimSinScalar(SkScalar amplitude,
+                                      SkScalar periodInSec,
+                                      SkScalar phaseInSec) {
+    if (!periodInSec) {
+        return 0;
+    }
+    double t = (double)gAnimTime / 1000.0 + phaseInSec;
+    t *= SkScalarToFloat(2 * SK_ScalarPI) / periodInSec;
+    amplitude = SK_ScalarHalf * amplitude;
+    return SkScalarMul(amplitude, SkDoubleToScalar(sin(t))) + amplitude;
+}
+
 GrContext* SampleCode::GetGr() {
     return gSampleWindow ? gSampleWindow->getGrContext() : NULL;
 }
diff --git a/samplecode/SampleCode.h b/samplecode/SampleCode.h
index 197e0f1..3d1f266 100644
--- a/samplecode/SampleCode.h
+++ b/samplecode/SampleCode.h
@@ -35,6 +35,10 @@
     static SkMSec GetAnimTimeDelta();
     static SkScalar GetAnimSecondsDelta();
     static SkScalar GetAnimScalar(SkScalar speedPerSec, SkScalar period = 0);
+    // gives a sinusoidal value between 0 and amplitude
+    static SkScalar GetAnimSinScalar(SkScalar amplitude,
+                                     SkScalar periodInSec,
+                                     SkScalar phaseInSec = 0);
 
     static GrContext* GetGr();
 };
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 703153b..5f9879e 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -716,7 +716,12 @@
 #include "SkMaskFilter.h"
 #include "SkBounder.h"
 
-static GrPathFill skToGrFillType(SkPath::FillType fillType) {
+///////////////////////////////////////////////////////////////////////////////
+
+// helpers for applying mask filters
+namespace {
+
+GrPathFill skToGrFillType(SkPath::FillType fillType) {
     switch (fillType) {
         case SkPath::kWinding_FillType:
             return kWinding_PathFill;
@@ -732,10 +737,22 @@
     }
 }
 
-static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
-                                  SkMaskFilter* filter, const SkMatrix& matrix,
-                                  const SkRegion& clip, SkBounder* bounder,
-                                  GrPaint* grp) {
+// We prefer to blur small rect with small radius via CPU.
+#define MIN_GPU_BLUR_SIZE SkIntToScalar(64)
+#define MIN_GPU_BLUR_RADIUS SkIntToScalar(32)
+inline bool shouldDrawBlurWithCPU(const SkRect& rect, SkScalar radius) {
+    if (rect.width() <= MIN_GPU_BLUR_SIZE &&
+        rect.height() <= MIN_GPU_BLUR_SIZE &&
+        radius <= MIN_GPU_BLUR_RADIUS) {
+        return true;
+    }
+    return false;
+}
+
+bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
+                           SkMaskFilter* filter, const SkMatrix& matrix,
+                           const SkRegion& clip, SkBounder* bounder,
+                           GrPaint* grp) {
 #ifdef SK_DISABLE_GPU_BLUR
     return false;
 #endif
@@ -750,10 +767,15 @@
     if (radius <= 0) {
         return false;
     }
+
+    SkRect srcRect = path.getBounds();
+    if (shouldDrawBlurWithCPU(srcRect, radius)) {
+        return false;
+    }
+
     float sigma = SkScalarToFloat(radius) * BLUR_SIGMA_SCALE;
     float sigma3 = sigma * 3.0f;
 
-    SkRect srcRect = path.getBounds();
     SkRect clipRect;
     clipRect.set(clip.getBounds());
 
@@ -872,10 +894,10 @@
     return true;
 }
 
-static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
-                               SkMaskFilter* filter, const SkMatrix& matrix,
-                               const SkRegion& clip, SkBounder* bounder,
-                               GrPaint* grp) {
+bool drawWithMaskFilter(GrContext* context, const SkPath& path,
+                        SkMaskFilter* filter, const SkMatrix& matrix,
+                        const SkRegion& clip, SkBounder* bounder,
+                        GrPaint* grp) {
     SkMask  srcM, dstM;
 
     if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
@@ -946,6 +968,10 @@
     return true;
 }
 
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
                            const SkPaint& paint, const SkMatrix* prePathMatrix,
                            bool pathIsMutable) {