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 <michaelludwig@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2021-02-02 11:53:19 -07:00 committed by Skia Commit-Bot
parent 8ca4626a4b
commit b8ed2bce50
3 changed files with 113 additions and 57 deletions

View File

@ -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

View File

@ -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<SkIDChangeListener> 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;
}

View File

@ -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<SkPath> fInheritedPathForListeners;