aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/ops/GrAAHairLinePathRenderer.cpp
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2018-05-09 13:28:44 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-05-09 18:05:40 +0000
commit969a738e7f7fe03832acb86362d133db40623c01 (patch)
tree98edcbefdfd2a9d77e6b00c0366b417cd94bfb31 /src/gpu/ops/GrAAHairLinePathRenderer.cpp
parent788a2dc754f9da403d297e4a09efe187aeda3229 (diff)
Approximate conics as quads in GrAAHairlinePathRenderer when fp32 not supported
This fixes the precision issues with hairline conics on Mali 4xx. Change-Id: I1924915eba7bf6056df1fb8dd366ecebd8c40dd0 Reviewed-on: https://skia-review.googlesource.com/126622 Commit-Queue: Brian Salomon <bsalomon@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com>
Diffstat (limited to 'src/gpu/ops/GrAAHairLinePathRenderer.cpp')
-rw-r--r--src/gpu/ops/GrAAHairLinePathRenderer.cpp204
1 files changed, 100 insertions, 104 deletions
diff --git a/src/gpu/ops/GrAAHairLinePathRenderer.cpp b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
index a463c89d62..249635169a 100644
--- a/src/gpu/ops/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
@@ -242,6 +242,7 @@ static int gather_lines_and_quads(const SkPath& path,
const SkMatrix& m,
const SkIRect& devClipBounds,
SkScalar capLength,
+ bool convertConicsToQuads,
GrAAHairLinePathRenderer::PtArray* lines,
GrAAHairLinePathRenderer::PtArray* quads,
GrAAHairLinePathRenderer::PtArray* conics,
@@ -262,49 +263,102 @@ static int gather_lines_and_quads(const SkPath& path,
bool seenZeroLengthVerb = false;
SkPoint zeroVerbPt;
+ // Adds a quad that has already been chopped to the list and checks for quads that are close to
+ // lines. Also does a bounding box check. It takes points that are in src space and device
+ // space. The src points are only required if the view matrix has perspective.
+ auto addChoppedQuad = [&](const SkPoint srcPts[3], const SkPoint devPts[4],
+ bool isContourStart) {
+ SkRect bounds;
+ SkIRect ibounds;
+ bounds.setBounds(devPts, 3);
+ bounds.outset(SK_Scalar1, SK_Scalar1);
+ bounds.roundOut(&ibounds);
+ // We only need the src space space pts when not in perspective.
+ SkASSERT(srcPts || !persp);
+ if (SkIRect::Intersects(devClipBounds, ibounds)) {
+ int subdiv = num_quad_subdivs(devPts);
+ SkASSERT(subdiv >= -1);
+ if (-1 == subdiv) {
+ SkPoint* pts = lines->push_back_n(4);
+ pts[0] = devPts[0];
+ pts[1] = devPts[1];
+ pts[2] = devPts[1];
+ pts[3] = devPts[2];
+ if (isContourStart && pts[0] == pts[1] && pts[2] == pts[3]) {
+ seenZeroLengthVerb = true;
+ zeroVerbPt = pts[0];
+ }
+ } else {
+ // when in perspective keep quads in src space
+ const SkPoint* qPts = persp ? srcPts : devPts;
+ SkPoint* pts = quads->push_back_n(3);
+ pts[0] = qPts[0];
+ pts[1] = qPts[1];
+ pts[2] = qPts[2];
+ quadSubdivCnts->push_back() = subdiv;
+ totalQuadCount += 1 << subdiv;
+ }
+ }
+ };
+
+ // Applies the view matrix to quad src points and calls the above helper.
+ auto addSrcChoppedQuad = [&](const SkPoint srcSpaceQuadPts[3], bool isContourStart) {
+ SkPoint devPts[3];
+ m.mapPoints(devPts, srcSpaceQuadPts, 3);
+ addChoppedQuad(srcSpaceQuadPts, devPts, isContourStart);
+ };
+
for (;;) {
SkPoint pathPts[4];
- SkPoint devPts[4];
SkPath::Verb verb = iter.next(pathPts, false);
switch (verb) {
- case SkPath::kConic_Verb: {
- SkConic dst[4];
- // We chop the conics to create tighter clipping to hide error
- // that appears near max curvature of very thin conics. Thin
- // hyperbolas with high weight still show error.
- int conicCnt = chop_conic(pathPts, dst, iter.conicWeight());
- for (int i = 0; i < conicCnt; ++i) {
- SkPoint* chopPnts = dst[i].fPts;
- m.mapPoints(devPts, chopPnts, 3);
- bounds.setBounds(devPts, 3);
- bounds.outset(SK_Scalar1, SK_Scalar1);
- bounds.roundOut(&ibounds);
- if (SkIRect::Intersects(devClipBounds, ibounds)) {
- if (is_degen_quad_or_conic(devPts)) {
- SkPoint* pts = lines->push_back_n(4);
- pts[0] = devPts[0];
- pts[1] = devPts[1];
- pts[2] = devPts[1];
- pts[3] = devPts[2];
- if (verbsInContour == 0 && i == 0 &&
- pts[0] == pts[1] && pts[2] == pts[3]) {
- seenZeroLengthVerb = true;
- zeroVerbPt = pts[0];
+ case SkPath::kConic_Verb:
+ if (convertConicsToQuads) {
+ SkScalar weight = iter.conicWeight();
+ SkAutoConicToQuads converter;
+ const SkPoint* quadPts = converter.computeQuads(pathPts, weight, 0.5f);
+ for (int i = 0; i < converter.countQuads(); ++i) {
+ addSrcChoppedQuad(quadPts + 2 * i, !verbsInContour && 0 == i);
+ }
+ } else {
+ SkConic dst[4];
+ // We chop the conics to create tighter clipping to hide error
+ // that appears near max curvature of very thin conics. Thin
+ // hyperbolas with high weight still show error.
+ int conicCnt = chop_conic(pathPts, dst, iter.conicWeight());
+ for (int i = 0; i < conicCnt; ++i) {
+ SkPoint devPts[4];
+ SkPoint* chopPnts = dst[i].fPts;
+ m.mapPoints(devPts, chopPnts, 3);
+ bounds.setBounds(devPts, 3);
+ bounds.outset(SK_Scalar1, SK_Scalar1);
+ bounds.roundOut(&ibounds);
+ if (SkIRect::Intersects(devClipBounds, ibounds)) {
+ if (is_degen_quad_or_conic(devPts)) {
+ SkPoint* pts = lines->push_back_n(4);
+ pts[0] = devPts[0];
+ pts[1] = devPts[1];
+ pts[2] = devPts[1];
+ pts[3] = devPts[2];
+ if (verbsInContour == 0 && i == 0 && pts[0] == pts[1] &&
+ pts[2] == pts[3]) {
+ seenZeroLengthVerb = true;
+ zeroVerbPt = pts[0];
+ }
+ } else {
+ // when in perspective keep conics in src space
+ SkPoint* cPts = persp ? chopPnts : devPts;
+ SkPoint* pts = conics->push_back_n(3);
+ pts[0] = cPts[0];
+ pts[1] = cPts[1];
+ pts[2] = cPts[2];
+ conicWeights->push_back() = dst[i].fW;
}
- } else {
- // when in perspective keep conics in src space
- SkPoint* cPts = persp ? chopPnts : devPts;
- SkPoint* pts = conics->push_back_n(3);
- pts[0] = cPts[0];
- pts[1] = cPts[1];
- pts[2] = cPts[2];
- conicWeights->push_back() = dst[i].fW;
}
}
}
verbsInContour++;
break;
- }
case SkPath::kMove_Verb:
// New contour (and last one was unclosed). If it was just a zero length drawing
// operation, and we're supposed to draw caps, then add a tiny line.
@@ -316,7 +370,8 @@ static int gather_lines_and_quads(const SkPath& path,
verbsInContour = 0;
seenZeroLengthVerb = false;
break;
- case SkPath::kLine_Verb:
+ case SkPath::kLine_Verb: {
+ SkPoint devPts[2];
m.mapPoints(devPts, pathPts, 2);
bounds.setBounds(devPts, 2);
bounds.outset(SK_Scalar1, SK_Scalar1);
@@ -332,6 +387,7 @@ static int gather_lines_and_quads(const SkPath& path,
}
verbsInContour++;
break;
+ }
case SkPath::kQuad_Verb: {
SkPoint choppedPts[5];
// Chopping the quad helps when the quad is either degenerate or nearly degenerate.
@@ -341,42 +397,13 @@ static int gather_lines_and_quads(const SkPath& path,
// can cause rendering artifacts.
int n = SkChopQuadAtMaxCurvature(pathPts, choppedPts);
for (int i = 0; i < n; ++i) {
- SkPoint* quadPts = choppedPts + i * 2;
- m.mapPoints(devPts, quadPts, 3);
- bounds.setBounds(devPts, 3);
- bounds.outset(SK_Scalar1, SK_Scalar1);
- bounds.roundOut(&ibounds);
-
- if (SkIRect::Intersects(devClipBounds, ibounds)) {
- int subdiv = num_quad_subdivs(devPts);
- SkASSERT(subdiv >= -1);
- if (-1 == subdiv) {
- SkPoint* pts = lines->push_back_n(4);
- pts[0] = devPts[0];
- pts[1] = devPts[1];
- pts[2] = devPts[1];
- pts[3] = devPts[2];
- if (verbsInContour == 0 && i == 0 &&
- pts[0] == pts[1] && pts[2] == pts[3]) {
- seenZeroLengthVerb = true;
- zeroVerbPt = pts[0];
- }
- } else {
- // when in perspective keep quads in src space
- SkPoint* qPts = persp ? quadPts : devPts;
- SkPoint* pts = quads->push_back_n(3);
- pts[0] = qPts[0];
- pts[1] = qPts[1];
- pts[2] = qPts[2];
- quadSubdivCnts->push_back() = subdiv;
- totalQuadCount += 1 << subdiv;
- }
- }
+ addSrcChoppedQuad(choppedPts + i * 2, !verbsInContour && 0 == i);
}
verbsInContour++;
break;
}
- case SkPath::kCubic_Verb:
+ case SkPath::kCubic_Verb: {
+ SkPoint devPts[4];
m.mapPoints(devPts, pathPts, 4);
bounds.setBounds(devPts, 4);
bounds.outset(SK_Scalar1, SK_Scalar1);
@@ -393,49 +420,16 @@ static int gather_lines_and_quads(const SkPath& path,
GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, &q);
}
for (int i = 0; i < q.count(); i += 3) {
- SkPoint* qInDevSpace;
- // bounds has to be calculated in device space, but q is
- // in src space when there is perspective.
if (persp) {
- m.mapPoints(devPts, &q[i], 3);
- bounds.setBounds(devPts, 3);
- qInDevSpace = devPts;
+ addSrcChoppedQuad(&q[i], !verbsInContour && 0 == i);
} else {
- bounds.setBounds(&q[i], 3);
- qInDevSpace = &q[i];
- }
- bounds.outset(SK_Scalar1, SK_Scalar1);
- bounds.roundOut(&ibounds);
- if (SkIRect::Intersects(devClipBounds, ibounds)) {
- int subdiv = num_quad_subdivs(qInDevSpace);
- SkASSERT(subdiv >= -1);
- if (-1 == subdiv) {
- SkPoint* pts = lines->push_back_n(4);
- // lines should always be in device coords
- pts[0] = qInDevSpace[0];
- pts[1] = qInDevSpace[1];
- pts[2] = qInDevSpace[1];
- pts[3] = qInDevSpace[2];
- if (verbsInContour == 0 && i == 0 &&
- pts[0] == pts[1] && pts[2] == pts[3]) {
- seenZeroLengthVerb = true;
- zeroVerbPt = pts[0];
- }
- } else {
- SkPoint* pts = quads->push_back_n(3);
- // q is already in src space when there is no
- // perspective and dev coords otherwise.
- pts[0] = q[0 + i];
- pts[1] = q[1 + i];
- pts[2] = q[2 + i];
- quadSubdivCnts->push_back() = subdiv;
- totalQuadCount += 1 << subdiv;
- }
+ addChoppedQuad(nullptr, &q[i], !verbsInContour && 0 == i);
}
}
}
verbsInContour++;
break;
+ }
case SkPath::kClose_Verb:
// Contour is closed, so we don't need to grow the starting line, unless it's
// *just* a zero length subpath. (SVG Spec 11.4, 'stroke').
@@ -446,6 +440,7 @@ static int gather_lines_and_quads(const SkPath& path,
pts[1] = SkPoint::Make(zeroVerbPt.fX + capLength, zeroVerbPt.fY);
} else if (verbsInContour == 0) {
// Contour was (moveTo, close). Add a line.
+ SkPoint devPts[2];
m.mapPoints(devPts, pathPts, 1);
devPts[1] = devPts[0];
bounds.setBounds(devPts, 2);
@@ -924,11 +919,12 @@ void AAHairlineOp::onPrepareDraws(Target* target) {
int quadCount = 0;
int instanceCount = fPaths.count();
+ bool convertConicsToQuads = !target->caps().shaderCaps()->floatIs32Bits();
for (int i = 0; i < instanceCount; i++) {
const PathData& args = fPaths[i];
quadCount += gather_lines_and_quads(args.fPath, args.fViewMatrix, args.fDevClipBounds,
- args.fCapLength, &lines, &quads, &conics, &qSubdivs,
- &cWeights);
+ args.fCapLength, convertConicsToQuads, &lines, &quads,
+ &conics, &qSubdivs, &cWeights);
}
int lineCount = lines.count() / 2;