Retry drawing the simplified shape

Previously, functions like GrRTC::drawRect or drawRRect would check
for common cases and then fallback to creating a GrStyledShape and
calling drawShapeWithPathRenderer. This would always use path rendering,
even if the analysis that GrStyledShape did was able to change the style.

This adds one additional retry to go through drawShape() before the
settling on path rendering.

Change-Id: I1dcf218f9bf83d40dad992352bcd4a6e74b01fad
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/285720
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Michael Ludwig 2020-04-30 20:16:36 -04:00 committed by Skia Commit-Bot
parent 672c7a698a
commit 6a6de65fd9
4 changed files with 57 additions and 21 deletions

View File

@ -2268,7 +2268,9 @@ void GrRenderTargetContext::drawShape(const GrClip& clip,
}
}
this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape);
// If we get here in drawShape(), we definitely need to use path rendering
this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape,
/* attempt fallback */ false);
}
bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
@ -2359,7 +2361,8 @@ void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
GrPaint&& paint,
GrAA aa,
const SkMatrix& viewMatrix,
const GrStyledShape& originalShape) {
const GrStyledShape& originalShape,
bool attemptShapeFallback) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext);
@ -2368,6 +2371,14 @@ void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
return;
}
if (attemptShapeFallback && originalShape.simplified()) {
// Usually we enter drawShapeUsingPathRenderer() because the shape+style was too
// complex for dedicated draw ops. However, if GrStyledShape was able to reduce something
// we ought to try again instead of going right to path rendering.
this->drawShape(clip, std::move(paint), aa, viewMatrix, originalShape);
return;
}
SkIRect clipConservativeBounds;
clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);

View File

@ -671,8 +671,10 @@ private:
DrawQuad* quad,
const SkRect* subset = nullptr);
// If 'attemptShapeFallback' is true, and the original shape had been simplfied, this
// will re-route through drawShape() to see if we can avoid path rendering one more time.
void drawShapeUsingPathRenderer(const GrClip&, GrPaint&&, GrAA, const SkMatrix&,
const GrStyledShape&);
const GrStyledShape&, bool attemptShapeFallback = true);
void addOp(std::unique_ptr<GrOp>);

View File

@ -15,6 +15,7 @@ GrStyledShape& GrStyledShape::operator=(const GrStyledShape& that) {
fShape = that.fShape;
fStyle = that.fStyle;
fGenID = that.fGenID;
fSimplified = that.fSimplified;
fInheritedKey.reset(that.fInheritedKey.count());
sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
@ -63,6 +64,10 @@ GrStyledShape GrStyledShape::MakeFilled(const GrStyledShape& original, FillInver
// closing an open rect that wasn't closed in the original shape because it had
// stroke style).
result.simplify();
// 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.
result.fSimplified = true;
}
// Sanity check that lines/points were converted to empty by the style change
@ -311,7 +316,8 @@ GrStyledShape GrStyledShape::MakeArc(const SkRect& oval, SkScalar startAngleDegr
GrStyledShape::GrStyledShape(const GrStyledShape& that)
: fShape(that.fShape)
, fStyle(that.fStyle)
, fGenID(that.fGenID) {
, fGenID(that.fGenID)
, fSimplified(that.fSimplified) {
fInheritedKey.reset(that.fInheritedKey.count());
sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
sizeof(uint32_t) * fInheritedKey.count());
@ -572,7 +578,9 @@ 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);
fSimplified = oldType != fShape.type();
if (fShape.isPath()) {
// The shape remains a path, so configure the gen ID and canonicalize fill type if possible
@ -598,7 +606,7 @@ void GrStyledShape::simplify() {
fInheritedPathForListeners.reset();
// Further simplifications to the shape based on the style
this->simplifyStroke(wasClosed);
fSimplified |= this->simplifyStroke(wasClosed);
}
// Restore invertedness after any modifications were made to the shape type
@ -606,7 +614,7 @@ void GrStyledShape::simplify() {
SkASSERT(!fShape.isPath() || inverted == fShape.path().isInverseFillType());
}
void GrStyledShape::simplifyStroke(bool originallyClosed) {
bool GrStyledShape::simplifyStroke(bool originallyClosed) {
// For stroke+filled rects, a mitered shape becomes a larger rect and a rounded shape
// becomes a round rect.
if (!fStyle.hasPathEffect() && fShape.isRect() &&
@ -615,7 +623,7 @@ void GrStyledShape::simplifyStroke(bool originallyClosed) {
(fStyle.strokeRec().getJoin() == SkPaint::kMiter_Join &&
fStyle.strokeRec().getMiter() < SK_ScalarSqrt2)) {
// Bevel-stroked rect needs path rendering
return;
return false;
}
SkScalar r = fStyle.strokeRec().getWidth() / 2;
@ -626,16 +634,18 @@ void GrStyledShape::simplifyStroke(bool originallyClosed) {
fShape.setRRect(SkRRect::MakeRectXY(fShape.rect(), r, r));
}
fStyle = GrStyle::SimpleFill();
return;
return true;
}
// 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;
return false;
}
// Tracks style simplifications, even if the geometry can't be further simplified.
bool styleSimplified = false;
if (fStyle.isDashed()) {
// For dashing a point, if the first interval is on, we can drop the dash and just draw
// the caps. For dashing a line, if every off interval is 0 length, its a stroke.
@ -655,13 +665,14 @@ void GrStyledShape::simplifyStroke(bool originallyClosed) {
}
if (!dropDash) {
return;
return false;
}
// 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;
styleSimplified = true;
}
// At this point, we're a line or point with no path effects. Any fill portion of the style
@ -669,12 +680,13 @@ void GrStyledShape::simplifyStroke(bool originallyClosed) {
bool strokeAndFilled = false;
if (fStyle.isSimpleFill()) {
fShape.reset();
return;
return true;
} else if (fStyle.strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
// Stroke only
SkStrokeRec rec = fStyle.strokeRec();
rec.setStrokeStyle(fStyle.strokeRec().getWidth(), false);
fStyle = GrStyle(rec, nullptr);
styleSimplified = true;
strokeAndFilled = true;
}
@ -704,9 +716,13 @@ void GrStyledShape::simplifyStroke(bool originallyClosed) {
cap = SkPaint::kButt_Cap;
}
SkStrokeRec rec = fStyle.strokeRec();
rec.setStrokeParams(cap, SkPaint::kDefault_Join, fStyle.strokeRec().getMiter());
fStyle = GrStyle(rec, nullptr);
if (cap != fStyle.strokeRec().getCap() ||
SkPaint::kDefault_Join != fStyle.strokeRec().getJoin()) {
SkStrokeRec rec = fStyle.strokeRec();
rec.setStrokeParams(cap, SkPaint::kDefault_Join, fStyle.strokeRec().getMiter());
fStyle = GrStyle(rec, nullptr);
styleSimplified = true;
}
}
if (fShape.isPoint()) {
@ -743,7 +759,9 @@ void GrStyledShape::simplifyStroke(bool originallyClosed) {
outset.fX = fStyle.strokeRec().getWidth() / 2.f;
outset.fY = SkPaint::kButt_Cap == fStyle.strokeRec().getCap() ? 0.f : outset.fX;
} else {
return;
// 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;
}
rect.outset(outset.fX, outset.fY);
if (rect.isEmpty()) {
@ -757,4 +775,5 @@ void 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;
}

View File

@ -107,6 +107,9 @@ public:
const GrStyle& style() const { return fStyle; }
// True if the shape and/or style were modified into a simpler, equivalent pairing
bool simplified() const { return fSimplified; }
/**
* Returns a shape that has either applied the path effect or path effect and stroking
* information from this shape's style to its geometry. Scale is used when approximating the
@ -262,17 +265,18 @@ private:
void simplify();
// As part of the simplification process, some shapes can have stroking trivially evaluated
// and form a new geometry with just a fill.
void simplifyStroke(bool originallyClosed);
bool simplifyStroke(bool originallyClosed);
/** Gets the path that gen id listeners should be added to. */
const SkPath* originalPathForListeners() const;
GrShape fShape;
GrStyle fStyle;
GrShape fShape;
GrStyle fStyle;
// Gen ID of the original path (path may be modified or simplified away).
int32_t fGenID = 0;
int32_t fGenID = 0;
bool fSimplified = false;
SkTLazy<SkPath> fInheritedPathForListeners;
SkAutoSTArray<8, uint32_t> fInheritedKey;
SkTLazy<SkPath> fInheritedPathForListeners;
SkAutoSTArray<8, uint32_t> fInheritedKey;
};
#endif