Fix transparent ambient shadows
authorJim Van Verth <jvanverth@google.com>
Thu, 11 May 2017 14:43:35 +0000 (10:43 -0400)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Thu, 11 May 2017 15:09:27 +0000 (15:09 +0000)
Add a clamp value to indicate the percentage of the blurWidth to apply.

Change-Id: I962dc57ed786fa67ed1606b1148f1b2c568025e5
Reviewed-on: https://skia-review.googlesource.com/16424
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
src/effects/shadows/SkAmbientShadowMaskFilter.cpp
src/gpu/GrRenderTargetContext.cpp
src/gpu/GrRenderTargetContext.h
src/gpu/effects/GrShadowGeoProc.cpp
src/gpu/ops/GrShadowRRectOp.cpp
src/gpu/ops/GrShadowRRectOp.h

index 3416835..66218cd 100644 (file)
@@ -221,8 +221,12 @@ bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
         devSpaceInsetWidth = ambientRRect.width();
     }
 
+    // the fraction of the blur we want to apply is devSpaceInsetWidth/devSpaceAmbientBlur,
+    // which is just 1/umbraAlpha.
+    SkScalar blurClamp = SkScalarInvert(umbraAlpha);
     rtContext->drawShadowRRect(clip, std::move(newPaint), viewMatrix, ambientRRect,
-                               devSpaceAmbientBlur, devSpaceInsetWidth);
+                               devSpaceAmbientBlur, devSpaceInsetWidth,
+                               blurClamp);
 
     return true;
 }
index 12ddb96..56e2c2f 100644 (file)
@@ -986,7 +986,8 @@ void GrRenderTargetContext::drawShadowRRect(const GrClip& clip,
                                             const SkMatrix& viewMatrix,
                                             const SkRRect& rrect,
                                             SkScalar blurWidth,
-                                            SkScalar insetWidth) {
+                                            SkScalar insetWidth,
+                                            SkScalar blurClamp) {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
@@ -999,7 +1000,8 @@ void GrRenderTargetContext::drawShadowRRect(const GrClip& clip,
     // TODO: add instancing support?
 
     std::unique_ptr<GrLegacyMeshDrawOp> op = GrShadowRRectOp::Make(paint.getColor(), viewMatrix,
-                                                                   rrect, blurWidth, insetWidth);
+                                                                   rrect, blurWidth, insetWidth,
+                                                                   blurClamp);
     if (op) {
         GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
         this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
index b3ff137..5aef96a 100644 (file)
@@ -161,13 +161,15 @@ public:
      * @param blurWidth    amount of shadow blur to apply (in device space)
      * @param insetWidth   minimum amount to inset from the rrect edge (in local space).
      *                     We may inset more depending on the blur radius and geometry.
+     * @param blurClamp    Optional parameter used to indicate fraction of blur to actually apply
      */
     void drawShadowRRect(const GrClip&,
                          GrPaint&&,
                          const SkMatrix& viewMatrix,
                          const SkRRect& rrect,
                          SkScalar blurRadius,
-                         SkScalar insetWidth);
+                         SkScalar insetWidth,
+                         SkScalar blurClamp = 1);
 
     /**
      * Shortcut for filling a SkPath consisting of nested rrects using a paint. The result is
index 4e33e4b..5ff7ec1 100644 (file)
@@ -26,7 +26,7 @@ public:
 
         // emit attributes
         varyingHandler->emitAttributes(rsgp);
-        fragBuilder->codeAppend("vec3 shadowParams;");
+        fragBuilder->codeAppend("vec4 shadowParams;");
         varyingHandler->addPassThroughAttribute(rsgp.inShadowParams(), "shadowParams");
 
         // setup pass through color
@@ -47,7 +47,7 @@ public:
         fragBuilder->codeAppend("float d = length(shadowParams.xy);");
         fragBuilder->codeAppend("float distance = shadowParams.z * (1.0 - d);");
 
-        fragBuilder->codeAppend("float factor = 1.0 - clamp(distance, 0.0, 1.0);");
+        fragBuilder->codeAppend("float factor = 1.0 - clamp(distance, 0.0, shadowParams.w);");
         fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
         fragBuilder->codeAppendf("%s = vec4(factor);",
                                  args.fOutputCoverage);
@@ -81,7 +81,7 @@ GrRRectShadowGeoProc::GrRRectShadowGeoProc(const SkMatrix& localMatrix)
     fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
                                          kHigh_GrSLPrecision);
     fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
-    fInShadowParams = &this->addVertexAttrib("inShadowParams", kVec3f_GrVertexAttribType);
+    fInShadowParams = &this->addVertexAttrib("inShadowParams", kVec4f_GrVertexAttribType);
 }
 
 void GrRRectShadowGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
index 77cd5ef..43c8839 100644 (file)
@@ -190,7 +190,8 @@ public:
 
     // An insetWidth > 1/2 rect width or height indicates a simple fill.
     ShadowCircularRRectOp(GrColor color, const SkMatrix& viewMatrix, const SkRect& devRect,
-                          float devRadius, bool isCircle, float blurRadius, float insetWidth)
+                          float devRadius, bool isCircle, float blurRadius, float insetWidth,
+                          float blurClamp)
             : INHERITED(ClassID()), fViewMatrixIfUsingLocalCoords(viewMatrix) {
         SkRect bounds = devRect;
         SkASSERT(insetWidth > 0);
@@ -226,7 +227,7 @@ public:
         this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
 
         fGeoData.emplace_back(Geometry{color, outerRadius, umbraInset, innerRadius,
-                                       blurRadius, bounds, type, isCircle});
+                                       blurRadius, blurClamp, bounds, type, isCircle});
         if (isCircle) {
             fVertCount = circle_type_to_vert_count(kStroke_RRectType == type);
             fIndexCount = circle_type_to_index_count(kStroke_RRectType == type);
@@ -274,6 +275,7 @@ private:
         SkScalar  fUmbraInset;
         SkScalar  fInnerRadius;
         SkScalar  fBlurRadius;
+        SkScalar  fClampValue;
         SkRect    fDevBounds;
         RRectType fType;
         bool      fIsCircle;
@@ -284,6 +286,7 @@ private:
         GrColor fColor;
         SkPoint fOffset;
         SkScalar fDistanceCorrection;
+        SkScalar fClampValue;
     };
 
     void fillInCircleVerts(const Geometry& args, bool isStroked, CircleVertex** verts) const {
@@ -293,6 +296,7 @@ private:
         SkScalar innerRadius = args.fInnerRadius;
         SkScalar blurRadius = args.fBlurRadius;
         SkScalar distanceCorrection = outerRadius / blurRadius;
+        SkScalar clampValue = args.fClampValue;
 
         const SkRect& bounds = args.fDevBounds;
 
@@ -307,48 +311,56 @@ private:
         (*verts)->fColor = color;
         (*verts)->fOffset = SkPoint::Make(-octOffset, -1);
         (*verts)->fDistanceCorrection = distanceCorrection;
+        (*verts)->fClampValue = clampValue;
         (*verts)++;
 
         (*verts)->fPos = center + SkPoint::Make(octOffset * halfWidth, -halfWidth);
         (*verts)->fColor = color;
         (*verts)->fOffset = SkPoint::Make(octOffset, -1);
         (*verts)->fDistanceCorrection = distanceCorrection;
+        (*verts)->fClampValue = clampValue;
         (*verts)++;
 
         (*verts)->fPos = center + SkPoint::Make(halfWidth, -octOffset * halfWidth);
         (*verts)->fColor = color;
         (*verts)->fOffset = SkPoint::Make(1, -octOffset);
         (*verts)->fDistanceCorrection = distanceCorrection;
+        (*verts)->fClampValue = clampValue;
         (*verts)++;
 
         (*verts)->fPos = center + SkPoint::Make(halfWidth, octOffset * halfWidth);
         (*verts)->fColor = color;
         (*verts)->fOffset = SkPoint::Make(1, octOffset);
         (*verts)->fDistanceCorrection = distanceCorrection;
+        (*verts)->fClampValue = clampValue;
         (*verts)++;
 
         (*verts)->fPos = center + SkPoint::Make(octOffset * halfWidth, halfWidth);
         (*verts)->fColor = color;
         (*verts)->fOffset = SkPoint::Make(octOffset, 1);
         (*verts)->fDistanceCorrection = distanceCorrection;
+        (*verts)->fClampValue = clampValue;
         (*verts)++;
 
         (*verts)->fPos = center + SkPoint::Make(-octOffset * halfWidth, halfWidth);
         (*verts)->fColor = color;
         (*verts)->fOffset = SkPoint::Make(-octOffset, 1);
         (*verts)->fDistanceCorrection = distanceCorrection;
+        (*verts)->fClampValue = clampValue;
         (*verts)++;
 
         (*verts)->fPos = center + SkPoint::Make(-halfWidth, octOffset * halfWidth);
         (*verts)->fColor = color;
         (*verts)->fOffset = SkPoint::Make(-1, octOffset);
         (*verts)->fDistanceCorrection = distanceCorrection;
+        (*verts)->fClampValue = clampValue;
         (*verts)++;
 
         (*verts)->fPos = center + SkPoint::Make(-halfWidth, -octOffset * halfWidth);
         (*verts)->fColor = color;
         (*verts)->fOffset = SkPoint::Make(-1, -octOffset);
         (*verts)->fDistanceCorrection = distanceCorrection;
+        (*verts)->fClampValue = clampValue;
         (*verts)++;
 
         if (isStroked) {
@@ -363,48 +375,56 @@ private:
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(-s * innerRadius, -c * innerRadius);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             (*verts)->fPos = center + SkPoint::Make(s * r, -c * r);
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(s * innerRadius, -c * innerRadius);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             (*verts)->fPos = center + SkPoint::Make(c * r, -s * r);
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(c * innerRadius, -s * innerRadius);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             (*verts)->fPos = center + SkPoint::Make(c * r, s * r);
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(c * innerRadius, s * innerRadius);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             (*verts)->fPos = center + SkPoint::Make(s * r, c * r);
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(s * innerRadius, c * innerRadius);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             (*verts)->fPos = center + SkPoint::Make(-s * r, c * r);
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(-s * innerRadius, c * innerRadius);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             (*verts)->fPos = center + SkPoint::Make(-c * r, s * r);
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(-c * innerRadius, s * innerRadius);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             (*verts)->fPos = center + SkPoint::Make(-c * r, -s * r);
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(-c * innerRadius, -s * innerRadius);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
         } else {
             // filled
@@ -412,6 +432,7 @@ private:
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(0, 0);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
         }
     }
@@ -454,6 +475,7 @@ private:
                                           outerVec.fX + outerVec.fY);
         diagVec *= umbraInset / (2 * umbraInset - outerRadius);
         SkScalar distanceCorrection = umbraInset / blurRadius;
+        SkScalar clampValue = args.fClampValue;
 
         // build corner by corner
         for (int i = 0; i < 4; ++i) {
@@ -462,6 +484,7 @@ private:
             (*verts)->fColor = color;
             (*verts)->fOffset = SkVector::Make(0, 0);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             // outer points
@@ -469,30 +492,35 @@ private:
             (*verts)->fColor = color;
             (*verts)->fOffset = SkVector::Make(0, -1);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             (*verts)->fPos = SkPoint::Make(xOuter[i], yMid[i]);
             (*verts)->fColor = color;
             (*verts)->fOffset = outerVec;
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             (*verts)->fPos = SkPoint::Make(xOuter[i], yOuter[i]);
             (*verts)->fColor = color;
             (*verts)->fOffset = diagVec;
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             (*verts)->fPos = SkPoint::Make(xMid[i], yOuter[i]);
             (*verts)->fColor = color;
             (*verts)->fOffset = outerVec;
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             (*verts)->fPos = SkPoint::Make(xInner[i], yOuter[i]);
             (*verts)->fColor = color;
             (*verts)->fOffset = SkVector::Make(0, -1);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
         }
 
@@ -510,6 +538,7 @@ private:
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(0, 0);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             // TR
@@ -517,6 +546,7 @@ private:
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(0, 0);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             // BL
@@ -524,6 +554,7 @@ private:
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(0, 0);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
 
             // BR
@@ -531,6 +562,7 @@ private:
             (*verts)->fColor = color;
             (*verts)->fOffset = SkPoint::Make(0, 0);
             (*verts)->fDistanceCorrection = distanceCorrection;
+            (*verts)->fClampValue = clampValue;
             (*verts)++;
         }
 
@@ -640,7 +672,8 @@ std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
                                          const SkMatrix& viewMatrix,
                                          const SkRRect& rrect,
                                          SkScalar blurWidth,
-                                         SkScalar insetWidth) {
+                                         SkScalar insetWidth,
+                                         SkScalar blurClamp) {
     // Shadow rrect ops only handle simple circular rrects.
     SkASSERT(viewMatrix.isSimilarity() &&
              (rrect.isSimpleCircular() || rrect.isRect() || rrect.isCircle()));
@@ -660,7 +693,8 @@ std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
                                                                          scaledRadius,
                                                                          rrect.isOval(),
                                                                          blurWidth,
-                                                                         scaledInsetWidth));
+                                                                         scaledInsetWidth,
+                                                                         blurClamp));
 }
 }
 
@@ -681,14 +715,15 @@ DRAW_OP_TEST_DEFINE(ShadowRRectOp) {
     GrColor color = GrRandomColor(random);
     SkScalar insetWidth = random->nextSScalar1() * 72.f;
     SkScalar blurWidth = random->nextSScalar1() * 72.f;
+    SkScalar blurClamp = random->nextSScalar1();
     bool isCircle = random->nextBool();
     if (isCircle) {
         SkRect circle = GrTest::TestSquare(random);
         SkRRect rrect = SkRRect::MakeOval(circle);
-        return GrShadowRRectOp::Make(color, viewMatrix, rrect, blurWidth, insetWidth);
+        return GrShadowRRectOp::Make(color, viewMatrix, rrect, blurWidth, insetWidth, blurClamp);
     } else {
         const SkRRect& rrect = GrTest::TestRRectSimple(random);
-        return GrShadowRRectOp::Make(color, viewMatrix, rrect, blurWidth, insetWidth);
+        return GrShadowRRectOp::Make(color, viewMatrix, rrect, blurWidth, insetWidth, blurClamp);
     }
 }
 
index f972788..1260095 100644 (file)
@@ -20,7 +20,8 @@ class SkStrokeRec;
 namespace GrShadowRRectOp {
 
 std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor, const SkMatrix& viewMatrix, const SkRRect& rrect,
-                                         SkScalar blurWidth, SkScalar insetWidth);
+                                         SkScalar blurWidth, SkScalar insetWidth,
+                                         SkScalar blurClamp = 1);
 }
 
 #endif