diff options
author | Brian Salomon <bsalomon@google.com> | 2017-12-20 13:28:55 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-12-20 18:47:36 +0000 |
commit | 2fad74a0fdc5eb3f505a052849c3cbeffa6e2d17 (patch) | |
tree | 6a3ec7975dc7ff37a6e8ccfe817fc3ccbd723b18 | |
parent | 939e6719abb657096b5837d67d594256aa69da45 (diff) |
Make GrRenderTargetContext::drawPath() use GrShape to identify simpler
geometries.
Change-Id: I24230efc8bcb60f00c0c855090e3311ad13d7da8
Reviewed-on: https://skia-review.googlesource.com/85962
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
-rw-r--r-- | src/gpu/GrRenderTargetContext.cpp | 125 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetContext.h | 5 | ||||
-rw-r--r-- | src/gpu/GrShape.cpp | 19 | ||||
-rw-r--r-- | src/gpu/GrShape.h | 3 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 15 | ||||
-rw-r--r-- | tests/GrShapeTest.cpp | 32 |
6 files changed, 109 insertions, 90 deletions
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index 1c617c9410..4f566ba15b 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -584,11 +584,7 @@ void GrRenderTargetContext::drawRect(const GrClip& clip, return; } } - - SkPath path; - path.setIsVolatile(true); - path.addRect(rect); - this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, *style); + this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style)); } int GrRenderTargetContextPriv::maxWindowRectangles() const { @@ -747,10 +743,8 @@ void GrRenderTargetContext::fillRectToRect(const GrClip& clip, } viewAndUnLocalMatrix.postConcat(viewMatrix); - SkPath path; - path.setIsVolatile(true); - path.addRect(localRect); - this->internalDrawPath(clip, std::move(paint), aa, viewAndUnLocalMatrix, path, GrStyle()); + this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewAndUnLocalMatrix, + GrShape(localRect)); } static bool must_filter(const SkRect& src, const SkRect& dst, const SkMatrix& ctm) { @@ -840,7 +834,8 @@ void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip, path.setIsVolatile(true); path.addRect(rectToDraw); path.transform(localMatrix); - this->internalDrawPath(clip, std::move(paint), aa, viewAndUnLocalMatrix, path, GrStyle()); + this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewAndUnLocalMatrix, + GrShape(path)); } void GrRenderTargetContext::drawVertices(const GrClip& clip, @@ -934,10 +929,8 @@ void GrRenderTargetContext::drawRRect(const GrClip& origClip, } } - SkPath path; - path.setIsVolatile(true); - path.addRRect(rrect); - this->internalDrawPath(*clip, std::move(paint), aa, viewMatrix, path, style); + this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix, + GrShape(rrect, style)); } /////////////////////////////////////////////////////////////////////////////// @@ -1276,8 +1269,7 @@ void GrRenderTargetContext::drawDRRect(const GrClip& clip, path.addRRect(inner); path.addRRect(outer); path.setFillType(SkPath::kEvenOdd_FillType); - - this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, GrStyle::SimpleFill()); + this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path)); } /////////////////////////////////////////////////////////////////////////////// @@ -1347,10 +1339,8 @@ void GrRenderTargetContext::drawOval(const GrClip& clip, } } - SkPath path; - path.setIsVolatile(true); - path.addOval(oval); - this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style); + this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, + GrShape(SkRRect::MakeOval(oval), style)); } void GrRenderTargetContext::drawArc(const GrClip& clip, @@ -1388,7 +1378,7 @@ void GrRenderTargetContext::drawArc(const GrClip& clip, SkPath path; SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter, style.isSimpleFill()); - this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style); + this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path, style)); } void GrRenderTargetContext::drawImageLattice(const GrClip& clip, @@ -1501,25 +1491,29 @@ void GrRenderTargetContext::drawPath(const GrClip& clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, - const SkPath& path, + const SkPath& originalPath, const GrStyle& style) { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawPath", fContext); - - if (path.isEmpty()) { - if (path.isInverseFillType()) { - this->drawPaint(clip, std::move(paint), viewMatrix); - } - return; + GrShape shape(originalPath, style); + if (shape.isEmpty()) { + if (shape.inverseFilled()) { + this->drawPaint(clip, std::move(paint), viewMatrix); + } + return; } AutoCheckFlush acf(this->drawingManager()); GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); - if (GrAAType::kCoverage == aaType && !style.pathEffect()) { - if (style.isSimpleFill() && !path.isConvex()) { + if (GrAAType::kCoverage == aaType) { + // TODO: Make GrShape check for nested rects. + SkPath path; + shape.asPath(&path); + SkRect rects[2]; + if (shape.style().isSimpleFill() && fills_as_nested_rects(viewMatrix, path, rects)) { // Concave AA paths are expensive - try to avoid them for special cases SkRect rects[2]; @@ -1533,26 +1527,26 @@ void GrRenderTargetContext::drawPath(const GrClip& clip, return; } } - SkRect ovalRect; - bool isOval = path.isOval(&ovalRect); - - if (isOval && !path.isInverseFillType()) { - const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); - std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeOvalOp( - std::move(paint), viewMatrix, ovalRect, style.strokeRec(), shaderCaps); - if (op) { - this->addDrawOp(clip, std::move(op)); + } + if (!shape.style().hasPathEffect()) { + SkRRect rrect; + // We can ignore the starting point and direction since there is no path effect. + bool inverted; + if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) { + if (rrect.isRect()) { + this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(), + &shape.style()); + return; + } else if (rrect.isOval()) { + this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style()); return; } + this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style()); + return; } } - // Note that internalDrawPath may sw-rasterize the path into a scratch texture. - // Scratch textures can be recycled after they are returned to the texture - // cache. This presents a potential hazard for buffered drawing. However, - // the writePixels that uploads to the scratch will perform a flush so we're - // OK. - this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style); + this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape); } bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip, @@ -1633,12 +1627,11 @@ SkBudgeted GrRenderTargetContextPriv::isBudgeted() const { return fRenderTargetContext->fRenderTargetProxy->isBudgeted(); } -void GrRenderTargetContext::internalDrawPath(const GrClip& clip, - GrPaint&& paint, - GrAA aa, - const SkMatrix& viewMatrix, - const SkPath& path, - const GrStyle& style) { +void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip, + GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const GrShape& originalShape) { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext); @@ -1646,25 +1639,24 @@ void GrRenderTargetContext::internalDrawPath(const GrClip& clip, SkIRect clipConservativeBounds; clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr); - SkASSERT(!path.isEmpty()); - GrShape shape; + GrShape tempShape; // NVPR cannot handle hairlines, so this would get picked up by a different stencil and // cover path renderer (i.e. default path renderer). The hairline renderer produces much // smoother hairlines than MSAA. - GrAllowMixedSamples allowMixedSamples = - style.isSimpleHairline() ? GrAllowMixedSamples::kNo : GrAllowMixedSamples::kYes; + GrAllowMixedSamples allowMixedSamples = originalShape.style().isSimpleHairline() + ? GrAllowMixedSamples::kNo + : GrAllowMixedSamples::kYes; GrAAType aaType = this->chooseAAType(aa, allowMixedSamples); GrPathRenderer::CanDrawPathArgs canDrawArgs; canDrawArgs.fCaps = this->drawingManager()->getContext()->caps(); canDrawArgs.fViewMatrix = &viewMatrix; - canDrawArgs.fShape = &shape; + canDrawArgs.fShape = &originalShape; canDrawArgs.fClipConservativeBounds = &clipConservativeBounds; canDrawArgs.fHasUserStencilSettings = false; GrPathRenderer* pr; static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor; - shape = GrShape(path, style); - if (shape.isEmpty() && !shape.inverseFilled()) { + if (originalShape.isEmpty() && !originalShape.inverseFilled()) { return; } @@ -1674,20 +1666,23 @@ void GrRenderTargetContext::internalDrawPath(const GrClip& clip, pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType); SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix); - if (!pr && shape.style().pathEffect()) { + if (!pr && originalShape.style().pathEffect()) { // It didn't work above, so try again with the path effect applied. - shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale); - if (shape.isEmpty()) { + tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale); + if (tempShape.isEmpty()) { return; } + canDrawArgs.fShape = &tempShape; pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType); } if (!pr) { - if (shape.style().applies()) { - shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale); - if (shape.isEmpty()) { + if (canDrawArgs.fShape->style().applies()) { + tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, + styleScale); + if (tempShape.isEmpty()) { return; } + canDrawArgs.fShape = &tempShape; } // This time, allow SW renderer pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType); @@ -1707,7 +1702,7 @@ void GrRenderTargetContext::internalDrawPath(const GrClip& clip, &clip, &clipConservativeBounds, &viewMatrix, - &shape, + canDrawArgs.fShape, aaType, this->colorSpaceInfo().isGammaCorrect()}; pr->drawPath(args); diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h index 304e6bc0bf..902c488461 100644 --- a/src/gpu/GrRenderTargetContext.h +++ b/src/gpu/GrRenderTargetContext.h @@ -30,6 +30,7 @@ class GrFixedClip; class GrRenderTarget; class GrRenderTargetContextPriv; class GrRenderTargetOpList; +class GrShape; class GrStyle; class GrTextureProxy; struct GrUserStencilSettings; @@ -432,8 +433,8 @@ private: const SkRect& rect, const GrUserStencilSettings* ss); - void internalDrawPath( - const GrClip&, GrPaint&&, GrAA, const SkMatrix&, const SkPath&, const GrStyle&); + void drawShapeUsingPathRenderer(const GrClip&, GrPaint&&, GrAA, const SkMatrix&, + const GrShape&); // These perform processing specific to Gr[Mesh]DrawOp-derived ops before recording them into // the op list. They return the id of the opList to which the op was added, or 0, if it was diff --git a/src/gpu/GrShape.cpp b/src/gpu/GrShape.cpp index 8c56054135..4c9338409c 100644 --- a/src/gpu/GrShape.cpp +++ b/src/gpu/GrShape.cpp @@ -539,11 +539,22 @@ void GrShape::attemptToSimplifyPath() { void GrShape::attemptToSimplifyRRect() { SkASSERT(Type::kRRect == fType); SkASSERT(!fInheritedKey.count()); - // TODO: This isn't valid for strokes. if (fRRectData.fRRect.isEmpty()) { - // Dashing ignores the inverseness currently. skbug.com/5421 - fType = fRRectData.fInverted && !fStyle.isDashed() ? Type::kInvertedEmpty : Type::kEmpty; - return; + // An empty filled rrect is equivalent to a filled empty path with inversion preserved. + if (fStyle.isSimpleFill()) { + fType = fRRectData.fInverted ? Type::kInvertedEmpty : Type::kEmpty; + fStyle = GrStyle::SimpleFill(); + return; + } + // Dashing a rrect with no width or height is equivalent to filling an emtpy path. + // When skbug.com/7387 is fixed this should be modified or removed as a dashed zero length + // line will produce cap geometry if the effect begins in an "on" interval. + if (fStyle.isDashed() && !fRRectData.fRRect.width() && !fRRectData.fRRect.height()) { + // Dashing ignores the inverseness (currently). skbug.com/5421. + fType = Type::kEmpty; + fStyle = GrStyle::SimpleFill(); + return; + } } if (!this->style().hasPathEffect()) { fRRectData.fDir = kDefaultRRectDir; diff --git a/src/gpu/GrShape.h b/src/gpu/GrShape.h index 032c4d5e57..924232e8cf 100644 --- a/src/gpu/GrShape.h +++ b/src/gpu/GrShape.h @@ -338,7 +338,8 @@ public: case Type::kRRect: if (fRRectData.fRRect.getType() == SkRRect::kOval_Type) { return SkPath::kConic_SegmentMask; - } else if (fRRectData.fRRect.getType() == SkRRect::kRect_Type) { + } else if (fRRectData.fRRect.getType() == SkRRect::kRect_Type || + fRRectData.fRRect.getType() == SkRRect::kEmpty_Type) { return SkPath::kLine_SegmentMask; } return SkPath::kLine_SegmentMask | SkPath::kConic_SegmentMask; diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 1eebb5d095..f8924802e6 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -622,21 +622,6 @@ void SkGpuDevice::drawPath(const SkPath& origSrcPath, return; } } - bool isClosed; - SkRect rect; - if (origSrcPath.isRect(&rect, &isClosed) && isClosed) { - this->drawRect(rect, paint); - return; - } - if (origSrcPath.isOval(&rect)) { - this->drawOval(rect, paint); - return; - } - SkRRect rrect; - if (origSrcPath.isRRect(&rrect)) { - this->drawRRect(rrect, paint); - return; - } } GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext.get()); diff --git a/tests/GrShapeTest.cpp b/tests/GrShapeTest.cpp index 259026c8d0..826d0f864b 100644 --- a/tests/GrShapeTest.cpp +++ b/tests/GrShapeTest.cpp @@ -1490,6 +1490,8 @@ DEF_TEST(GrShape_empty_shape, reporter) { SkPaint stroke; stroke.setStrokeWidth(2.f); stroke.setStyle(SkPaint::kStroke_Style); + stroke.setStrokeJoin(SkPaint::kRound_Join); + stroke.setStrokeCap(SkPaint::kRound_Cap); TestCase strokeEmptyCase(reporter, emptyPath, stroke); strokeEmptyCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation); TestCase strokeInvertedEmptyCase(reporter, invertedEmptyPath, stroke); @@ -1509,25 +1511,49 @@ DEF_TEST(GrShape_empty_shape, reporter) { dashAndStrokeInvertexEmptyCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation); - // A shape made from an empty rrect should behave the same as an empty path. - SkRRect emptyRRect = SkRRect::MakeRect(SkRect::MakeEmpty()); + // A shape made from an empty rrect should behave the same as an empty path when filled but not + // when stroked. However, dashing an empty rrect produces an empty path leaving nothing to + // stroke - so equivalent to filling an empty path. + SkRRect emptyRRect = SkRRect::MakeEmpty(); REPORTER_ASSERT(reporter, emptyRRect.getType() == SkRRect::kEmpty_Type); + + TestCase fillEmptyRRectCase(reporter, emptyRRect, fill); + fillEmptyRRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation); + + TestCase strokeEmptyRRectCase(reporter, emptyRRect, stroke); + strokeEmptyRRectCase.compare(reporter, strokeEmptyCase, + TestCase::kAllDifferent_ComparisonExpecation); + TestCase dashAndStrokeEmptyRRectCase(reporter, emptyRRect, dashAndStroke); dashAndStrokeEmptyRRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation); + static constexpr SkPath::Direction kDir = SkPath::kCCW_Direction; static constexpr int kStart = 0; + + TestCase fillInvertedEmptyRRectCase(reporter, emptyRRect, kDir, kStart, true, GrStyle(fill)); + fillInvertedEmptyRRectCase.compare(reporter, fillInvertedEmptyCase, + TestCase::kAllSame_ComparisonExpecation); + + TestCase strokeInvertedEmptyRRectCase(reporter, emptyRRect, kDir, kStart, true, + GrStyle(stroke)); + strokeInvertedEmptyRRectCase.compare(reporter, strokeInvertedEmptyCase, + TestCase::kAllDifferent_ComparisonExpecation); + TestCase dashAndStrokeEmptyInvertedRRectCase(reporter, emptyRRect, kDir, kStart, true, GrStyle(dashAndStroke)); - // Dashing ignores inverseness so this is equivalent to the non-inverted empty fill. dashAndStrokeEmptyInvertedRRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation); // Same for a rect. SkRect emptyRect = SkRect::MakeEmpty(); + TestCase fillEmptyRectCase(reporter, emptyRect, fill); + fillEmptyRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation); + TestCase dashAndStrokeEmptyRectCase(reporter, emptyRect, dashAndStroke); dashAndStrokeEmptyRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation); + TestCase dashAndStrokeEmptyInvertedRectCase(reporter, SkRRect::MakeRect(emptyRect), kDir, kStart, true, GrStyle(dashAndStroke)); // Dashing ignores inverseness so this is equivalent to the non-inverted empty fill. |