plumbing for GPU fast blur
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 10 Mar 2014 22:53:20 +0000 (22:53 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 10 Mar 2014 22:53:20 +0000 (22:53 +0000)
BUG=skia:2281
R=bsalomon@google.com

Author: humper@google.com

Review URL: https://codereview.chromium.org/193193002

git-svn-id: http://skia.googlecode.com/svn/trunk@13735 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkMaskFilter.h
include/core/SkRRect.h
src/core/SkMaskFilter.cpp
src/core/SkRRect.cpp
src/effects/SkBlurMaskFilter.cpp
src/gpu/SkGpuDevice.cpp

index 33e45552e89f95f5e1463798309a274db134977c..ac9b7189b2122b3b7280de06c2aafcdcaab6af12 100644 (file)
@@ -101,6 +101,14 @@ public:
                                      GrPaint* grp,
                                      const SkStrokeRec& strokeRec,
                                      const SkPath& path) const;
+    /**
+     *  Try to directly render a rounded rect mask filter into the target.  Returns
+     *  true if drawing was successful.
+     */
+    virtual bool directFilterRRectMaskGPU(GrContext* context,
+                                          GrPaint* grp,
+                                          const SkStrokeRec& strokeRec,
+                                          const SkRRect& rrect) const;
 
     /**
      * This function is used to implement filters that require an explicit src mask. It should only
index c996346442325659bff213a4cbe5e536984ac979..9878b54fdc0019be255f3c18551b748cd9dce8aa 100644 (file)
@@ -101,6 +101,8 @@ public:
     }
     inline bool isComplex() const { return kComplex_Type == this->getType(); }
 
+    bool allCornersCircular() const;
+
     SkScalar width() const { return fRect.width(); }
     SkScalar height() const { return fRect.height(); }
 
index b96743d129531a6083c55b366c866f7f37caec84..9b023d0d65cb0e3ea40d24c35e2e6ff77bde360d 100644 (file)
@@ -317,6 +317,13 @@ bool SkMaskFilter::canFilterMaskGPU(const SkRect& devBounds,
 }
 
 
+bool SkMaskFilter::directFilterRRectMaskGPU(GrContext* context,
+                                            GrPaint* grp,
+                                            const SkStrokeRec& strokeRec,
+                                            const SkRRect& rrect) const {
+    return false;
+}
+
 bool SkMaskFilter::filterMaskGPU(GrTexture* src,
                                  const SkMatrix& ctm,
                                  const SkRect& maskRect,
index e5296d4e3a7d83ac871c063ee112dbcf9cbbc507..915ed75327f590c567ec18a5e9e0d92f64b76ee4 100644 (file)
@@ -172,6 +172,13 @@ bool SkRRect::checkCornerContainment(SkScalar x, SkScalar y) const {
     return dist <= SkScalarSquare(SkScalarMul(fRadii[index].fX, fRadii[index].fY));
 }
 
+bool SkRRect::allCornersCircular() const {
+    return fRadii[0].fX == fRadii[0].fY &&
+        fRadii[1].fX == fRadii[1].fY &&
+        fRadii[2].fX == fRadii[2].fY &&
+        fRadii[3].fX == fRadii[3].fY;
+}
+
 bool SkRRect::contains(const SkRect& rect) const {
     if (!this->getBounds().contains(rect)) {
         // If 'rect' isn't contained by the RR's bounds then the
index 2d7ff18fdb0b9ef9a63bfd55aa1e2ab196ee22ef..63032dbc297e49fb66309caf742c998092c16dc3 100644 (file)
@@ -45,6 +45,10 @@ public:
                                      GrPaint* grp,
                                      const SkStrokeRec& strokeRec,
                                      const SkPath& path) const SK_OVERRIDE;
+    virtual bool directFilterRRectMaskGPU(GrContext* context,
+                                          GrPaint* grp,
+                                          const SkStrokeRec& strokeRec,
+                                          const SkRRect& rrect) const SK_OVERRIDE;
 
     virtual bool filterMaskGPU(GrTexture* src,
                                const SkMatrix& ctm,
@@ -815,6 +819,13 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context,
     return true;
 }
 
+bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context,
+                                                    GrPaint* grp,
+                                                    const SkStrokeRec& strokeRec,
+                                                    const SkRRect& rrect) const {
+    return false;
+}
+
 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
                                             const SkIRect& clipBounds,
                                             const SkMatrix& ctm,
index 7cecf25bb2d834ce60976e37f280f13ceb5a86c3..82862414fc682968f7b164007a65ad5bb93c25fc 100644 (file)
 
 #include "SkGrTexturePixelRef.h"
 
+#include "SkBounder.h"
 #include "SkColorFilter.h"
 #include "SkDeviceImageFilterProxy.h"
 #include "SkDrawProcs.h"
 #include "SkGlyphCache.h"
 #include "SkImageFilter.h"
+#include "SkMaskFilter.h"
 #include "SkPathEffect.h"
 #include "SkRRect.h"
 #include "SkStroke.h"
@@ -739,6 +741,44 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
     CHECK_FOR_ANNOTATION(paint);
     CHECK_SHOULD_DRAW(draw, false);
 
+    GrPaint grPaint;
+    if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
+        return;
+    }
+
+    SkStrokeRec stroke(paint);
+    if (paint.getMaskFilter()) {
+        // try to hit the fast path for drawing filtered round rects
+
+        SkRRect devRRect;
+        if (rect.transform(fContext->getMatrix(), &devRRect)) {
+            if (devRRect.allCornersCircular()) {
+                SkRect maskRect;
+                if (paint.getMaskFilter()->canFilterMaskGPU(devRRect.rect(),
+                                            draw.fClip->getBounds(),
+                                            fContext->getMatrix(),
+                                            &maskRect)) {
+                    SkIRect finalIRect;
+                    maskRect.roundOut(&finalIRect);
+                    if (draw.fClip->quickReject(finalIRect)) {
+                        // clipped out
+                        return;
+                    }
+                    if (NULL != draw.fBounder && !draw.fBounder->doIRect(finalIRect)) {
+                        // nothing to draw
+                        return;
+                    }
+                    if (paint.getMaskFilter()->directFilterRRectMaskGPU(fContext, &grPaint,
+                                                                        stroke, devRRect)) {
+                        return;
+                    }
+                }
+
+            }
+        }
+
+    }
+
     bool usePath = !rect.isSimple();
     // another two reasons we might need to call drawPath...
     if (paint.getMaskFilter() || paint.getPathEffect()) {
@@ -756,16 +796,10 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
         return;
     }
 
-    GrPaint grPaint;
-    if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
-        return;
-    }
-
-    SkStrokeRec stroke(paint);
     fContext->drawRRect(grPaint, rect, stroke);
 }
 
-///////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
 
 void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval,
                            const SkPaint& paint) {
@@ -1011,7 +1045,7 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
             }
 
             if (paint.getMaskFilter()->directFilterMaskGPU(fContext, &grPaint,
-                                                           SkStrokeRec(paint), *devPathPtr)) {
+                                                           stroke, *devPathPtr)) {
                 // the mask filter was able to draw itself directly, so there's nothing
                 // left to do.
                 return;