From b8ed2bce50646882f71c0fd0cc191e936321dce9 Mon Sep 17 00:00:00 2001 From: Chris Dalton Date: Tue, 2 Feb 2021 11:53:19 -0700 Subject: [PATCH] Make simplifyStroke optional on GrStyledShape For now we simplify every stroke at the beginning of drawShape*, but in the future we will give the tessellator a chance to claim stroked shapes before simplifying the stroke. Bug: chromium:1172543 Change-Id: Ie90c20a1d342661b9006b16ab1fdad3ebe290ba3 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/362798 Reviewed-by: Michael Ludwig Commit-Queue: Chris Dalton --- src/gpu/GrSurfaceDrawContext.cpp | 28 ++++++++---- src/gpu/geometry/GrStyledShape.cpp | 71 +++++++++++++++++++----------- src/gpu/geometry/GrStyledShape.h | 71 ++++++++++++++++++++---------- 3 files changed, 113 insertions(+), 57 deletions(-) diff --git a/src/gpu/GrSurfaceDrawContext.cpp b/src/gpu/GrSurfaceDrawContext.cpp index deb4ec70ea..cf1f20aabf 100644 --- a/src/gpu/GrSurfaceDrawContext.cpp +++ b/src/gpu/GrSurfaceDrawContext.cpp @@ -77,6 +77,8 @@ ////////////////////////////////////////////////////////////////////////////// +using SimplifyStroke = GrStyledShape::SimplifyStroke; + class AutoCheckFlush { public: AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) { @@ -721,7 +723,7 @@ void GrSurfaceDrawContext::drawRect(const GrClip* clip, } assert_alive(paint); this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, - GrStyledShape(rect, *style)); + GrStyledShape(rect, *style, SimplifyStroke::kNo)); } void GrSurfaceDrawContext::drawQuadSet(const GrClip* clip, @@ -1015,7 +1017,7 @@ void GrSurfaceDrawContext::drawRRect(const GrClip* origClip, assert_alive(paint); this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, - GrStyledShape(rrect, style)); + GrStyledShape(rrect, style, SimplifyStroke::kNo)); } /////////////////////////////////////////////////////////////////////////////// @@ -1439,9 +1441,9 @@ void GrSurfaceDrawContext::drawOval(const GrClip* clip, } assert_alive(paint); - this->drawShapeUsingPathRenderer( - clip, std::move(paint), aa, viewMatrix, - GrStyledShape(SkRRect::MakeOval(oval), SkPathDirection::kCW, 2, false, style)); + this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, + GrStyledShape(SkRRect::MakeOval(oval), SkPathDirection::kCW, 2, + false, style, SimplifyStroke::kNo)); } void GrSurfaceDrawContext::drawArc(const GrClip* clip, @@ -1478,9 +1480,9 @@ void GrSurfaceDrawContext::drawArc(const GrClip* clip, } assert_alive(paint); } - this->drawShapeUsingPathRenderer( - clip, std::move(paint), aa, viewMatrix, - GrStyledShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style)); + this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, + GrStyledShape::MakeArc(oval, startAngle, sweepAngle, useCenter, + style, SimplifyStroke::kNo)); } void GrSurfaceDrawContext::drawImageLattice(const GrClip* clip, @@ -1558,7 +1560,7 @@ void GrSurfaceDrawContext::drawPath(const GrClip* clip, SkDEBUGCODE(this->validate();) GR_CREATE_TRACE_MARKER_CONTEXT("GrSurfaceDrawContext", "drawPath", fContext); - GrStyledShape shape(path, style); + GrStyledShape shape(path, style, SimplifyStroke::kNo); this->drawShape(clip, std::move(paint), aa, viewMatrix, std::move(shape)); } @@ -1581,6 +1583,10 @@ void GrSurfaceDrawContext::drawShape(const GrClip* clip, AutoCheckFlush acf(this->drawingManager()); + // Always simplify the stroke for now. In the future we will give the tessellator a chance to + // claim strokes before trying to simplify them. + shape.simplifyStroke(); + if (!shape.style().hasPathEffect()) { GrAAType aaType = this->chooseAAType(aa); SkPoint linePts[2]; @@ -1780,6 +1786,10 @@ void GrSurfaceDrawContext::drawShapeUsingPathRenderer(const GrClip* clip, return; } + // Always simplify the stroke for now. In the future we will give the tessellator a chance to + // claim strokes before trying to simplify them. + shape.simplifyStroke(); + if (attemptShapeFallback && shape.simplified()) { // Usually we enter drawShapeUsingPathRenderer() because the shape+style was too // complex for dedicated draw ops. However, if GrStyledShape was able to reduce something diff --git a/src/gpu/geometry/GrStyledShape.cpp b/src/gpu/geometry/GrStyledShape.cpp index b29f8bc4ab..af3806446f 100644 --- a/src/gpu/geometry/GrStyledShape.cpp +++ b/src/gpu/geometry/GrStyledShape.cpp @@ -42,7 +42,8 @@ static bool is_inverted(bool originalIsInverted, GrStyledShape::FillInversion in return false; } -GrStyledShape GrStyledShape::MakeFilled(const GrStyledShape& original, FillInversion inversion) { +GrStyledShape GrStyledShape::MakeFilled(const GrStyledShape& original, FillInversion inversion, + SimplifyStroke simplifyStroke) { bool newIsInverted = is_inverted(original.fShape.inverted(), inversion); if (original.style().isSimpleFill() && newIsInverted == original.fShape.inverted()) { // By returning the original rather than falling through we can preserve any inherited style @@ -63,7 +64,7 @@ GrStyledShape GrStyledShape::MakeFilled(const GrStyledShape& original, FillInver // Going from a non-filled style to fill may allow additional simplifications (e.g. // closing an open rect that wasn't closed in the original shape because it had // stroke style). - result.simplify(); + result.simplify(simplifyStroke); // The above simplify() call only sets simplified to true if its geometry was changed, // since it already sees its style as a simple fill. Since the original style was not a // simple fill, MakeFilled always simplifies. @@ -305,11 +306,11 @@ void GrStyledShape::addGenIDChangeListener(sk_sp listener) c GrStyledShape GrStyledShape::MakeArc(const SkRect& oval, SkScalar startAngleDegrees, SkScalar sweepAngleDegrees, bool useCenter, - const GrStyle& style) { + const GrStyle& style, SimplifyStroke simplifyStroke) { GrStyledShape result; result.fShape.setArc({oval.makeSorted(), startAngleDegrees, sweepAngleDegrees, useCenter}); result.fStyle = style; - result.simplify(); + result.simplify(simplifyStroke); return result; } @@ -416,7 +417,7 @@ GrStyledShape::GrStyledShape(const GrStyledShape& parent, GrStyle::Apply apply, } else if (parent.fShape.isPath() && !parent.fShape.path().isVolatile()) { fInheritedPathForListeners.set(parent.fShape.path()); } - this->simplify(); + this->simplify(SimplifyStroke::kYes); this->setInheritedKey(*parentForKey, apply, scale); } @@ -561,9 +562,25 @@ bool GrStyledShape::asNestedRects(SkRect rects[2]) const { return allEq || allGoE1; } -void GrStyledShape::simplify() { - // Dashing ignores inverseness skbug.com/5421. - bool inverted = !fStyle.isDashed() && fShape.inverted(); +class AutoRestoreInverseness { +public: + AutoRestoreInverseness(GrShape* shape, const GrStyle& style) + // Dashing ignores inverseness skbug.com/5421. + : fShape(shape), fInverted(!style.isDashed() && fShape->inverted()) {} + + ~AutoRestoreInverseness() { + // Restore invertedness after any modifications were made to the shape type + fShape->setInverted(fInverted); + SkASSERT(!fShape->isPath() || fInverted == fShape->path().isInverseFillType()); + } + +private: + GrShape* fShape; + bool fInverted; +}; + +void GrStyledShape::simplify(SimplifyStroke simplifyStroke) { + AutoRestoreInverseness ari(&fShape, fStyle); unsigned simplifyFlags = 0; if (fStyle.isSimpleFill()) { @@ -579,7 +596,7 @@ void GrStyledShape::simplify() { // Remember if the original shape was closed; in the event we simplify to a point or line // because of degenerate geometry, we need to update joins and caps. GrShape::Type oldType = fShape.type(); - bool wasClosed = fShape.simplify(simplifyFlags); + fClosed = fShape.simplify(simplifyFlags); fSimplified = oldType != fShape.type(); if (fShape.isPath()) { @@ -605,16 +622,16 @@ void GrStyledShape::simplify() { // drawing simple shapes. fInheritedPathForListeners.reset(); - // Further simplifications to the shape based on the style - fSimplified |= this->simplifyStroke(wasClosed); + if (simplifyStroke == SimplifyStroke::kYes) { + // Further simplifications to the shape based on the style + this->simplifyStroke(); + } } - - // Restore invertedness after any modifications were made to the shape type - fShape.setInverted(inverted); - SkASSERT(!fShape.isPath() || inverted == fShape.path().isInverseFillType()); } -bool GrStyledShape::simplifyStroke(bool originallyClosed) { +void GrStyledShape::simplifyStroke() { + AutoRestoreInverseness ari(&fShape, fStyle); + // For stroke+filled rects, a mitered shape becomes a larger rect and a rounded shape // becomes a round rect. if (!fStyle.hasPathEffect() && fShape.isRect() && @@ -623,7 +640,7 @@ bool GrStyledShape::simplifyStroke(bool originallyClosed) { (fStyle.strokeRec().getJoin() == SkPaint::kMiter_Join && fStyle.strokeRec().getMiter() < SK_ScalarSqrt2)) { // Bevel-stroked rect needs path rendering - return false; + return; } SkScalar r = fStyle.strokeRec().getWidth() / 2; @@ -634,14 +651,15 @@ bool GrStyledShape::simplifyStroke(bool originallyClosed) { fShape.setRRect(SkRRect::MakeRectXY(fShape.rect(), r, r)); } fStyle = GrStyle::SimpleFill(); - return true; + fSimplified = true; + return; } // Otherwise, if we're a point or a line, we might be able to explicitly apply some of the // stroking (and even some of the dashing). Any other shape+style is too complicated to reduce. if ((!fShape.isPoint() && !fShape.isLine()) || fStyle.hasNonDashPathEffect() || fStyle.strokeRec().isHairlineStyle()) { - return false; + return; } // Tracks style simplifications, even if the geometry can't be further simplified. @@ -665,13 +683,13 @@ bool GrStyledShape::simplifyStroke(bool originallyClosed) { } if (!dropDash) { - return false; + return; } // Fall through to modifying the shape to respect the new stroke geometry fStyle = GrStyle(fStyle.strokeRec(), nullptr); // Since the reduced the line or point after dashing is dependent on the caps of the dashes, // we reset to be unclosed so we don't override the style based on joins later. - originallyClosed = false; + fClosed = false; styleSimplified = true; } @@ -680,7 +698,8 @@ bool GrStyledShape::simplifyStroke(bool originallyClosed) { bool strokeAndFilled = false; if (fStyle.isSimpleFill()) { fShape.reset(); - return true; + fSimplified = true; + return; } else if (fStyle.strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style) { // Stroke only SkStrokeRec rec = fStyle.strokeRec(); @@ -692,7 +711,7 @@ bool GrStyledShape::simplifyStroke(bool originallyClosed) { // A point or line that was formed by a degenerate closed shape needs its style updated to // reflect the fact that it doesn't actually produce caps. - if (originallyClosed) { + if (fClosed) { SkPaint::Cap cap; if (fShape.isLine() && fStyle.strokeRec().getJoin() == SkPaint::kRound_Join) { // As a closed shape, the line moves from a to b and back to a, producing a 180 degree @@ -761,7 +780,8 @@ bool GrStyledShape::simplifyStroke(bool originallyClosed) { } else { // Geometrically can't apply the style and turn into a fill, but might still be simpler // than before based solely on changes to fStyle. - return styleSimplified; + fSimplified |= styleSimplified; + return; } rect.outset(outset.fX, outset.fY); if (rect.isEmpty()) { @@ -775,5 +795,6 @@ bool GrStyledShape::simplifyStroke(bool originallyClosed) { } // If we made it here, the stroke was fully applied to the new shape so we can become a fill. fStyle = GrStyle::SimpleFill(); - return true; + fSimplified = true; + return; } diff --git a/src/gpu/geometry/GrStyledShape.h b/src/gpu/geometry/GrStyledShape.h index eaf5cc9d9e..f527d4ec64 100644 --- a/src/gpu/geometry/GrStyledShape.h +++ b/src/gpu/geometry/GrStyledShape.h @@ -44,44 +44,61 @@ public: GrStyledShape() {} - explicit GrStyledShape(const SkPath& path) : GrStyledShape(path, GrStyle::SimpleFill()) {} + enum class SimplifyStroke : bool { kNo = false, kYes }; - explicit GrStyledShape(const SkRRect& rrect) : GrStyledShape(rrect, GrStyle::SimpleFill()) {} + explicit GrStyledShape(const SkPath& path) + : GrStyledShape(path, GrStyle::SimpleFill(), SimplifyStroke::kNo) {} - explicit GrStyledShape(const SkRect& rect) : GrStyledShape(rect, GrStyle::SimpleFill()) {} + explicit GrStyledShape(const SkRRect& rrect) + : GrStyledShape(rrect, GrStyle::SimpleFill(), SimplifyStroke::kNo) {} - GrStyledShape(const SkPath& path, const SkPaint& paint) : GrStyledShape(path, GrStyle(paint)) {} + explicit GrStyledShape(const SkRect& rect) + : GrStyledShape(rect, GrStyle::SimpleFill(), SimplifyStroke::kNo) {} - GrStyledShape(const SkRRect& rrect, const SkPaint& paint) - : GrStyledShape(rrect, GrStyle(paint)) {} + GrStyledShape(const SkPath& path, const SkPaint& paint, + SimplifyStroke simplifyStroke = SimplifyStroke::kYes) + : GrStyledShape(path, GrStyle(paint), simplifyStroke) {} - GrStyledShape(const SkRect& rect, const SkPaint& paint) : GrStyledShape(rect, GrStyle(paint)) {} + GrStyledShape(const SkRRect& rrect, const SkPaint& paint, + SimplifyStroke simplifyStroke = SimplifyStroke::kYes) + : GrStyledShape(rrect, GrStyle(paint), simplifyStroke) {} - GrStyledShape(const SkPath& path, const GrStyle& style) : fShape(path), fStyle(style) { - this->simplify(); + GrStyledShape(const SkRect& rect, const SkPaint& paint, + SimplifyStroke simplifyStroke = SimplifyStroke::kYes) + : GrStyledShape(rect, GrStyle(paint), simplifyStroke) {} + + GrStyledShape(const SkPath& path, const GrStyle& style, + SimplifyStroke simplifyStroke = SimplifyStroke::kYes) + : fShape(path), fStyle(style) { + this->simplify(simplifyStroke); } - GrStyledShape(const SkRRect& rrect, const GrStyle& style) : fShape(rrect), fStyle(style) { - this->simplify(); + GrStyledShape(const SkRRect& rrect, const GrStyle& style, + SimplifyStroke simplifyStroke = SimplifyStroke::kYes) + : fShape(rrect), fStyle(style) { + this->simplify(simplifyStroke); } GrStyledShape(const SkRRect& rrect, SkPathDirection dir, unsigned start, bool inverted, - const GrStyle& style) + const GrStyle& style, SimplifyStroke simplifyStroke = SimplifyStroke::kYes) : fShape(rrect) , fStyle(style) { fShape.setPathWindingParams(dir, start); fShape.setInverted(inverted); - this->simplify(); + this->simplify(simplifyStroke); } - GrStyledShape(const SkRect& rect, const GrStyle& style) : fShape(rect), fStyle(style) { - this->simplify(); + GrStyledShape(const SkRect& rect, const GrStyle& style, + SimplifyStroke simplifyStroke = SimplifyStroke::kYes) + : fShape(rect), fStyle(style) { + this->simplify(simplifyStroke); } GrStyledShape(const GrStyledShape&); static GrStyledShape MakeArc(const SkRect& oval, SkScalar startAngleDegrees, - SkScalar sweepAngleDegrees, bool useCenter, const GrStyle& style); + SkScalar sweepAngleDegrees, bool useCenter, const GrStyle& style, + SimplifyStroke = SimplifyStroke::kYes); GrStyledShape& operator=(const GrStyledShape& that); @@ -103,7 +120,8 @@ public: * made non-inverted since dashing ignores inverseness). */ static GrStyledShape MakeFilled(const GrStyledShape& original, - FillInversion = FillInversion::kPreserve); + FillInversion = FillInversion::kPreserve, + SimplifyStroke = SimplifyStroke::kYes); const GrStyle& style() const { return fStyle; } @@ -249,6 +267,12 @@ public: bool testingOnly_isPath() const; bool testingOnly_isNonVolatilePath() const; + /** + * As an optional part of the simplification process, some shapes can have stroking trivially + * evaluated and form a new geometry with just a fill. + */ + void simplifyStroke(); + private: /** Constructor used by the applyStyle() function */ GrStyledShape(const GrStyledShape& parentShape, GrStyle::Apply, SkScalar scale); @@ -259,12 +283,12 @@ private: */ void setInheritedKey(const GrStyledShape& parentShape, GrStyle::Apply, SkScalar scale); - // Similar to GrShape::simplify but also takes into account style and stroking, possibly - // applying the style explicitly to produce a new analytic shape with a simpler style. - void simplify(); - // As part of the simplification process, some shapes can have stroking trivially evaluated - // and form a new geometry with just a fill. - bool simplifyStroke(bool originallyClosed); + /** + * Similar to GrShape::simplify but also takes into account style and, optionally, stroking. + * Some stroked shapes can be represented as a different filled primitive (e.g. a stroked line + * becomes a filled round rect). When SimplifyStroke is kYes, such optimizations are permitted. + */ + void simplify(SimplifyStroke); /** Gets the path that gen id listeners should be added to. */ const SkPath* originalPathForListeners() const; @@ -273,6 +297,7 @@ private: GrStyle fStyle; // Gen ID of the original path (path may be modified or simplified away). int32_t fGenID = 0; + bool fClosed = false; bool fSimplified = false; SkTLazy fInheritedPathForListeners;