diff options
author | 2013-05-17 12:50:27 +0000 | |
---|---|---|
committer | 2013-05-17 12:50:27 +0000 | |
commit | 83d1a68141830cbfa0d5fca6f9c9bccf9c978ad2 (patch) | |
tree | c20879508ce5a1c52790dbbc61b8dfbfc96e5e8e /src | |
parent | 8be02fc2a72ae69a9142de68a483edf378aff1c8 (diff) |
Add special handling of rectori case for gpu
https://codereview.chromium.org/15080010/
git-svn-id: http://skia.googlecode.com/svn/trunk@9175 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkPath.cpp | 15 | ||||
-rw-r--r-- | src/effects/SkDashPathEffect.cpp | 7 | ||||
-rw-r--r-- | src/gpu/GrAARectRenderer.cpp | 69 | ||||
-rw-r--r-- | src/gpu/GrContext.cpp | 77 |
4 files changed, 141 insertions, 27 deletions
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index 3dd619f586..95cd9fe938 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -600,17 +600,18 @@ bool SkPath::isRect(bool* isClosed, Direction* direction) const { return isRectContour(false, &currVerb, &pts, isClosed, direction); } -bool SkPath::isNestedRects(SkRect rects[2]) const { +bool SkPath::isNestedRects(SkRect rects[2], Direction dirs[2]) const { SkDEBUGCODE(this->validate();) int currVerb = 0; const SkPoint* pts = fPathRef->points(); const SkPoint* first = pts; - if (!isRectContour(true, &currVerb, &pts, NULL, NULL)) { + Direction testDirs[2]; + if (!isRectContour(true, &currVerb, &pts, NULL, &testDirs[0])) { return false; } const SkPoint* last = pts; SkRect testRects[2]; - if (isRectContour(false, &currVerb, &pts, NULL, NULL)) { + if (isRectContour(false, &currVerb, &pts, NULL, &testDirs[1])) { testRects[0].set(first, SkToS32(last - first)); testRects[1].set(last, SkToS32(pts - last)); if (testRects[0].contains(testRects[1])) { @@ -618,6 +619,10 @@ bool SkPath::isNestedRects(SkRect rects[2]) const { rects[0] = testRects[0]; rects[1] = testRects[1]; } + if (dirs) { + dirs[0] = testDirs[0]; + dirs[1] = testDirs[1]; + } return true; } if (testRects[1].contains(testRects[0])) { @@ -625,6 +630,10 @@ bool SkPath::isNestedRects(SkRect rects[2]) const { rects[0] = testRects[1]; rects[1] = testRects[0]; } + if (dirs) { + dirs[0] = testDirs[1]; + dirs[1] = testDirs[0]; + } return true; } } diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp index a3a011c08c..be065919ce 100644 --- a/src/effects/SkDashPathEffect.cpp +++ b/src/effects/SkDashPathEffect.cpp @@ -237,6 +237,7 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, const SkScalar* intervals = fIntervals; SkScalar dashCount = 0; + int segCount = 0; SkPath cullPathStorage; const SkPath* srcPtr = &src; @@ -291,6 +292,7 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, addedSegment = false; if (is_even(index) && dlen > 0 && !skipFirstSegment) { addedSegment = true; + ++segCount; if (specialLine) { lineRec.addSegment(SkDoubleToScalar(distance), @@ -322,9 +324,14 @@ bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, if (meas.isClosed() && is_even(fInitialDashIndex) && fInitialDashLength > 0) { meas.getSegment(0, SkScalarMul(fInitialDashLength, scale), dst, !addedSegment); + ++segCount; } } while (meas.nextContour()); + if (segCount > 1) { + dst->setConvexity(SkPath::kConcave_Convexity); + } + return true; } diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp index c1870dd46b..bef5ddb620 100644 --- a/src/gpu/GrAARectRenderer.cpp +++ b/src/gpu/GrAARectRenderer.cpp @@ -635,9 +635,16 @@ void GrAARectRenderer::strokeAARect(GrGpu* gpu, const GrRect& rect, const SkMatrix& combinedMatrix, const GrRect& devRect, - const GrVec& devStrokeSize, + SkScalar width, bool useVertexCoverage) { - GrDrawState* drawState = target->drawState(); + GrVec devStrokeSize; + if (width > 0) { + devStrokeSize.set(width, width); + combinedMatrix.mapVectors(&devStrokeSize, 1); + devStrokeSize.setAbs(devStrokeSize); + } else { + devStrokeSize.set(SK_Scalar1, SK_Scalar1); + } const SkScalar dx = devStrokeSize.fX; const SkScalar dy = devStrokeSize.fY; @@ -659,13 +666,28 @@ void GrAARectRenderer::strokeAARect(GrGpu* gpu, spare = GrMin(w, h); } + GrRect devOutside(devRect); + devOutside.outset(rx, ry); + if (spare <= 0) { - GrRect r(devRect); - r.outset(rx, ry); - this->fillAARect(gpu, target, r, SkMatrix::I(), r, useVertexCoverage); + this->fillAARect(gpu, target, devOutside, SkMatrix::I(), + devOutside, useVertexCoverage); return; } + SkRect devInside(devRect); + devInside.inset(rx, ry); + + this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage); +} + +void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu, + GrDrawTarget* target, + const SkRect& devOutside, + const SkRect& devInside, + bool useVertexCoverage) { + GrDrawState* drawState = target->drawState(); + set_aa_rect_vertex_attributes(drawState, useVertexCoverage); GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0); @@ -691,14 +713,12 @@ void GrAARectRenderer::strokeAARect(GrGpu* gpu, GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize); GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize); - set_inset_fan(fan0Pos, vsize, devRect, - -rx - SK_ScalarHalf, -ry - SK_ScalarHalf); - set_inset_fan(fan1Pos, vsize, devRect, - -rx + SK_ScalarHalf, -ry + SK_ScalarHalf); - set_inset_fan(fan2Pos, vsize, devRect, - rx - SK_ScalarHalf, ry - SK_ScalarHalf); - set_inset_fan(fan3Pos, vsize, devRect, - rx + SK_ScalarHalf, ry + SK_ScalarHalf); + // outermost + set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); + set_inset_fan(fan1Pos, vsize, devOutside, SK_ScalarHalf, SK_ScalarHalf); + set_inset_fan(fan2Pos, vsize, devInside, -SK_ScalarHalf, -SK_ScalarHalf); + // innermost + set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf); // The outermost rect has 0 coverage verts += sizeof(GrPoint); @@ -718,7 +738,7 @@ void GrAARectRenderer::strokeAARect(GrGpu* gpu, *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; } - // The innermost rect has full coverage + // The innermost rect has 0 coverage verts += 8 * vsize; for (int i = 0; i < 4; ++i) { *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; @@ -728,3 +748,24 @@ void GrAARectRenderer::strokeAARect(GrGpu* gpu, target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, aaStrokeRectIndexCount()); } + +void GrAARectRenderer::fillAANestedRects(GrGpu* gpu, + GrDrawTarget* target, + const SkRect rects[2], + const SkMatrix& combinedMatrix, + bool useVertexCoverage) { + SkASSERT(combinedMatrix.rectStaysRect()); + SkASSERT(!rects[1].isEmpty()); + + SkRect devOutside, devInside; + combinedMatrix.mapRect(&devOutside, rects[0]); + // can't call mapRect for devInside since it calls sort + combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2); + + if (devInside.isEmpty()) { + this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage); + return; + } + + this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage); +} diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 64893b461a..d25709f0ea 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -792,17 +792,9 @@ void GrContext::drawRect(const GrPaint& paint, return; } if (width >= 0) { - GrVec strokeSize; - if (width > 0) { - strokeSize.set(width, width); - combinedMatrix.mapVectors(&strokeSize, 1); - strokeSize.setAbs(strokeSize); - } else { - strokeSize.set(SK_Scalar1, SK_Scalar1); - } fAARectRenderer->strokeAARect(this->getGpu(), target, rect, combinedMatrix, devRect, - strokeSize, useVertexCoverage); + width, useVertexCoverage); } else { // filled AA rect fAARectRenderer->fillAARect(this->getGpu(), target, @@ -1004,6 +996,52 @@ void GrContext::drawOval(const GrPaint& paint, } } +namespace { + +// Can 'path' be drawn as a pair of filled nested rectangles? +static bool is_nested_rects(GrDrawTarget* target, + const SkPath& path, + const SkStrokeRec& stroke, + SkRect rects[2], + bool* useVertexCoverage) { + SkASSERT(stroke.isFillStyle()); + + if (path.isInverseFillType()) { + return false; + } + + const GrDrawState& drawState = target->getDrawState(); + + // TODO: this restriction could be lifted if we were willing to apply + // the matrix to all the points individually rather than just to the rect + if (!drawState.getViewMatrix().preservesAxisAlignment()) { + return false; + } + + *useVertexCoverage = false; + if (!target->getDrawState().canTweakAlphaForCoverage()) { + if (disable_coverage_aa_for_blend(target)) { + return false; + } else { + *useVertexCoverage = true; + } + } + + SkPath::Direction dirs[2]; + if (!path.isNestedRects(rects, dirs)) { + return false; + } + + if (SkPath::kWinding_FillType == path.getFillType()) { + // The two rects need to be wound opposite to each other + return dirs[0] != dirs[1]; + } else { + return true; + } +} + +}; + void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke) { if (path.isEmpty()) { @@ -1021,9 +1059,28 @@ void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const SkStrok GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); GrDrawState::AutoStageDisable atr(fDrawState); + bool useAA = paint.isAntiAlias() && !this->getRenderTarget()->isMultisampled(); + if (useAA && stroke.getWidth() < 0 && !path.isConvex()) { + // Concave AA paths are expensive - try to avoid them for special cases + bool useVertexCoverage; + SkRect rects[2]; + + if (is_nested_rects(target, path, stroke, rects, &useVertexCoverage)) { + GrDrawState::AutoDeviceCoordDraw adcd(target->drawState()); + if (!adcd.succeeded()) { + return; + } + + fAARectRenderer->fillAANestedRects(this->getGpu(), target, + rects, + adcd.getOriginalMatrix(), + useVertexCoverage); + return; + } + } + SkRect ovalRect; bool isOval = path.isOval(&ovalRect); - bool useAA = paint.isAntiAlias() && !this->getRenderTarget()->isMultisampled(); if (!isOval || path.isInverseFillType() || !fOvalRenderer->drawOval(target, this, useAA, ovalRect, stroke)) { |