aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar senorblanco <senorblanco@chromium.org>2015-08-06 10:28:55 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-08-06 10:28:55 -0700
commitb4f9d0ec6cc95ce46f9351fee5adaffcfa729e38 (patch)
tree8228bd16c5d42c782475409f49c6dd9d14a77b52
parente47829b6b1eeb6b0c97ccb3df3016d197046824c (diff)
Implement caching of stroked paths in the tessellating path renderer.
This requires adding the stroke info to the cache key, and doing the stroking and dashing before rendering as triangles. BUG=skia:3755 Committed: https://skia.googlesource.com/skia/+/29e0d3f267a03546f236023347cdb4595ece2fd1 Review URL: https://codereview.chromium.org/1275553002
-rw-r--r--include/gpu/GrTestUtils.h2
-rw-r--r--src/gpu/GrTessellatingPathRenderer.cpp58
-rw-r--r--src/gpu/GrTestUtils.cpp37
3 files changed, 80 insertions, 17 deletions
diff --git a/include/gpu/GrTestUtils.h b/include/gpu/GrTestUtils.h
index 6fed7e1761..91f36ea2d9 100644
--- a/include/gpu/GrTestUtils.h
+++ b/include/gpu/GrTestUtils.h
@@ -16,6 +16,7 @@
#include "SkRandom.h"
#include "SkStrokeRec.h"
+class GrStrokeInfo;
class SkMatrix;
class SkPath;
class SkRRect;
@@ -35,6 +36,7 @@ const SkRRect& TestRRectSimple(SkRandom*);
const SkPath& TestPath(SkRandom*);
const SkPath& TestPathConvex(SkRandom*);
SkStrokeRec TestStrokeRec(SkRandom*);
+GrStrokeInfo TestStrokeInfo(SkRandom*);
}
diff --git a/src/gpu/GrTessellatingPathRenderer.cpp b/src/gpu/GrTessellatingPathRenderer.cpp
index 76bfa13161..ebb23903bb 100644
--- a/src/gpu/GrTessellatingPathRenderer.cpp
+++ b/src/gpu/GrTessellatingPathRenderer.cpp
@@ -1384,9 +1384,11 @@ private:
} // namespace
bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
- // This path renderer can draw all fill styles, but does not do antialiasing. It can do convex
- // and concave paths, but we'll leave the convex ones to simpler algorithms.
- return args.fStroke->isFillStyle() && !args.fAntiAlias && !args.fPath->isConvex();
+ // This path renderer can draw all fill styles, all stroke styles except hairlines, but does
+ // not do antialiasing. It can do convex and concave paths, but we'll leave the convex ones to
+ // simpler algorithms.
+ return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, NULL) &&
+ !args.fAntiAlias && !args.fPath->isConvex();
}
class TessellatingPathBatch : public GrBatch {
@@ -1394,9 +1396,10 @@ public:
static GrBatch* Create(const GrColor& color,
const SkPath& path,
+ const GrStrokeInfo& stroke,
const SkMatrix& viewMatrix,
SkRect clipBounds) {
- return SkNEW_ARGS(TessellatingPathBatch, (color, path, viewMatrix, clipBounds));
+ return SkNEW_ARGS(TessellatingPathBatch, (color, path, stroke, viewMatrix, clipBounds));
}
const char* name() const override { return "TessellatingPathBatch"; }
@@ -1421,7 +1424,23 @@ public:
int tessellate(GrUniqueKey* key,
GrResourceProvider* resourceProvider,
SkAutoTUnref<GrVertexBuffer>& vertexBuffer) {
- SkRect pathBounds = fPath.getBounds();
+ SkPath path;
+ GrStrokeInfo stroke(fStroke);
+ if (stroke.isDashed()) {
+ if (!stroke.applyDashToPath(&path, &stroke, fPath)) {
+ return 0;
+ }
+ } else {
+ path = fPath;
+ }
+ if (!stroke.isFillStyle()) {
+ stroke.setResScale(SkScalarAbs(fViewMatrix.getMaxScale()));
+ if (!stroke.applyToPath(&path, path)) {
+ return 0;
+ }
+ stroke.setFillStyle();
+ }
+ SkRect pathBounds = path.getBounds();
Comparator c;
if (pathBounds.width() > pathBounds.height()) {
c.sweep_lt = sweep_lt_horiz;
@@ -1433,7 +1452,7 @@ public:
SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance;
SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMatrix, pathBounds);
int contourCnt;
- int maxPts = GrPathUtils::worstCasePointCount(fPath, &contourCnt, tol);
+ int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol);
if (maxPts <= 0) {
return 0;
}
@@ -1441,7 +1460,7 @@ public:
SkDebugf("Path not rendered, too many verts (%d)\n", maxPts);
return 0;
}
- SkPath::FillType fillType = fPath.getFillType();
+ SkPath::FillType fillType = path.getFillType();
if (SkPath::IsInverseFillType(fillType)) {
contourCnt++;
}
@@ -1455,7 +1474,7 @@ public:
// connectivity of one Edge per Vertex (will grow for intersections).
SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge)));
bool isLinear;
- path_to_contours(fPath, tol, fClipBounds, contours.get(), alloc, &isLinear);
+ path_to_contours(path, tol, fClipBounds, contours.get(), alloc, &isLinear);
Poly* polys;
polys = contours_to_polys(contours.get(), contourCnt, c, alloc);
int count = 0;
@@ -1503,13 +1522,15 @@ public:
GrUniqueKey key;
int clipBoundsSize32 =
fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) : 0;
- GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32);
+ int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt();
+ GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strokeDataSize32);
builder[0] = fPath.getGenerationID();
builder[1] = fPath.getFillType();
// For inverse fills, the tessellation is dependent on clip bounds.
if (fPath.isInverseFillType()) {
memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds));
}
+ fStroke.asUniqueKeyFragment(&builder[2 + clipBoundsSize32]);
builder.finish();
GrResourceProvider* rp = batchTarget->resourceProvider();
SkAutoTUnref<GrVertexBuffer> vertexBuffer(rp->findAndRefTByUniqueKey<GrVertexBuffer>(key));
@@ -1561,20 +1582,33 @@ public:
private:
TessellatingPathBatch(const GrColor& color,
const SkPath& path,
+ const GrStrokeInfo& stroke,
const SkMatrix& viewMatrix,
const SkRect& clipBounds)
: fColor(color)
, fPath(path)
+ , fStroke(stroke)
, fViewMatrix(viewMatrix)
, fClipBounds(clipBounds) {
this->initClassID<TessellatingPathBatch>();
fBounds = path.getBounds();
+ if (!stroke.isFillStyle()) {
+ SkScalar radius = SkScalarHalf(stroke.getWidth());
+ if (stroke.getJoin() == SkPaint::kMiter_Join) {
+ SkScalar scale = stroke.getMiter();
+ if (scale > SK_Scalar1) {
+ radius = SkScalarMul(radius, scale);
+ }
+ }
+ fBounds.outset(radius, radius);
+ }
viewMatrix.mapRect(&fBounds);
}
GrColor fColor;
SkPath fPath;
+ GrStrokeInfo fStroke;
SkMatrix fViewMatrix;
SkRect fClipBounds; // in source space
GrPipelineInfo fPipelineInfo;
@@ -1596,7 +1630,8 @@ bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
}
vmi.mapRect(&clipBounds);
SkAutoTUnref<GrBatch> batch(TessellatingPathBatch::Create(args.fColor, *args.fPath,
- *args.fViewMatrix, clipBounds));
+ *args.fStroke, *args.fViewMatrix,
+ clipBounds));
args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
return true;
@@ -1617,7 +1652,8 @@ BATCH_TEST_DEFINE(TesselatingPathBatch) {
SkFAIL("Cannot invert matrix\n");
}
vmi.mapRect(&clipBounds);
- return TessellatingPathBatch::Create(color, path, viewMatrix, clipBounds);
+ GrStrokeInfo strokeInfo = GrTest::TestStrokeInfo(random);
+ return TessellatingPathBatch::Create(color, path, strokeInfo, viewMatrix, clipBounds);
}
#endif
diff --git a/src/gpu/GrTestUtils.cpp b/src/gpu/GrTestUtils.cpp
index b690d7e3cd..714b99f65c 100644
--- a/src/gpu/GrTestUtils.cpp
+++ b/src/gpu/GrTestUtils.cpp
@@ -5,8 +5,10 @@
* found in the LICENSE file.
*/
+#include "GrStrokeInfo.h"
#include "GrTestUtils.h"
#include "SkMatrix.h"
+#include "SkPathEffect.h"
#include "SkPath.h"
#include "SkRRect.h"
@@ -216,21 +218,44 @@ const SkPath& TestPathConvex(SkRandom* random) {
return gPath[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gPath)))];
}
-SkStrokeRec TestStrokeRec(SkRandom* random) {
- SkStrokeRec::InitStyle style =
- SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
- SkStrokeRec rec(style);
+static void randomize_stroke_rec(SkStrokeRec* rec, SkRandom* random) {
bool strokeAndFill = random->nextBool();
SkScalar strokeWidth = random->nextBool() ? 0.f : 1.f;
- rec.setStrokeStyle(strokeWidth, strokeAndFill);
+ rec->setStrokeStyle(strokeWidth, strokeAndFill);
SkPaint::Cap cap = SkPaint::Cap(random->nextULessThan(SkPaint::kCapCount));
SkPaint::Join join = SkPaint::Join(random->nextULessThan(SkPaint::kJoinCount));
SkScalar miterLimit = random->nextRangeScalar(1.f, 5.f);
- rec.setStrokeParams(cap, join, miterLimit);
+ rec->setStrokeParams(cap, join, miterLimit);
+}
+
+SkStrokeRec TestStrokeRec(SkRandom* random) {
+ SkStrokeRec::InitStyle style =
+ SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
+ SkStrokeRec rec(style);
+ randomize_stroke_rec(&rec, random);
return rec;
}
+GrStrokeInfo TestStrokeInfo(SkRandom* random) {
+ SkStrokeRec::InitStyle style =
+ SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
+ GrStrokeInfo strokeInfo(style);
+ randomize_stroke_rec(&strokeInfo, random);
+ SkPathEffect::DashInfo dashInfo;
+ dashInfo.fCount = random->nextRangeU(1, 50) * 2;
+ dashInfo.fIntervals = SkNEW_ARRAY(SkScalar, dashInfo.fCount);
+ SkScalar sum = 0;
+ for (int i = 0; i < dashInfo.fCount; i++) {
+ dashInfo.fIntervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01),
+ SkDoubleToScalar(10.0));
+ sum += dashInfo.fIntervals[i];
+ }
+ dashInfo.fPhase = random->nextRangeScalar(0, sum);
+ strokeInfo.setDashInfo(dashInfo);
+ return strokeInfo;
+}
+
};
#endif