aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkEdgeBuilder.cpp
diff options
context:
space:
mode:
authorGravatar Yuqian Li <liyuqian@google.com>2017-07-25 11:26:31 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-07-25 21:55:19 +0000
commitdf60e369a8fb83c5dafded3f2453defa423f174a (patch)
treedc5383b60c1efa6430756670e8b0618465bea857 /src/core/SkEdgeBuilder.cpp
parent3f475d948251e00a1525914469ee72e891bf436c (diff)
New analytic AA scan converter using delta (I call it DAA for now)
DAA is: 1. Much simpler than AAA. SkScan_AAAPath.cpp is about 1700 lines. SkScan_DAAPath.cpp is about 300 lines. The whole DAA CL is only about 800 lines. 2. Much faster than AAA for complicated paths. The speedup applies to GL backend (including ccpr)! Here's the frame time of 'SampleApp --slide Chart' on macbook pro: AAA-raster: 33ms DAA-raster: 21ms AAA-gl: 30ms DAA-gl: 20ms AAA-ccpr: 18ms DAA-ccpr: 12ms My linux desktop doesn't have SSE3 so the speedup is smaller (~25% for Chart). I believe that DAA is so fast that I can enable it for any paths (AAA is not enabled by default for complicated paths because it is slow; hence our older supersampling scan converter is used for stroking on Chart for AAA-xxx config.) 3. The SkCoverageDelta is suitable for threaded backend with out-of-order concurrent scan conversion as commented in the source code. Maybe we can also just send deltas to GPU. 4. Similar to most analytic path renderers, the quality is on the best ground-truth level, unless there are intersections within a pixel. The intersections look good to my eyes although theoretically that could be arbitrary far from the ground truth (see my AAA slides). 5. For simple paths, such as circle, triangle, rrect, etc., DAA is slower than AAA. But DAA is faster than our older supersampling scan converter in most cases. As those simple paths usually don't constitute the bottleneck of a picture (skp or svg), I strongly recommend use DAA. 6. DAA also heavily favors blitMask so it may work quite well with SkRasterPipeline and SkRasterPipelineBlitter. Finally, please check https://skia-review.googlesource.com/c/22420/ which accelerate DAA by specializing blitCoverageDeltas for SkARGB32_Blitter and SkARGB32_Black_Blitter. It brings a little(<5%) speedup. But I couldn't figure out how to reduce the duplicate code so I don't intend to land it. Bug: skia: Change-Id: I3b7ed6a727447922e645b1acb737a506e7c09a4c Reviewed-on: https://skia-review.googlesource.com/19666 Reviewed-by: Mike Reed <reed@google.com> Reviewed-by: Cary Clark <caryclark@google.com> Commit-Queue: Yuqian Li <liyuqian@google.com>
Diffstat (limited to 'src/core/SkEdgeBuilder.cpp')
-rw-r--r--src/core/SkEdgeBuilder.cpp84
1 files changed, 43 insertions, 41 deletions
diff --git a/src/core/SkEdgeBuilder.cpp b/src/core/SkEdgeBuilder.cpp
index 385193040b..7a02187470 100644
--- a/src/core/SkEdgeBuilder.cpp
+++ b/src/core/SkEdgeBuilder.cpp
@@ -65,7 +65,7 @@ static inline bool approximatelyEqual(SkFixed a, SkFixed b) {
SkEdgeBuilder::Combine SkEdgeBuilder::CombineVertical(
const SkAnalyticEdge* edge, SkAnalyticEdge* last) {
- SkASSERT(fAnalyticAA);
+ SkASSERT(fEdgeType == kAnalyticEdge);
if (last->fCurveCount || last->fDX || edge->fX != last->fX) {
return kNo_Combine;
}
@@ -115,12 +115,17 @@ bool SkEdgeBuilder::vertical_line(const SkEdge* edge) {
}
bool SkEdgeBuilder::vertical_line(const SkAnalyticEdge* edge) {
- SkASSERT(fAnalyticAA);
+ SkASSERT(fEdgeType == kAnalyticEdge);
return !edge->fDX && !edge->fCurveCount;
}
void SkEdgeBuilder::addLine(const SkPoint pts[]) {
- if (fAnalyticAA) {
+ if (fEdgeType == kBezier) {
+ SkLine* line = fAlloc.make<SkLine>();
+ if (line->set(pts)) {
+ fList.push(line);
+ }
+ } else if (fEdgeType == kAnalyticEdge) {
SkAnalyticEdge* edge = fAlloc.make<SkAnalyticEdge>();
if (edge->setLine(pts[0], pts[1])) {
if (vertical_line(edge) && fList.count()) {
@@ -160,7 +165,12 @@ unallocate_edge:
}
void SkEdgeBuilder::addQuad(const SkPoint pts[]) {
- if (fAnalyticAA) {
+ if (fEdgeType == kBezier) {
+ SkQuad* quad = fAlloc.make<SkQuad>();
+ if (quad->set(pts)) {
+ fList.push(quad);
+ }
+ } else if (fEdgeType == kAnalyticEdge) {
SkAnalyticQuadraticEdge* edge = fAlloc.make<SkAnalyticQuadraticEdge>();
if (edge->setQuadratic(pts)) {
fList.push(edge);
@@ -178,7 +188,12 @@ void SkEdgeBuilder::addQuad(const SkPoint pts[]) {
}
void SkEdgeBuilder::addCubic(const SkPoint pts[]) {
- if (fAnalyticAA) {
+ if (fEdgeType == kBezier) {
+ SkCubic* cubic = fAlloc.make<SkCubic>();
+ if (cubic->set(pts)) {
+ fList.push(cubic);
+ }
+ } else if (fEdgeType == kAnalyticEdge) {
SkAnalyticCubicEdge* edge = fAlloc.make<SkAnalyticCubicEdge>();
if (edge->setCubic(pts)) {
fList.push(edge);
@@ -232,7 +247,7 @@ SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkEdge* edge, SkEdge**
SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkAnalyticEdge* edge,
SkAnalyticEdge** edgePtr) {
- SkASSERT(fAnalyticAA);
+ SkASSERT(fEdgeType == kAnalyticEdge);
return !vertical_line(edge) || edgePtr <= (SkAnalyticEdge**)fEdgeList ? kNo_Combine :
CombineVertical(edge, edgePtr[-1]);
}
@@ -251,9 +266,22 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift
maxEdgeCount *= SkLineClipper::kMaxClippedLineSegments;
}
- size_t edgeSize = fAnalyticAA ? sizeof(SkAnalyticEdge) : sizeof(SkEdge);
- char* edge = fAnalyticAA ? (char*)fAlloc.makeArrayDefault<SkAnalyticEdge>(maxEdgeCount)
- : (char*)fAlloc.makeArrayDefault<SkEdge>(maxEdgeCount);
+ size_t edgeSize;
+ char* edge;
+ switch (fEdgeType) {
+ case kEdge:
+ edgeSize = sizeof(SkEdge);
+ edge = (char*)fAlloc.makeArrayDefault<SkEdge>(maxEdgeCount);
+ break;
+ case kAnalyticEdge:
+ edgeSize = sizeof(SkAnalyticEdge);
+ edge = (char*)fAlloc.makeArrayDefault<SkAnalyticEdge>(maxEdgeCount);
+ break;
+ case kBezier:
+ edgeSize = sizeof(SkLine);
+ edge = (char*)fAlloc.makeArrayDefault<SkLine>(maxEdgeCount);
+ break;
+ }
SkDEBUGCODE(char* edgeStart = edge);
char** edgePtr = fAlloc.makeArrayDefault<char*>(maxEdgeCount);
@@ -275,20 +303,7 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift
int lineCount = SkLineClipper::ClipLine(pts, clip, lines, canCullToTheRight);
SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments);
for (int i = 0; i < lineCount; i++) {
- bool setLineResult = fAnalyticAA ?
- ((SkAnalyticEdge*)edge)->setLine(lines[i], lines[i + 1]) :
- ((SkEdge*)edge)->setLine(lines[i], lines[i + 1], shiftUp);
- if (setLineResult) {
- Combine combine = fAnalyticAA ?
- checkVertical((SkAnalyticEdge*)edge, (SkAnalyticEdge**)edgePtr) :
- checkVertical((SkEdge*)edge, (SkEdge**)edgePtr);
- if (kNo_Combine == combine) {
- *edgePtr++ = edge;
- edge += edgeSize;
- } else if (kTotal_Combine == combine) {
- --edgePtr;
- }
- }
+ this->addPolyLine(lines + i, edge, edgeSize, edgePtr, shiftUp);
}
break;
}
@@ -306,20 +321,7 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift
// the corresponding line/quad/cubic verbs
break;
case SkPath::kLine_Verb: {
- bool setLineResult = fAnalyticAA ?
- ((SkAnalyticEdge*)edge)->setLine(pts[0], pts[1]) :
- ((SkEdge*)edge)->setLine(pts[0], pts[1], shiftUp);
- if (setLineResult) {
- Combine combine = fAnalyticAA ?
- checkVertical((SkAnalyticEdge*)edge, (SkAnalyticEdge**)edgePtr) :
- checkVertical((SkEdge*)edge, (SkEdge**)edgePtr);
- if (kNo_Combine == combine) {
- *edgePtr++ = edge;
- edge += edgeSize;
- } else if (kTotal_Combine == combine) {
- --edgePtr;
- }
- }
+ this->addPolyLine(pts, edge, edgeSize, edgePtr, shiftUp);
break;
}
default:
@@ -342,11 +344,11 @@ static void handle_quad(SkEdgeBuilder* builder, const SkPoint pts[3]) {
}
int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, int shiftUp,
- bool canCullToTheRight, bool analyticAA) {
+ bool canCullToTheRight, EdgeType edgeType) {
fAlloc.reset();
fList.reset();
fShiftUp = shiftUp;
- fAnalyticAA = analyticAA;
+ fEdgeType = edgeType;
if (SkPath::kLine_SegmentMask == path.getSegmentMasks()) {
return this->buildPoly(path, iclip, shiftUp, canCullToTheRight);
@@ -443,12 +445,12 @@ int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, int shiftUp,
}
int SkEdgeBuilder::build_edges(const SkPath& path, const SkIRect* shiftedClip,
- int shiftEdgesUp, bool pathContainedInClip, bool analyticAA) {
+ int shiftEdgesUp, bool pathContainedInClip, EdgeType edgeType) {
// If we're convex, then we need both edges, even the right edge is past the clip
const bool canCullToTheRight = !path.isConvex();
const SkIRect* builderClip = pathContainedInClip ? nullptr : shiftedClip;
- int count = this->build(path, builderClip, shiftEdgesUp, canCullToTheRight, analyticAA);
+ int count = this->build(path, builderClip, shiftEdgesUp, canCullToTheRight, edgeType);
SkASSERT(count >= 0);
// canCullToRight == false should imply count != 1