From cf40e307cd7c78c3ac8812229a7f4f2796b8688e Mon Sep 17 00:00:00 2001 From: Jim Van Verth Date: Thu, 2 Mar 2017 11:28:43 -0500 Subject: [PATCH] Use fast path for circular shadows. 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 Reviewed-by: Brian Salomon --- samplecode/SampleAndroidShadows.cpp | 2 +- .../shadows/SkAmbientShadowMaskFilter.cpp | 14 +++++------ src/gpu/ops/GrShadowRRectOp.cpp | 23 +------------------ src/utils/SkShadowUtils.cpp | 22 ++++++++++++++++++ 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp index 803ea49f4a..cad8f5012e 100644 --- a/samplecode/SampleAndroidShadows.cpp +++ b/samplecode/SampleAndroidShadows.cpp @@ -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); diff --git a/src/effects/shadows/SkAmbientShadowMaskFilter.cpp b/src/effects/shadows/SkAmbientShadowMaskFilter.cpp index 9db75c5acb..b6f5392cb1 100644 --- a/src/effects/shadows/SkAmbientShadowMaskFilter.cpp +++ b/src/effects/shadows/SkAmbientShadowMaskFilter.cpp @@ -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, diff --git a/src/gpu/ops/GrShadowRRectOp.cpp b/src/gpu/ops/GrShadowRRectOp.cpp index 6a848b8332..637c38a67d 100644 --- a/src/gpu/ops/GrShadowRRectOp.cpp +++ b/src/gpu/ops/GrShadowRRectOp.cpp @@ -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 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); diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp index 88ebaf5c8f..94dd113a5f 100644 --- a/src/utils/SkShadowUtils.cpp +++ b/src/utils/SkShadowUtils.cpp @@ -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);