diff options
author | Brian Salomon <bsalomon@google.com> | 2018-05-09 13:28:44 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-05-09 18:05:40 +0000 |
commit | 969a738e7f7fe03832acb86362d133db40623c01 (patch) | |
tree | 98edcbefdfd2a9d77e6b00c0366b417cd94bfb31 /src/gpu/ops/GrAAHairLinePathRenderer.cpp | |
parent | 788a2dc754f9da403d297e4a09efe187aeda3229 (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.cpp | 204 |
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; |