diff options
author | Brian Salomon <bsalomon@google.com> | 2017-12-01 13:49:50 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-12-01 20:00:09 +0000 |
commit | 096074af2c6fcbf622f0a42b2f7c56d0c66fbd80 (patch) | |
tree | c8162aad746f18fee6344567a6cf63ae11dc7dec | |
parent | b826a3ab7247fea323eb8b06372a678fbc6c3dbe (diff) |
Fix rendering of drrects with small circular inner rrects.
Previously when the inner rrect was a circle with a radius of 1 we would
cause a inf * 0 in the shader which would lead to the shape not rendering.
This change also makes concentric circle drrects draw as stroked circles.
bug: chromium:789262
Change-Id: I6efbe3fdde25d6c4e031c7412d83df009afe014a
Reviewed-on: https://skia-review.googlesource.com/79141
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
-rw-r--r-- | gm/drrect_small_inner.cpp | 42 | ||||
-rw-r--r-- | gn/gm.gni | 1 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetContext.cpp | 23 | ||||
-rw-r--r-- | src/gpu/effects/GrCircleEffect.cpp | 3 | ||||
-rw-r--r-- | src/gpu/effects/GrCircleEffect.fp | 14 | ||||
-rw-r--r-- | src/gpu/effects/GrCircleEffect.h | 6 |
6 files changed, 88 insertions, 1 deletions
diff --git a/gm/drrect_small_inner.cpp b/gm/drrect_small_inner.cpp new file mode 100644 index 0000000000..1c7a7436ff --- /dev/null +++ b/gm/drrect_small_inner.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRRect.h" +#include "gm.h" + +DEF_SIMPLE_GM(drrect_small_inner, canvas, 170, 610) { + SkPaint paint; + paint.setAntiAlias(true); + static constexpr SkScalar kOuterRadius = 35.f; + auto outer = SkRRect::MakeOval(SkRect::MakeXYWH(0, 0, 2 * kOuterRadius, 2 * kOuterRadius)); + canvas->translate(10.f, 10.f); + canvas->save(); + for (bool offcenter : {false, true}) { + for (bool oval : {false, true}) { + for (SkScalar innerRadiusX : {1.f, 0.5f, 0.1f, .01f}) { + SkScalar innerRadiusY = innerRadiusX; + if (oval) { + innerRadiusY *= 0.95f; + } + SkScalar tx = kOuterRadius - innerRadiusX; + SkScalar ty = kOuterRadius - innerRadiusY; + if (offcenter) { + tx += 1.f; + } + auto inner = SkRRect::MakeOval( + SkRect::MakeXYWH(tx, ty, 2 * innerRadiusX, 2 * innerRadiusY)); + canvas->drawDRRect(outer, inner, paint); + canvas->translate(0, 2 * kOuterRadius + 5); + } + } + canvas->restore(); + canvas->translate(2 * kOuterRadius + 2, 0); + } + canvas->restore(); +} @@ -118,6 +118,7 @@ gm_sources = [ "$_gm/drawregionmodes.cpp", "$_gm/dropshadowimagefilter.cpp", "$_gm/drrect.cpp", + "$_gm/drrect_small_inner.cpp", "$_gm/dstreadshuffle.cpp", "$_gm/emboss.cpp", "$_gm/emptypath.cpp", diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index 2310ebda94..aba2e1db29 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -1224,6 +1224,28 @@ bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip, } } + SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter); + + if (aa == GrAA::kYes && inner->isCircle() && outer->isCircle()) { + auto outerR = outer->width() / 2.f; + auto innerR = inner->width() / 2.f; + auto cx = outer->getBounds().fLeft + outerR; + auto cy = outer->getBounds().fTop + outerR; + if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) && + SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) { + auto avgR = (innerR + outerR) / 2.f; + auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR); + SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); + stroke.setStrokeStyle(outerR - innerR); + auto op = GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, circleBounds, + stroke, this->caps()->shaderCaps()); + if (op) { + this->addDrawOp(clip, std::move(op)); + return true; + } + } + } + GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); GrClipEdgeType innerEdgeType, outerEdgeType; @@ -1235,7 +1257,6 @@ bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip, outerEdgeType = GrClipEdgeType::kFillBW; } - SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter); SkMatrix inverseVM; if (!viewMatrix.isIdentity()) { if (!origInner.transform(viewMatrix, inner.writable())) { diff --git a/src/gpu/effects/GrCircleEffect.cpp b/src/gpu/effects/GrCircleEffect.cpp index 3bd2138e94..2198cc304f 100644 --- a/src/gpu/effects/GrCircleEffect.cpp +++ b/src/gpu/effects/GrCircleEffect.cpp @@ -66,6 +66,9 @@ private: SkScalar effectiveRadius = radius; if (GrProcessorEdgeTypeIsInverseFill((GrClipEdgeType)edgeType)) { effectiveRadius -= 0.5f; + // When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the + // shader. + effectiveRadius = SkTMax(0.001f, effectiveRadius); } else { effectiveRadius += 0.5f; } diff --git a/src/gpu/effects/GrCircleEffect.fp b/src/gpu/effects/GrCircleEffect.fp index fe959f8bc8..c5a1b77204 100644 --- a/src/gpu/effects/GrCircleEffect.fp +++ b/src/gpu/effects/GrCircleEffect.fp @@ -15,6 +15,18 @@ half prevRadius = -1; // fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills. uniform half4 circle; +@make { + static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkPoint center, + float radius) { + // A radius below half causes the implicit insetting done by this processor to become + // inverted. We could handle this case by making the processor code more complicated. + if (radius < .5f) { + return nullptr; + } + return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(edgeType, center, radius)); + } +} + @optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag } @setData(pdman) { @@ -22,6 +34,8 @@ uniform half4 circle; SkScalar effectiveRadius = radius; if (GrProcessorEdgeTypeIsInverseFill((GrClipEdgeType) edgeType)) { effectiveRadius -= 0.5f; + // When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader. + effectiveRadius = SkTMax(0.001f, effectiveRadius); } else { effectiveRadius += 0.5f; } diff --git a/src/gpu/effects/GrCircleEffect.h b/src/gpu/effects/GrCircleEffect.h index bf6bd0e8e6..d721a78241 100644 --- a/src/gpu/effects/GrCircleEffect.h +++ b/src/gpu/effects/GrCircleEffect.h @@ -19,8 +19,14 @@ public: GrClipEdgeType edgeType() const { return fEdgeType; } SkPoint center() const { return fCenter; } float radius() const { return fRadius; } + static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkPoint center, float radius) { + // A radius below half causes the implicit insetting done by this processor to become + // inverted. We could handle this case by making the processor code more complicated. + if (radius < .5f) { + return nullptr; + } return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(edgeType, center, radius)); } GrCircleEffect(const GrCircleEffect& src); |