Improve GrPathRendererChain heuristics
Changes GrPathRenderer::canDrawPath to return a 'CanDrawPath' enum,
which contains a new kAsBackup value that means "I'm better than SW,
but give the path renderers below me a chance first."
Bug: skia:
Change-Id: I45aac5462ca1bc0bc839eb1c315db9493901a07e
Reviewed-on: https://skia-review.googlesource.com/42222
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/ops/GrAAConvexPathRenderer.cpp b/src/gpu/ops/GrAAConvexPathRenderer.cpp
index 425dbae..0fe7443 100644
--- a/src/gpu/ops/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAAConvexPathRenderer.cpp
@@ -665,10 +665,14 @@
///////////////////////////////////////////////////////////////////////////////
-bool GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
- return (args.fCaps->shaderCaps()->shaderDerivativeSupport() &&
- (GrAAType::kCoverage == args.fAAType) && args.fShape->style().isSimpleFill() &&
- !args.fShape->inverseFilled() && args.fShape->knownToBeConvex());
+GrPathRenderer::CanDrawPath
+GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
+ if (args.fCaps->shaderCaps()->shaderDerivativeSupport() &&
+ (GrAAType::kCoverage == args.fAAType) && args.fShape->style().isSimpleFill() &&
+ !args.fShape->inverseFilled() && args.fShape->knownToBeConvex()) {
+ return CanDrawPath::kYes;
+ }
+ return CanDrawPath::kNo;
}
// extract the result vertices and indices from the GrAAConvexTessellator
diff --git a/src/gpu/ops/GrAAConvexPathRenderer.h b/src/gpu/ops/GrAAConvexPathRenderer.h
index 420ca60..a31d6b9 100644
--- a/src/gpu/ops/GrAAConvexPathRenderer.h
+++ b/src/gpu/ops/GrAAConvexPathRenderer.h
@@ -15,7 +15,7 @@
GrAAConvexPathRenderer();
private:
- bool onCanDrawPath(const CanDrawPathArgs&) const override;
+ CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
};
diff --git a/src/gpu/ops/GrAAHairLinePathRenderer.cpp b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
index e00ca3f..ba72eac 100644
--- a/src/gpu/ops/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
@@ -677,26 +677,27 @@
///////////////////////////////////////////////////////////////////////////////
-bool GrAAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
+GrPathRenderer::CanDrawPath
+GrAAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
if (GrAAType::kCoverage != args.fAAType) {
- return false;
+ return CanDrawPath::kNo;
}
if (!IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr)) {
- return false;
+ return CanDrawPath::kNo;
}
// We don't currently handle dashing in this class though perhaps we should.
if (args.fShape->style().pathEffect()) {
- return false;
+ return CanDrawPath::kNo;
}
if (SkPath::kLine_SegmentMask == args.fShape->segmentMask() ||
args.fCaps->shaderCaps()->shaderDerivativeSupport()) {
- return true;
+ return CanDrawPath::kYes;
}
- return false;
+ return CanDrawPath::kNo;
}
template <class VertexType>
diff --git a/src/gpu/ops/GrAAHairLinePathRenderer.h b/src/gpu/ops/GrAAHairLinePathRenderer.h
index e2406a5..b52d5e9 100644
--- a/src/gpu/ops/GrAAHairLinePathRenderer.h
+++ b/src/gpu/ops/GrAAHairLinePathRenderer.h
@@ -19,7 +19,7 @@
typedef SkTArray<float, true> FloatArray;
private:
- bool onCanDrawPath(const CanDrawPathArgs&) const override;
+ CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
diff --git a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
index c1fd4f7..d206951 100644
--- a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
@@ -34,39 +34,46 @@
///////////////////////////////////////////////////////////////////////////////
-bool GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
+GrPathRenderer::CanDrawPath
+GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
if (GrAAType::kCoverage != args.fAAType) {
- return false;
+ return CanDrawPath::kNo;
}
if (!args.fShape->knownToBeConvex()) {
- return false;
+ return CanDrawPath::kNo;
}
if (args.fShape->style().pathEffect()) {
- return false;
+ return CanDrawPath::kNo;
}
if (args.fShape->inverseFilled()) {
- return false;
+ return CanDrawPath::kNo;
}
if (args.fShape->bounds().width() <= 0 && args.fShape->bounds().height() <= 0) {
// Stroked zero length lines should draw, but this PR doesn't handle that case
- return false;
+ return CanDrawPath::kNo;
}
const SkStrokeRec& stroke = args.fShape->style().strokeRec();
if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
if (!args.fViewMatrix->isSimilarity()) {
- return false;
+ return CanDrawPath::kNo;
}
SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth();
if (strokeWidth < 1.0f && stroke.getStyle() == SkStrokeRec::kStroke_Style) {
- return false;
+ return CanDrawPath::kNo;
}
- return strokeWidth <= kMaxStrokeWidth &&
- args.fShape->knownToBeClosed() &&
- stroke.getJoin() != SkPaint::Join::kRound_Join;
+ if (strokeWidth > kMaxStrokeWidth ||
+ !args.fShape->knownToBeClosed() ||
+ stroke.getJoin() == SkPaint::Join::kRound_Join) {
+ return CanDrawPath::kNo;
+ }
+ return CanDrawPath::kYes;
}
- return stroke.getStyle() == SkStrokeRec::kFill_Style;
+ if (stroke.getStyle() != SkStrokeRec::kFill_Style) {
+ return CanDrawPath::kNo;
+ }
+ return CanDrawPath::kYes;
}
// extract the result vertices and indices from the GrAAConvexTessellator
diff --git a/src/gpu/ops/GrAALinearizingConvexPathRenderer.h b/src/gpu/ops/GrAALinearizingConvexPathRenderer.h
index afee5db..4fdcb12 100644
--- a/src/gpu/ops/GrAALinearizingConvexPathRenderer.h
+++ b/src/gpu/ops/GrAALinearizingConvexPathRenderer.h
@@ -15,7 +15,7 @@
GrAALinearizingConvexPathRenderer();
private:
- bool onCanDrawPath(const CanDrawPathArgs&) const override;
+ CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
};
diff --git a/src/gpu/ops/GrDashLinePathRenderer.cpp b/src/gpu/ops/GrDashLinePathRenderer.cpp
index 38d486c..73c2b3e 100644
--- a/src/gpu/ops/GrDashLinePathRenderer.cpp
+++ b/src/gpu/ops/GrDashLinePathRenderer.cpp
@@ -12,18 +12,22 @@
#include "ops/GrDashOp.h"
#include "ops/GrMeshDrawOp.h"
-bool GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
+GrPathRenderer::CanDrawPath
+GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
SkPoint pts[2];
bool inverted;
if (args.fShape->style().isDashed() && args.fShape->asLine(pts, &inverted)) {
if (args.fAAType == GrAAType::kMixedSamples) {
- return false;
+ return CanDrawPath::kNo;
}
// We should never have an inverse dashed case.
SkASSERT(!inverted);
- return GrDashOp::CanDrawDashLine(pts, args.fShape->style(), *args.fViewMatrix);
+ if (!GrDashOp::CanDrawDashLine(pts, args.fShape->style(), *args.fViewMatrix)) {
+ return CanDrawPath::kNo;
+ }
+ return CanDrawPath::kYes;
}
- return false;
+ return CanDrawPath::kNo;
}
bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
diff --git a/src/gpu/ops/GrDashLinePathRenderer.h b/src/gpu/ops/GrDashLinePathRenderer.h
index 11abf99..23227bc 100644
--- a/src/gpu/ops/GrDashLinePathRenderer.h
+++ b/src/gpu/ops/GrDashLinePathRenderer.h
@@ -14,7 +14,7 @@
class GrDashLinePathRenderer : public GrPathRenderer {
private:
- bool onCanDrawPath(const CanDrawPathArgs&) const override;
+ CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
StencilSupport onGetStencilSupport(const GrShape&) const override {
return kNoSupport_StencilSupport;
diff --git a/src/gpu/ops/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp
index e3b48a8..9741781 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.cpp
+++ b/src/gpu/ops/GrDefaultPathRenderer.cpp
@@ -609,15 +609,20 @@
return true;
}
-bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
+GrPathRenderer::CanDrawPath
+GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
bool isHairline = IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr);
// If we aren't a single_pass_shape or hairline, we require stencil buffers.
if (!(single_pass_shape(*args.fShape) || isHairline) && args.fCaps->avoidStencilBuffers()) {
- return false;
+ return CanDrawPath::kNo;
}
// This can draw any path with any simple fill style but doesn't do coverage-based antialiasing.
- return GrAAType::kCoverage != args.fAAType &&
- (args.fShape->style().isSimpleFill() || isHairline);
+ if (GrAAType::kCoverage == args.fAAType ||
+ (!args.fShape->style().isSimpleFill() && !isHairline)) {
+ return CanDrawPath::kNo;
+ }
+ // This is the fallback renderer for when a path is too complicated for the others to draw.
+ return CanDrawPath::kAsBackup;
}
bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
diff --git a/src/gpu/ops/GrDefaultPathRenderer.h b/src/gpu/ops/GrDefaultPathRenderer.h
index 7f7ab2a..f7d9819 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.h
+++ b/src/gpu/ops/GrDefaultPathRenderer.h
@@ -23,7 +23,7 @@
private:
StencilSupport onGetStencilSupport(const GrShape&) const override;
- bool onCanDrawPath(const CanDrawPathArgs&) const override;
+ CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
diff --git a/src/gpu/ops/GrMSAAPathRenderer.cpp b/src/gpu/ops/GrMSAAPathRenderer.cpp
index ef19367..b80a811 100644
--- a/src/gpu/ops/GrMSAAPathRenderer.cpp
+++ b/src/gpu/ops/GrMSAAPathRenderer.cpp
@@ -682,15 +682,18 @@
return true;
}
-bool GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
+GrPathRenderer::CanDrawPath GrMSAAPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
// If we aren't a single_pass_shape, we require stencil buffers.
if (!single_pass_shape(*args.fShape) && args.fCaps->avoidStencilBuffers()) {
- return false;
+ return CanDrawPath::kNo;
}
// This path renderer only fills and relies on MSAA for antialiasing. Stroked shapes are
// handled by passing on the original shape and letting the caller compute the stroked shape
// which will have a fill style.
- return args.fShape->style().isSimpleFill() && (GrAAType::kCoverage != args.fAAType);
+ if (!args.fShape->style().isSimpleFill() || GrAAType::kCoverage == args.fAAType) {
+ return CanDrawPath::kNo;
+ }
+ return CanDrawPath::kYes;
}
bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
diff --git a/src/gpu/ops/GrMSAAPathRenderer.h b/src/gpu/ops/GrMSAAPathRenderer.h
index 13d3e15..1353867 100644
--- a/src/gpu/ops/GrMSAAPathRenderer.h
+++ b/src/gpu/ops/GrMSAAPathRenderer.h
@@ -15,7 +15,7 @@
private:
StencilSupport onGetStencilSupport(const GrShape&) const override;
- bool onCanDrawPath(const CanDrawPathArgs&) const override;
+ CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index cfdf873..1b06486 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -81,30 +81,30 @@
}
////////////////////////////////////////////////////////////////////////////////
-bool GrSmallPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
+GrPathRenderer::CanDrawPath GrSmallPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
if (!args.fCaps->shaderCaps()->shaderDerivativeSupport()) {
- return false;
+ return CanDrawPath::kNo;
}
// If the shape has no key then we won't get any reuse.
if (!args.fShape->hasUnstyledKey()) {
- return false;
+ return CanDrawPath::kNo;
}
// This only supports filled paths, however, the caller may apply the style to make a filled
// path and try again.
if (!args.fShape->style().isSimpleFill()) {
- return false;
+ return CanDrawPath::kNo;
}
// This does non-inverse coverage-based antialiased fills.
if (GrAAType::kCoverage != args.fAAType) {
- return false;
+ return CanDrawPath::kNo;
}
// TODO: Support inverse fill
if (args.fShape->inverseFilled()) {
- return false;
+ return CanDrawPath::kNo;
}
// currently don't support perspective
if (args.fViewMatrix->hasPerspective()) {
- return false;
+ return CanDrawPath::kNo;
}
// Only support paths with bounds within kMaxDim by kMaxDim,
@@ -112,15 +112,18 @@
// The goal is to accelerate rendering of lots of small paths that may be scaling.
SkScalar scaleFactors[2];
if (!args.fViewMatrix->getMinMaxScales(scaleFactors)) {
- return false;
+ return CanDrawPath::kNo;
}
SkRect bounds = args.fShape->styledBounds();
SkScalar minDim = SkMinScalar(bounds.width(), bounds.height());
SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
SkScalar minSize = minDim * SkScalarAbs(scaleFactors[0]);
SkScalar maxSize = maxDim * SkScalarAbs(scaleFactors[1]);
+ if (maxDim > kMaxDim || kMinSize > minSize || maxSize > kMaxSize) {
+ return CanDrawPath::kNo;
+ }
- return maxDim <= kMaxDim && kMinSize <= minSize && maxSize <= kMaxSize;
+ return CanDrawPath::kYes;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/ops/GrSmallPathRenderer.h b/src/gpu/ops/GrSmallPathRenderer.h
index d10c4ba..b958baa 100644
--- a/src/gpu/ops/GrSmallPathRenderer.h
+++ b/src/gpu/ops/GrSmallPathRenderer.h
@@ -31,7 +31,7 @@
return GrPathRenderer::kNoSupport_StencilSupport;
}
- bool onCanDrawPath(const CanDrawPathArgs&) const override;
+ CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
diff --git a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
index 4d86efd..3179eba 100644
--- a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
@@ -31,18 +31,22 @@
: fResourceProvider(resourceProvider) {
}
-bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
+GrPathRenderer::CanDrawPath
+GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
// GrPath doesn't support hairline paths. An arbitrary path effect could produce a hairline
// path.
if (args.fShape->style().strokeRec().isHairlineStyle() ||
args.fShape->style().hasNonDashPathEffect()) {
- return false;
+ return CanDrawPath::kNo;
}
if (args.fHasUserStencilSettings) {
- return false;
+ return CanDrawPath::kNo;
}
// doesn't do per-path AA, relies on the target having MSAA.
- return (GrAAType::kCoverage != args.fAAType);
+ if (GrAAType::kCoverage == args.fAAType) {
+ return CanDrawPath::kNo;
+ }
+ return CanDrawPath::kYes;
}
static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const GrShape& shape) {
diff --git a/src/gpu/ops/GrStencilAndCoverPathRenderer.h b/src/gpu/ops/GrStencilAndCoverPathRenderer.h
index c896e61..dda0157 100644
--- a/src/gpu/ops/GrStencilAndCoverPathRenderer.h
+++ b/src/gpu/ops/GrStencilAndCoverPathRenderer.h
@@ -28,7 +28,7 @@
return GrPathRenderer::kStencilOnly_StencilSupport;
}
- bool onCanDrawPath(const CanDrawPathArgs&) const override;
+ CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
diff --git a/src/gpu/ops/GrTessellatingPathRenderer.cpp b/src/gpu/ops/GrTessellatingPathRenderer.cpp
index 641a037..2db4ffc 100644
--- a/src/gpu/ops/GrTessellatingPathRenderer.cpp
+++ b/src/gpu/ops/GrTessellatingPathRenderer.cpp
@@ -132,27 +132,31 @@
GrTessellatingPathRenderer::GrTessellatingPathRenderer() {
}
-bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
- // This path renderer can draw fill styles, and can do screenspace antialiasing via a
- // one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex
- // ones to simpler algorithms. We pass on paths that have styles, though they may come back
- // around after applying the styling information to the geometry to create a filled path. In
- // the non-AA case, We skip paths thta don't have a key since the real advantage of this path
+GrPathRenderer::CanDrawPath
+GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
+ // This path renderer can draw fill styles, and can do screenspace antialiasing via a one-pixel
+ // coverage ramp. It can do convex and concave paths, but we'll give simpler algorithms a chance
+ // to draw the convex ones first. We pass on paths that have styles, though they may come back
+ // around after applying the styling information to the geometry to create a filled path. In the
+ // non-AA case, We skip paths that don't have a key since the real advantage of this path
// renderer comes from caching the tessellated geometry. In the AA case, we do not cache, so we
// accept paths without keys.
- if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
- return false;
+ if (!args.fShape->style().isSimpleFill()) {
+ return CanDrawPath::kNo;
}
if (GrAAType::kCoverage == args.fAAType) {
SkPath path;
args.fShape->asPath(&path);
if (path.countVerbs() > 10) {
- return false;
+ return CanDrawPath::kNo;
}
} else if (!args.fShape->hasUnstyledKey()) {
- return false;
+ return CanDrawPath::kNo;
}
- return true;
+ if (args.fShape->knownToBeConvex()) {
+ return CanDrawPath::kAsBackup;
+ }
+ return CanDrawPath::kYes;
}
namespace {
diff --git a/src/gpu/ops/GrTessellatingPathRenderer.h b/src/gpu/ops/GrTessellatingPathRenderer.h
index d5f2c7a..7dd50fc 100644
--- a/src/gpu/ops/GrTessellatingPathRenderer.h
+++ b/src/gpu/ops/GrTessellatingPathRenderer.h
@@ -19,7 +19,7 @@
GrTessellatingPathRenderer();
private:
- bool onCanDrawPath(const CanDrawPathArgs& ) const override;
+ CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
StencilSupport onGetStencilSupport(const GrShape&) const override {
return GrPathRenderer::kNoSupport_StencilSupport;