combine vertical overlapping edges

Paths outside clips, and sometimes paths inside clips, devolve
to multiple adjacent or overlapping vertical edges. Combine
these edges when possible to reduce the overall edge count.

R=reed@google.com
BUG=573166
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1654433002

Review URL: https://codereview.chromium.org/1654433002
This commit is contained in:
caryclark 2016-01-30 14:07:20 -08:00 committed by Commit bot
parent 02a6bfaaaa
commit afd25f703d
2 changed files with 85 additions and 2 deletions

View File

@ -22,11 +22,70 @@ SkEdgeBuilder::SkEdgeBuilder() : fAlloc(16*1024) {
fEdgeList = nullptr;
}
SkEdgeBuilder::Combine SkEdgeBuilder::CombineVertical(const SkEdge* edge, SkEdge* last) {
if (last->fCurveCount || last->fDX || edge->fX != last->fX) {
return kNo_Combine;
}
if (edge->fWinding == last->fWinding) {
if (edge->fLastY + 1 == last->fFirstY) {
last->fFirstY = edge->fFirstY;
return kPartial_Combine;
}
if (edge->fFirstY == last->fLastY + 1) {
last->fLastY = edge->fLastY;
return kPartial_Combine;
}
return kNo_Combine;
}
if (edge->fFirstY == last->fFirstY) {
if (edge->fLastY == last->fLastY) {
return kTotal_Combine;
}
if (edge->fLastY < last->fLastY) {
last->fFirstY = edge->fLastY + 1;
return kPartial_Combine;
}
last->fFirstY = last->fLastY + 1;
last->fLastY = edge->fLastY;
last->fWinding = edge->fWinding;
return kPartial_Combine;
}
if (edge->fLastY == last->fLastY) {
if (edge->fFirstY > last->fFirstY) {
last->fLastY = edge->fFirstY - 1;
return kPartial_Combine;
}
last->fLastY = last->fFirstY - 1;
last->fFirstY = edge->fFirstY;
last->fWinding = edge->fWinding;
return kPartial_Combine;
}
return kNo_Combine;
}
static bool vertical_line(const SkEdge* edge) {
#ifdef SK_SUPPORT_LEGACY_VERTICAL_EDGE // this disables combining vertical overlapping edges
return false;
#endif
return !edge->fDX && !edge->fCurveCount;
}
void SkEdgeBuilder::addLine(const SkPoint pts[]) {
SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc);
if (edge->setLine(pts[0], pts[1], fShiftUp)) {
if (vertical_line(edge) && fList.count()) {
Combine combine = CombineVertical(edge, *(fList.end() - 1));
if (kNo_Combine != combine) {
if (kTotal_Combine == combine) {
fList.pop();
}
goto unallocate_edge;
}
}
fList.push(edge);
} else {
unallocate_edge:
;
// TODO: unallocate edge from storage...
}
}
@ -79,6 +138,11 @@ static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) {
SkIntToScalar(src.fBottom >> shift));
}
SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkEdge* edge, SkEdge** edgePtr) {
return !vertical_line(edge) || edgePtr <= fEdgeList ? kNo_Combine :
CombineVertical(edge, edgePtr[-1]);
}
int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shiftUp,
bool canCullToTheRight) {
SkPath::Iter iter(path, true);
@ -119,7 +183,12 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift
SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments);
for (int i = 0; i < lineCount; i++) {
if (edge->setLine(lines[i], lines[i + 1], shiftUp)) {
*edgePtr++ = edge++;
Combine combine = checkVertical(edge, edgePtr);
if (kNo_Combine == combine) {
*edgePtr++ = edge++;
} else if (kTotal_Combine == combine) {
--edgePtr;
}
}
}
break;
@ -139,7 +208,12 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift
break;
case SkPath::kLine_Verb:
if (edge->setLine(pts[0], pts[1], shiftUp)) {
*edgePtr++ = edge++;
Combine combine = checkVertical(edge, edgePtr);
if (kNo_Combine == combine) {
*edgePtr++ = edge++;
} else if (kTotal_Combine == combine) {
--edgePtr;
}
}
break;
default:

View File

@ -27,6 +27,15 @@ public:
SkEdge** edgeList() { return fEdgeList; }
private:
enum Combine {
kNo_Combine,
kPartial_Combine,
kTotal_Combine
};
static Combine CombineVertical(const SkEdge* edge, SkEdge* last);
Combine checkVertical(const SkEdge* edge, SkEdge** edgePtr);
SkChunkAlloc fAlloc;
SkTDArray<SkEdge*> fList;