Use fast path for circular shadows.
authorJim Van Verth <jvanverth@google.com>
Thu, 2 Mar 2017 16:28:43 +0000 (11:28 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Thu, 2 Mar 2017 17:40:00 +0000 (17:40 +0000)
Also cleans up some of the MaskFilter code to make it
more correct.

BUG=skia:6119

Change-Id: I93016bcdd9c55fcb2d1dc8776428a72eb563d67a
Reviewed-on: https://skia-review.googlesource.com/9116
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
samplecode/SampleAndroidShadows.cpp
src/effects/shadows/SkAmbientShadowMaskFilter.cpp
src/gpu/ops/GrShadowRRectOp.cpp
src/utils/SkShadowUtils.cpp

index 803ea49..cad8f50 100644 (file)
@@ -469,7 +469,7 @@ protected:
         canvas->translate(-250, 110);
         lightPos.fX -= 250;
         lightPos.fY += 110;
-        this->drawShadowedPath(canvas, fCirclePath, SkTMax(1.0f, 8+fZDelta), paint, 0,
+        this->drawShadowedPath(canvas, fCirclePath, SkTMax(1.0f, 8+fZDelta), paint, kAmbientAlpha,
                                lightPos, kLightWidth, 0.5f);
 
         paint.setColor(SK_ColorGREEN);
index 9db75c5..b6f5392 100644 (file)
@@ -220,12 +220,12 @@ bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
     if (fAmbientAlpha > 0.0f) {
         SkScalar srcSpaceAmbientRadius = fOccluderHeight * kHeightFactor * kGeomFactor;
         const float umbraAlpha = (1.0f + SkTMax(fOccluderHeight * kHeightFactor, 0.0f));
-        const SkScalar ambientOffset = srcSpaceAmbientRadius / umbraAlpha;
+        const SkScalar strokeWidth = srcSpaceAmbientRadius * umbraAlpha;
 
-        // For the ambient rrect, we inset the offset rect by half the srcSpaceAmbientRadius
-        // to get our stroke shape.
-        SkScalar ambientPathOutset = SkTMax(ambientOffset - srcSpaceAmbientRadius * 0.5f,
-                                              minRadius);
+        // For the ambient rrect, we outset the offset rect by srcSpaceAmbientRadius
+        // minus half the strokeWidth to get our stroke shape.
+        SkScalar ambientPathOutset = SkTMax(srcSpaceAmbientRadius - strokeWidth * 0.5f,
+                                            minRadius);
 
         SkRRect ambientRRect;
         if (isRect) {
@@ -235,14 +235,14 @@ bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
              rrect.outset(ambientPathOutset, ambientPathOutset, &ambientRRect);
         }
 
-        const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor;
+        const SkScalar devSpaceAmbientRadius = strokeWidth * scaleFactor;
 
         GrPaint newPaint(paint);
         GrColor4f color = newPaint.getColor4f();
         color.fRGBA[3] *= fAmbientAlpha;
         newPaint.setColor4f(color);
         SkStrokeRec ambientStrokeRec(SkStrokeRec::kHairline_InitStyle);
-        ambientStrokeRec.setStrokeStyle(srcSpaceAmbientRadius, false);
+        ambientStrokeRec.setStrokeStyle(strokeWidth, false);
 
         rtContext->drawShadowRRect(clip, std::move(newPaint), viewMatrix, ambientRRect,
                                    devSpaceAmbientRadius,
index 6a848b8..637c38a 100644 (file)
@@ -101,13 +101,6 @@ public:
             }
         }
 
-        // TODO: still needed?
-        // The radii are outset for two reasons. First, it allows the shader to simply perform
-        // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
-        // Second, the outer radius is used to compute the verts of the bounding box that is
-        // rendered and the outset ensures the box will cover all partially covered by the circle.
-        outerRadius += SK_ScalarHalf;
-        innerRadius -= SK_ScalarHalf;
         bool stroked = isStrokeOnly && innerRadius > 0.0f;
         std::unique_ptr<ShadowCircleOp> op(new ShadowCircleOp());
         op->fViewMatrixIfUsingLocalCoords = viewMatrix;
@@ -533,8 +526,6 @@ public:
             }
 
             if (strokeOnly) {
-                // Outset stroke by 1/4 pixel
-                devStrokeWidth += 0.25f;
                 // If stroke is greater than width or height, this is still a fill
                 // Otherwise we compute stroke params
                 if (devStrokeWidth <= devRect.width() && devStrokeWidth <= devRect.height()) {
@@ -546,19 +537,7 @@ public:
             bounds.outset(halfWidth, halfWidth);
         }
 
-        // TODO: still needed?
-        // The radii are outset for two reasons. First, it allows the shader to simply perform
-        // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
-        // Second, the outer radius is used to compute the verts of the bounding box that is
-        // rendered and the outset ensures the box will cover all partially covered by the rrect
-        // corners.
-        outerRadius += SK_ScalarHalf;
-        innerRadius -= SK_ScalarHalf;
-
-        this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo);
-
-        // Expand the rect for aa to generate correct vertices.
-        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
+        this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
 
         fGeoData.emplace_back(Geometry{color, outerRadius, innerRadius, blurRadius, bounds, type});
         fVertCount = rrect_type_to_vert_count(type);
index 88ebaf5..94dd113 100644 (file)
@@ -18,6 +18,8 @@
 #include "GrShape.h"
 #include "effects/GrBlurredEdgeFragmentProcessor.h"
 #endif
+#include "../../src/effects/shadows/SkAmbientShadowMaskFilter.h"
+#include "../../src/effects/shadows/SkSpotShadowMaskFilter.h"
 
 /**
 *  Gaussian color filter -- produces a Gaussian ramp based on the color's B value,
@@ -457,6 +459,26 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
                                uint32_t flags, SkResourceCache* cache) {
     SkAutoCanvasRestore acr(canvas, true);
     SkMatrix viewMatrix = canvas->getTotalMatrix();
+
+    // try circular fast path
+    SkRect rect;
+    if (viewMatrix.isSimilarity() &&
+        path.isOval(&rect) && rect.width() == rect.height()) {
+        SkPaint newPaint;
+        newPaint.setColor(color);
+        if (ambientAlpha > 0) {
+            newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderHeight, ambientAlpha,
+                                                                   flags));
+            canvas->drawPath(path, newPaint);
+        }
+        if (spotAlpha > 0) {
+            newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderHeight, devLightPos,
+                                                                lightRadius, spotAlpha, flags));
+            canvas->drawPath(path, newPaint);
+        }
+        return;
+    }
+
     canvas->resetMatrix();
 
     ShadowedPath shadowedPath(&path, &viewMatrix);