Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(266)

Unified Diff: src/gpu/GrOvalRenderer.cpp

Issue 761593006: Do circle anti-aliasing in normalized space to avoid precision issues with half-floats on Adreno. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Add ignored tests Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gm/circles.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/GrOvalRenderer.cpp
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index eac6fb4a3af5b2b3a3cb1ffba7659548ed4d7be4..b9a806c9e19bfe63ee7ea2a290efff2ac6061ce8 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -53,8 +53,14 @@ inline bool circle_stays_circle(const SkMatrix& m) {
///////////////////////////////////////////////////////////////////////////////
/**
- * The output of this effect is a modulation of the input color and coverage for a circle,
- * specified as offset_x, offset_y (both from center point), outer radius and inner radius.
+ * The output of this effect is a modulation of the input color and coverage for a circle. It
+ * operates in a space normalized by the circle radius (outer radius in the case of a stroke)
+ * with origin at the circle center. Two vertex attributes are used:
+ * vec2f : position in device space of the bounding geometry vertices
+ * vec4f : (p.xy, outerRad, innerRad)
+ * p is the position in the normalized space.
+ * outerRad is the outerRadius in device space.
+ * innerRad is the innerRadius in normalized space (ignored if not stroking).
*/
class CircleEdgeEffect : public GrGeometryProcessor {
@@ -94,10 +100,10 @@ public:
GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
fsBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn());
- fsBuilder->codeAppendf("float edgeAlpha = clamp(%s.z - d, 0.0, 1.0);", v.fsIn());
+ fsBuilder->codeAppendf("float edgeAlpha = clamp(%s.z * (1.0 - d), 0.0, 1.0);", v.fsIn());
if (ce.isStroked()) {
- fsBuilder->codeAppendf("float innerAlpha = clamp(d - %s.w, 0.0, 1.0);",
- v.fsIn());
+ fsBuilder->codeAppendf("float innerAlpha = clamp(%s.z * (d - %s.w), 0.0, 1.0);",
+ v.fsIn(), v.fsIn());
fsBuilder->codeAppend("edgeAlpha *= innerAlpha;");
}
@@ -574,10 +580,10 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target,
CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
- // The radii are outset for two reasons. First, it allows the shader to simply perform
- // clamp(distance-to-center - radius, 0, 1). 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
- // pixels partially covered by the circle.
+ // 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;
@@ -588,23 +594,25 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target,
center.fY + outerRadius
);
+ // The inner radius in the vertex data must be specified in normalized space.
+ innerRadius = innerRadius / outerRadius;
verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
- verts[0].fOffset = SkPoint::Make(-outerRadius, -outerRadius);
+ verts[0].fOffset = SkPoint::Make(-1, -1);
verts[0].fOuterRadius = outerRadius;
verts[0].fInnerRadius = innerRadius;
verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
- verts[1].fOffset = SkPoint::Make(-outerRadius, outerRadius);
+ verts[1].fOffset = SkPoint::Make(-1, 1);
verts[1].fOuterRadius = outerRadius;
verts[1].fInnerRadius = innerRadius;
verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
- verts[2].fOffset = SkPoint::Make(outerRadius, outerRadius);
+ verts[2].fOffset = SkPoint::Make(1, 1);
verts[2].fOuterRadius = outerRadius;
verts[2].fInnerRadius = innerRadius;
verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
- verts[3].fOffset = SkPoint::Make(outerRadius, -outerRadius);
+ verts[3].fOffset = SkPoint::Make(1, -1);
verts[3].fOuterRadius = outerRadius;
verts[3].fInnerRadius = innerRadius;
@@ -1089,9 +1097,10 @@ bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
// The radii are outset for two reasons. First, it allows the shader to simply perform
- // clamp(distance-to-center - radius, 0, 1). 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
- // pixels partially covered by the circle.
+ // 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;
@@ -1104,15 +1113,12 @@ bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
bounds.fBottom - outerRadius,
bounds.fBottom
};
- SkScalar yOuterRadii[4] = {
- -outerRadius,
- 0,
- 0,
- outerRadius
- };
+ SkScalar yOuterRadii[4] = {-1, 0, 0, 1 };
+ // The inner radius in the vertex data must be specified in normalized space.
+ innerRadius = innerRadius / outerRadius;
for (int i = 0; i < 4; ++i) {
verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
- verts->fOffset = SkPoint::Make(-outerRadius, yOuterRadii[i]);
+ verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
verts->fOuterRadius = outerRadius;
verts->fInnerRadius = innerRadius;
verts++;
@@ -1130,7 +1136,7 @@ bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
verts++;
verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
- verts->fOffset = SkPoint::Make(outerRadius, yOuterRadii[i]);
+ verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
verts->fOuterRadius = outerRadius;
verts->fInnerRadius = innerRadius;
verts++;
« no previous file with comments | « gm/circles.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698