aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2017-12-01 13:49:50 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-12-01 20:00:09 +0000
commit096074af2c6fcbf622f0a42b2f7c56d0c66fbd80 (patch)
treec8162aad746f18fee6344567a6cf63ae11dc7dec /src/gpu
parentb826a3ab7247fea323eb8b06372a678fbc6c3dbe (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>
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/GrRenderTargetContext.cpp23
-rw-r--r--src/gpu/effects/GrCircleEffect.cpp3
-rw-r--r--src/gpu/effects/GrCircleEffect.fp14
-rw-r--r--src/gpu/effects/GrCircleEffect.h6
4 files changed, 45 insertions, 1 deletions
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);