coin debugging runs all tests in extended

This extends path ops concidence debugging
to find unused algorithms and determine the extent
of loops.

This verifies that all 140M tests run without error
in release and debug.

TBR=reed@google.com
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2391733002

patch from issue 2391733002 at patchset 1 (http://crrev.com/2391733002#ps1)

Change-Id: I02ca29764405c5ac3e7ca3b2621fba28dbaaffc2
Reviewed-on: https://skia-review.googlesource.com/2923
Reviewed-by: Cary Clark <caryclark@google.com>
This commit is contained in:
Cary Clark 2016-10-04 10:01:04 -04:00
parent 1818701746
commit ab87d7abf1
17 changed files with 1032 additions and 636 deletions

View File

@ -60,7 +60,7 @@ bool FixWinding(SkPath* path) {
contourHead.resetReverse();
bool writePath = false;
SkOpSpan* topSpan;
globalState.setPhase(SkOpGlobalState::kFixWinding);
globalState.setPhase(SkOpPhase::kFixWinding);
while ((topSpan = FindSortableTop(&contourHead))) {
SkOpSegment* topSegment = topSpan->segment();
SkOpContour* topContour = topSegment->contour();

View File

@ -30,6 +30,7 @@ void SkCoincidentSpans::correctOneEnd(
}
}
/* Please keep this in sync with debugCorrectEnds */
// FIXME: member pointers have fallen out of favor and can be replaced with
// an alternative approach.
// makes all span ends agree with the segment's spans that define them
@ -99,13 +100,11 @@ bool SkCoincidentSpans::extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinP
// set the range of this span
void SkCoincidentSpans::set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart,
const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd
SkDEBUGPARAMS(int id)) {
const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) {
SkASSERT(SkOpCoincidence::Ordered(coinPtTStart, oppPtTStart));
fNext = next;
this->setStarts(coinPtTStart, oppPtTStart);
this->setEnds(coinPtTEnd, oppPtTEnd);
SkDEBUGCODE(fID = id);
}
// returns true if both points are inside this
@ -293,8 +292,7 @@ void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* o
SkCoincidentSpans* coinRec = SkOpTAllocator<SkCoincidentSpans>::Allocate(
this->globalState()->allocator());
coinRec->init(SkDEBUGCODE(fGlobalState));
coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd
SkDEBUGPARAMS(fGlobalState->nextCoinID()));
coinRec->set(this->fHead, coinPtTStart, coinPtTEnd, oppPtTStart, oppPtTEnd);
fHead = coinRec;
}
@ -398,7 +396,8 @@ bool SkOpCoincidence::addEndMovedSpans(const SkOpPtT* ptT) {
coincident pair. If so, check for a new coincident span between B-end/A ptT loop
and the adjacent ptT loop.
*/
bool SkOpCoincidence::addEndMovedSpans() {
bool SkOpCoincidence::addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* span = fHead;
if (!span) {
return true;
@ -445,7 +444,8 @@ bool SkOpCoincidence::addEndMovedSpans() {
/* Please keep this in sync with debugAddExpanded */
// for each coincident pair, match the spans
// if the spans don't match, add the missing pt to the segment and loop it in the opposite span
bool SkOpCoincidence::addExpanded() {
bool SkOpCoincidence::addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* coin = this->fHead;
if (!coin) {
return true;
@ -828,7 +828,7 @@ bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
/* detects overlaps of different coincident runs on same segment */
/* does not detect overlaps for pairs without any segments in common */
// returns true if caller should loop again
bool SkOpCoincidence::addMissing(bool* added) {
bool SkOpCoincidence::addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()) {
SkCoincidentSpans* outer = fHead;
*added = false;
if (!outer) {
@ -1115,7 +1115,8 @@ bool SkOpCoincidence::contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinP
return false;
}
void SkOpCoincidence::correctEnds() {
void SkOpCoincidence::correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* coin = fHead;
if (!coin) {
return;
@ -1126,7 +1127,8 @@ void SkOpCoincidence::correctEnds() {
}
// walk span sets in parallel, moving winding from one to the other
bool SkOpCoincidence::apply() {
bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* coin = fHead;
if (!coin) {
return true;
@ -1305,41 +1307,6 @@ void SkOpCoincidence::releaseDeleted() {
this->releaseDeleted(fTop);
}
// Please keep this in sync with debugReorder()
// iterate through all coincident pairs, looking for ranges greater than 1
// if found, see if the opposite pair can match it -- which may require
// reordering the ptT pairs
bool SkOpCoincidence::reorder() {
SkCoincidentSpans* coin = fHead;
if (!coin) {
return true;
}
do {
// most commonly, concidence are one span long; check for that first
int intervals = coin->spanCount();
if (intervals <= 0) {
return false;
}
if (1 == intervals) {
#if DEBUG_COINCIDENCE_VERBOSE
SkASSERT(!coin->debugExpand(nullptr, nullptr));
#endif
continue;
}
coin->expand(); // be all that you can be
if (coin->spanCount() <= 0) {
return false;
}
// check to see if every span in coin has a mate in opp
const SkOpSpan* start = coin->coinPtTStart()->span()->upCast();
bool flipped = coin->flipped();
const SkOpSpanBase* oppStartBase = coin->oppPtTStart()->span();
const SkOpSpan* oppStart = flipped ? oppStartBase->prev() : oppStartBase->upCast();
SkDebugf("", start, oppStart);
} while ((coin = coin->next()));
return true;
}
void SkOpCoincidence::restoreHead() {
SkCoincidentSpans** headPtr = &fHead;
while (*headPtr) {
@ -1361,7 +1328,8 @@ void SkOpCoincidence::restoreHead() {
// Please keep this in sync with debugExpand()
// expand the range by checking adjacent spans for coincidence
bool SkOpCoincidence::expand() {
bool SkOpCoincidence::expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* coin = fHead;
if (!coin) {
return false;
@ -1387,7 +1355,8 @@ bool SkOpCoincidence::expand() {
return expanded;
}
bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps) const {
bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps DEBUG_COIN_DECLARE_PARAMS()) const {
DEBUG_SET_PHASE();
overlaps->fHead = overlaps->fTop = nullptr;
SkCoincidentSpans* outer = fHead;
while (outer) {
@ -1422,33 +1391,6 @@ bool SkOpCoincidence::findOverlaps(SkOpCoincidence* overlaps) const {
return true;
}
// Please keep this in sync with debugRemoveCollapsed()
bool SkOpCoincidence::removeCollapsed() {
SkCoincidentSpans* coin = fHead;
if (!coin) {
return true;
}
SkCoincidentSpans** priorPtr = &fHead;
do {
if (coin->coinPtTStart() == coin->coinPtTEnd()) {
return false;
}
if (coin->oppPtTStart() == coin->oppPtTEnd()) {
return false;
}
if (coin->coinPtTStart()->collapsed(coin->coinPtTEnd())) {
*priorPtr = coin->next();
continue;
}
if (coin->oppPtTStart()->collapsed(coin->oppPtTEnd())) {
*priorPtr = coin->next();
continue;
}
priorPtr = coin->nextPtr();
} while ((coin = coin->next()));
return true;
}
void SkOpCoincidence::fixUp(SkOpPtT* deleted, const SkOpPtT* kept) {
SkOPASSERT(deleted != kept);
if (fHead) {
@ -1495,7 +1437,8 @@ void SkOpCoincidence::fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkO
// Please keep this in sync with debugMark()
/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
bool SkOpCoincidence::mark() {
bool SkOpCoincidence::mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
DEBUG_SET_PHASE();
SkCoincidentSpans* coin = fHead;
if (!coin) {
return true;

View File

@ -31,12 +31,20 @@ public:
void correctOneEnd(const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
void (SkCoincidentSpans::* setEnd)(const SkOpPtT* ptT) );
#if DEBUG_COINCIDENCE_VERBOSE
bool debugExpand(const char* id, SkPathOpsDebug::GlitchLog* log) const;
#if DEBUG_COIN
void debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const;
void debugCorrectOneEnd(SkPathOpsDebug::GlitchLog* log,
const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
void (SkCoincidentSpans::* setEnd)(const SkOpPtT* ptT) const) const;
bool debugExpand(SkPathOpsDebug::GlitchLog* log) const;
#endif
int debugID() const {
return SkDEBUGRELEASE(fID, -1);
const char* debugID() const {
#if DEBUG_COIN
return fGlobalState->debugCoinDictEntry().fFunctionName;
#else
return nullptr;
#endif
}
void debugShow() const;
@ -69,8 +77,7 @@ public:
int spanCount() const;
void set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd
SkDEBUGPARAMS(int id));
const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd);
void setCoinPtTEnd(const SkOpPtT* ptT) {
SkOPASSERT(ptT == ptT->span()->ptT());
@ -127,7 +134,6 @@ private:
const SkOpPtT* fOppPtTStart;
const SkOpPtT* fOppPtTEnd;
SkDEBUGCODE(SkOpGlobalState* fGlobalState);
SkDEBUGCODE(int fID);
};
class SkOpCoincidence {
@ -146,19 +152,20 @@ public:
void add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
SkOpPtT* oppPtTEnd);
bool addEndMovedSpans();
bool addExpanded();
bool addMissing(bool* added);
bool addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS());
bool addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS());
bool addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS());
bool addUncommon();
bool apply();
bool apply(DEBUG_COIN_DECLARE_ONLY_PARAMS());
bool contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const;
void correctEnds();
void correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS());
#if DEBUG_COINCIDENCE_VERBOSE
void debugAddExpanded(const char* id, SkPathOpsDebug::GlitchLog* ) const;
void debugAddMissing(const char* id, SkPathOpsDebug::GlitchLog* , bool* added) const;
void debugAddOrOverlap(const char* id, SkPathOpsDebug::GlitchLog* log,
#if DEBUG_COIN
void debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log) const;
void debugAddExpanded(SkPathOpsDebug::GlitchLog* ) const;
void debugAddMissing(SkPathOpsDebug::GlitchLog* , bool* added) const;
void debugAddOrOverlap(SkPathOpsDebug::GlitchLog* log,
const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
double coinTs, double coinTe, double oppTs, double oppTe,
bool* added) const;
@ -170,20 +177,21 @@ public:
void debugCheckBetween() const;
#if DEBUG_COINCIDENCE_VERBOSE
void debugCheckValid(const char* id, SkPathOpsDebug::GlitchLog* log) const;
#if DEBUG_COIN
void debugCheckValid(SkPathOpsDebug::GlitchLog* log) const;
#endif
SkOpContour* debugContour(int id) const {
return SkDEBUGRELEASE(fGlobalState->debugContour(id), nullptr);
}
#if DEBUG_COINCIDENCE_VERBOSE
bool debugExpand(const char* id, SkPathOpsDebug::GlitchLog* ) const;
void debugMark(const char* id, SkPathOpsDebug::GlitchLog* ) const;
void debugMarkCollapsed(const char* id, SkPathOpsDebug::GlitchLog* ,
#if DEBUG_COIN
void debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const;
bool debugExpand(SkPathOpsDebug::GlitchLog* ) const;
void debugMark(SkPathOpsDebug::GlitchLog* ) const;
void debugMarkCollapsed(SkPathOpsDebug::GlitchLog* ,
const SkCoincidentSpans* coin, const SkOpPtT* test) const;
void debugMarkCollapsed(const char* id, SkPathOpsDebug::GlitchLog* , const SkOpPtT* test) const;
void debugMarkCollapsed(SkPathOpsDebug::GlitchLog* , const SkOpPtT* test) const;
#endif
const SkOpPtT* debugPtT(int id) const {
@ -194,12 +202,11 @@ public:
return SkDEBUGRELEASE(fGlobalState->debugSegment(id), nullptr);
}
#if DEBUG_COINCIDENCE_VERBOSE
void debugRemoveCollapsed(const char* id, SkPathOpsDebug::GlitchLog* ) const;
void debugReorder(const char* id, SkPathOpsDebug::GlitchLog* ) const;
void debugRelease(const char* id, SkPathOpsDebug::GlitchLog* , const SkCoincidentSpans* ,
#if DEBUG_COIN
void debugRemoveCollapsed(SkPathOpsDebug::GlitchLog* ) const;
void debugRelease(SkPathOpsDebug::GlitchLog* , const SkCoincidentSpans* ,
const SkCoincidentSpans* ) const;
void debugRelease(const char* id, SkPathOpsDebug::GlitchLog* , const SkOpSegment* ) const;
void debugRelease(SkPathOpsDebug::GlitchLog* , const SkOpSegment* ) const;
#endif
void debugShowCoincidence() const;
@ -210,10 +217,10 @@ public:
void debugValidate() const;
void dump() const;
bool edge(const SkOpPtT* , bool* start) const;
bool expand();
bool expand(DEBUG_COIN_DECLARE_ONLY_PARAMS());
bool extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart,
const SkOpPtT* oppPtTEnd);
bool findOverlaps(SkOpCoincidence* ) const;
bool findOverlaps(SkOpCoincidence* DEBUG_COIN_DECLARE_PARAMS()) const;
void fixUp(SkOpPtT* deleted, const SkOpPtT* kept);
SkOpGlobalState* globalState() {
@ -228,7 +235,7 @@ public:
return !fHead && !fTop;
}
bool mark();
bool mark(DEBUG_COIN_DECLARE_ONLY_PARAMS());
void markCollapsed(SkOpPtT* );
static bool Ordered(const SkOpPtT* coinPtTStart, const SkOpPtT* oppPtTStart) {
@ -238,8 +245,6 @@ public:
static bool Ordered(const SkOpSegment* coin, const SkOpSegment* opp);
void release(const SkOpSegment* );
void releaseDeleted();
bool removeCollapsed();
bool reorder();
private:
void add(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart,
@ -276,15 +281,19 @@ private:
bool contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const;
bool contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
const SkOpSegment* opp, double oppT) const;
#if DEBUG_COINCIDENCE_VERBOSE
void debugAddIfMissing(const char* id, SkPathOpsDebug::GlitchLog* ,
#if DEBUG_COIN
void debugAddIfMissing(SkPathOpsDebug::GlitchLog* ,
const SkCoincidentSpans* outer, const SkOpPtT* over1s,
const SkOpPtT* over1e) const;
void debugAddIfMissing(const char* id, SkPathOpsDebug::GlitchLog* ,
void debugAddIfMissing(SkPathOpsDebug::GlitchLog* ,
const SkOpPtT* over1s, const SkOpPtT* over2s,
double tStart, double tEnd,
const SkOpSegment* coinSeg, const SkOpSegment* oppSeg, bool* added,
const SkOpPtT* over1e, const SkOpPtT* over2e) const;
void debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* ,
const SkOpSpan* base, const SkOpSpanBase* testSpan) const;
void debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* ,
const SkOpPtT* ptT) const;
#endif
void fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept);
void markCollapsed(SkCoincidentSpans* head, SkOpPtT* test);

View File

@ -91,14 +91,6 @@ public:
return SkDEBUGRELEASE(fDebugIndent, 0);
}
#if DEBUG_ACTIVE_SPANS
void debugShowActiveSpans() {
SkOpSegment* segment = &fHead;
do {
segment->debugShowActiveSpans();
} while ((segment = segment->next()));
}
#endif
const SkOpAngle* debugAngle(int id) const {
return SkDEBUGRELEASE(this->globalState()->debugAngle(id), nullptr);
@ -108,16 +100,18 @@ public:
return this->globalState()->coincidence();
}
#if DEBUG_COINCIDENCE_VERBOSE
void debugCheckHealth(const char* id, SkPathOpsDebug::GlitchLog* ) const;
#if DEBUG_COIN
void debugCheckHealth(SkPathOpsDebug::GlitchLog* ) const;
#endif
SkOpContour* debugContour(int id) const {
return SkDEBUGRELEASE(this->globalState()->debugContour(id), nullptr);
}
#if DEBUG_COINCIDENCE_VERBOSE
void debugMissingCoincidence(const char* id, SkPathOpsDebug::GlitchLog* log) const;
#if DEBUG_COIN
void debugMissingCoincidence(SkPathOpsDebug::GlitchLog* log) const;
void debugMoveMultiples(SkPathOpsDebug::GlitchLog* ) const;
void debugMoveNearby(SkPathOpsDebug::GlitchLog* log) const;
#endif
const SkOpPtT* debugPtT(int id) const {
@ -128,6 +122,15 @@ public:
return SkDEBUGRELEASE(this->globalState()->debugSegment(id), nullptr);
}
#if DEBUG_ACTIVE_SPANS
void debugShowActiveSpans() {
SkOpSegment* segment = &fHead;
do {
segment->debugShowActiveSpans();
} while ((segment = segment->next()));
}
#endif
const SkOpSpanBase* debugSpan(int id) const {
return SkDEBUGRELEASE(this->globalState()->debugSpan(id), nullptr);
}
@ -235,10 +238,6 @@ public:
#endif
} else if (segment->missingCoincidence()) {
result = true;
// FIXME: trying again loops forever in issue3651_6
// The continue below is speculative -- once there's an actual case that requires it,
// add the plumbing necessary to look for another missing coincidence in the same segment
// continue; // try again in case another missing coincidence is further along
}
segment = segment->next();
} while (segment);
@ -346,8 +345,6 @@ public:
fXor = isXor;
}
SkPath::Verb simplifyCubic(SkPoint pts[4]);
void sortAngles() {
SkASSERT(fCount > 0);
SkOpSegment* segment = &fHead;

View File

@ -129,17 +129,17 @@ public:
}
void debugAddAngle(double startT, double endT);
#if DEBUG_COINCIDENCE_VERBOSE
const SkOpPtT* debugAddT(double t, const char* id, SkPathOpsDebug::GlitchLog* ) const;
#if DEBUG_COIN
const SkOpPtT* debugAddT(double t, SkPathOpsDebug::GlitchLog* ) const;
#endif
const SkOpAngle* debugAngle(int id) const;
#if DEBUG_ANGLE
void debugCheckAngleCoin() const;
#endif
#if DEBUG_COINCIDENCE_VERBOSE
void debugCheckHealth(const char* id, SkPathOpsDebug::GlitchLog* ) const;
void debugClearAll(const char* id, SkPathOpsDebug::GlitchLog* glitches) const;
void debugClearOne(const SkOpSpan* span, const char* id, SkPathOpsDebug::GlitchLog* glitches) const;
#if DEBUG_COIN
void debugCheckHealth(SkPathOpsDebug::GlitchLog* ) const;
void debugClearAll(SkPathOpsDebug::GlitchLog* glitches) const;
void debugClearOne(const SkOpSpan* span, SkPathOpsDebug::GlitchLog* glitches) const;
#endif
const SkOpCoincidence* debugCoincidence() const;
SkOpContour* debugContour(int id) const;
@ -149,10 +149,10 @@ public:
}
SkOpAngle* debugLastAngle();
#if DEBUG_COINCIDENCE_VERBOSE
void debugMissingCoincidence(const char* id, SkPathOpsDebug::GlitchLog* glitches) const;
void debugMoveMultiples(const char* id, SkPathOpsDebug::GlitchLog* glitches) const;
void debugMoveNearby(const char* id, SkPathOpsDebug::GlitchLog* glitches) const;
#if DEBUG_COIN
void debugMissingCoincidence(SkPathOpsDebug::GlitchLog* glitches) const;
void debugMoveMultiples(SkPathOpsDebug::GlitchLog* glitches) const;
void debugMoveNearby(SkPathOpsDebug::GlitchLog* glitches) const;
#endif
const SkOpPtT* debugPtT(int id) const;
void debugReset();
@ -174,7 +174,7 @@ public:
void debugSetCoinT(int, SkScalar ) const;
#endif
#if DEBUG_COINCIDENCE
#if DEBUG_COIN
static void DebugClearVisited(const SkOpSpanBase* span);
bool debugVisited() const {
@ -341,7 +341,7 @@ public:
void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkChunkAlloc*);
#if DEBUG_COINCIDENCE
#if DEBUG_COIN
void resetDebugVisited() const {
fDebugVisited = false;
}
@ -447,7 +447,7 @@ private:
int fDoneCount; // number of processed spans (zero initially)
SkPath::Verb fVerb;
bool fVisited; // used by missing coincidence check
#if DEBUG_COINCIDENCE
#if DEBUG_COIN
mutable bool fDebugVisited; // used by debug missing coincidence check
#endif
#if DEBUG_COINCIDENCE_ORDER

View File

@ -223,14 +223,14 @@ public:
return SkDEBUGRELEASE(fID, -1);
}
#if DEBUG_COINCIDENCE_VERBOSE
void debugAddOpp(const char* id, SkPathOpsDebug::GlitchLog* , const SkOpSpanBase* opp) const;
#if DEBUG_COIN
void debugAddOpp(SkPathOpsDebug::GlitchLog* , const SkOpSpanBase* opp) const;
#endif
bool debugAlignedEnd(double t, const SkPoint& pt) const;
bool debugAlignedInner() const;
const SkOpAngle* debugAngle(int id) const;
#if DEBUG_COINCIDENCE_VERBOSE
void debugCheckForCollapsedCoincidence(const char* id, SkPathOpsDebug::GlitchLog* ) const;
#if DEBUG_COIN
void debugCheckForCollapsedCoincidence(SkPathOpsDebug::GlitchLog* ) const;
#endif
const SkOpCoincidence* debugCoincidence() const;
bool debugCoinEndLoopCheck() const;
@ -238,12 +238,12 @@ public:
#ifdef SK_DEBUG
bool debugDeleted() const { return fDebugDeleted; }
#endif
#if DEBUG_COINCIDENCE_VERBOSE
void debugInsertCoinEnd(const char* id, SkPathOpsDebug::GlitchLog* ,
#if DEBUG_COIN
void debugInsertCoinEnd(SkPathOpsDebug::GlitchLog* ,
const SkOpSpanBase* ) const;
void debugMergeContained(const char* id, SkPathOpsDebug::GlitchLog* ,
void debugMergeContained(SkPathOpsDebug::GlitchLog* ,
const SkPathOpsBounds& bounds, bool* deleted) const;
void debugMergeMatches(const char* id, SkPathOpsDebug::GlitchLog* log,
void debugMergeMatches(SkPathOpsDebug::GlitchLog* log,
const SkOpSpanBase* opp) const;
#endif
const SkOpPtT* debugPtT(int id) const;
@ -454,10 +454,10 @@ public:
}
bool debugCoinLoopCheck() const;
#if DEBUG_COINCIDENCE_VERBOSE
void debugInsertCoincidence(const char* , SkPathOpsDebug::GlitchLog* , const SkOpSpan* ) const;
void debugInsertCoincidence(const char* , SkPathOpsDebug::GlitchLog* ,
const SkOpSegment* , bool flipped) const;
#if DEBUG_COIN
void debugInsertCoincidence(SkPathOpsDebug::GlitchLog* , const SkOpSpan* ) const;
void debugInsertCoincidence(SkPathOpsDebug::GlitchLog* ,
const SkOpSegment* , bool flipped, bool ordered) const;
#endif
void dumpCoin() const;
bool dumpSpan() const;

View File

@ -198,14 +198,16 @@ bool SortContourList(SkOpContourHead** contourList, bool evenOdd, bool oppEvenOd
return true;
}
static void calcAngles(SkOpContourHead* contourList) {
static void calc_angles(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARAMS()) {
DEBUG_STATIC_SET_PHASE(contourList);
SkOpContour* contour = contourList;
do {
contour->calcAngles();
} while ((contour = contour->next()));
}
static bool missingCoincidence(SkOpContourHead* contourList) {
static bool missing_coincidence(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARAMS()) {
DEBUG_STATIC_SET_PHASE(contourList);
SkOpContour* contour = contourList;
bool result = false;
do {
@ -214,7 +216,8 @@ static bool missingCoincidence(SkOpContourHead* contourList) {
return result;
}
static bool moveMultiples(SkOpContourHead* contourList) {
static bool move_multiples(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARAMS()) {
DEBUG_STATIC_SET_PHASE(contourList);
SkOpContour* contour = contourList;
do {
if (!contour->moveMultiples()) {
@ -224,14 +227,15 @@ static bool moveMultiples(SkOpContourHead* contourList) {
return true;
}
static void moveNearby(SkOpContourHead* contourList) {
static void move_nearby(SkOpContourHead* contourList DEBUG_COIN_DECLARE_PARAMS()) {
DEBUG_STATIC_SET_PHASE(contourList);
SkOpContour* contour = contourList;
do {
contour->moveNearby();
} while ((contour = contour->next()));
}
static void sortAngles(SkOpContourHead* contourList) {
static void sort_angles(SkOpContourHead* contourList) {
SkOpContour* contour = contourList;
do {
contour->sortAngles();
@ -240,43 +244,27 @@ static void sortAngles(SkOpContourHead* contourList) {
bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence) {
SkOpGlobalState* globalState = contourList->globalState();
DEBUG_COINCIDENCE_HEALTH(contourList, "start");
#if DEBUG_VALIDATE
globalState->setPhase(SkOpGlobalState::kIntersecting);
#endif
// match up points within the coincident runs
if (!coincidence->addExpanded()) {
if (!coincidence->addExpanded(DEBUG_PHASE_ONLY_PARAMS(kIntersecting))) {
return false;
}
DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded");
#if DEBUG_VALIDATE
globalState->setPhase(SkOpGlobalState::kWalking);
#endif
// combine t values when multiple intersections occur on some segments but not others
if (!moveMultiples(contourList)) {
if (!move_multiples(contourList DEBUG_PHASE_PARAMS(kWalking))) {
return false;
}
DEBUG_COINCIDENCE_HEALTH(contourList, "moveMultiples");
// move t values and points together to eliminate small/tiny gaps
(void) moveNearby(contourList);
DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby");
#if DEBUG_VALIDATE
globalState->setPhase(SkOpGlobalState::kIntersecting);
#endif
move_nearby(contourList DEBUG_COIN_PARAMS());
// add coincidence formed by pairing on curve points and endpoints
coincidence->correctEnds();
if (!coincidence->addEndMovedSpans()) {
coincidence->correctEnds(DEBUG_PHASE_ONLY_PARAMS(kIntersecting));
if (!coincidence->addEndMovedSpans(DEBUG_COIN_ONLY_PARAMS())) {
return false;
}
DEBUG_COINCIDENCE_HEALTH(contourList, "addEndMovedSpans");
const int SAFETY_COUNT = 100; // FIXME: tune
int safetyHatch = SAFETY_COUNT;
// look for coincidence present in A-B and A-C but missing in B-C
do {
bool added;
if (!coincidence->addMissing(&added)) {
if (!coincidence->addMissing(&added DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) {
return false;
}
if (!added) {
@ -286,98 +274,70 @@ bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidenc
SkASSERT(globalState->debugSkipAssert());
return false;
}
DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing");
moveNearby(contourList);
DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby");
move_nearby(contourList DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch - 1));
} while (true);
DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing2");
// FIXME: only call this if addMissing modified something when returning false
moveNearby(contourList);
DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby2");
move_nearby(contourList DEBUG_COIN_PARAMS());
// check to see if, loosely, coincident ranges may be expanded
if (coincidence->expand()) {
DEBUG_COINCIDENCE_HEALTH(contourList, "expand1");
if (coincidence->expand(DEBUG_COIN_ONLY_PARAMS())) {
bool added;
if (!coincidence->addMissing(&added)) {
if (!coincidence->addMissing(&added DEBUG_COIN_PARAMS())) {
return false;
}
DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing2");
if (!coincidence->addExpanded()) {
if (!coincidence->addExpanded(DEBUG_COIN_ONLY_PARAMS())) {
return false;
}
DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded2");
if (!moveMultiples(contourList)) {
if (!move_multiples(contourList DEBUG_COIN_PARAMS())) {
return false;
}
DEBUG_COINCIDENCE_HEALTH(contourList, "moveMultiples2");
moveNearby(contourList);
move_nearby(contourList DEBUG_COIN_PARAMS());
}
#if DEBUG_VALIDATE
globalState->setPhase(SkOpGlobalState::kWalking);
#endif
DEBUG_COINCIDENCE_HEALTH(contourList, "expand2");
// the expanded ranges may not align -- add the missing spans
if (!coincidence->addExpanded()) {
if (!coincidence->addExpanded(DEBUG_PHASE_ONLY_PARAMS(kWalking))) {
return false;
}
DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded3");
coincidence->correctEnds();
if (!coincidence->mark()) { // mark spans of coincident segments as coincident
coincidence->correctEnds(DEBUG_COIN_ONLY_PARAMS());
// mark spans of coincident segments as coincident
if (!coincidence->mark(DEBUG_COIN_ONLY_PARAMS())) {
return false;
}
DEBUG_COINCIDENCE_HEALTH(contourList, "mark1");
// look for coincidence lines and curves undetected by intersection
if (missingCoincidence(contourList)) {
#if DEBUG_VALIDATE
globalState->setPhase(SkOpGlobalState::kIntersecting);
#endif
DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence1");
(void) coincidence->expand();
DEBUG_COINCIDENCE_HEALTH(contourList, "expand3");
if (!coincidence->addExpanded()) {
if (missing_coincidence(contourList DEBUG_COIN_PARAMS())) {
(void) coincidence->expand(DEBUG_PHASE_ONLY_PARAMS(kIntersecting));
if (!coincidence->addExpanded(DEBUG_COIN_ONLY_PARAMS())) {
return false;
}
#if DEBUG_VALIDATE
globalState->setPhase(SkOpGlobalState::kWalking);
#endif
DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded3");
if (!coincidence->mark()) {
if (!coincidence->mark(DEBUG_PHASE_ONLY_PARAMS(kWalking))) {
return false;
}
} else {
DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence2");
(void) coincidence->expand();
(void) coincidence->expand(DEBUG_COIN_ONLY_PARAMS());
}
DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence3");
(void) coincidence->expand(DEBUG_COIN_ONLY_PARAMS());
(void) coincidence->expand();
#if 0 // under development
// coincident runs may cross two or more spans, but the opposite spans may be out of order
if (!coincidence->reorder()) {
return false;
}
#endif
DEBUG_COINCIDENCE_HEALTH(contourList, "coincidence.reorder");
SkOpCoincidence overlaps(globalState);
safetyHatch = SAFETY_COUNT;
do {
SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps;
if (!pairs->apply()) { // adjust the winding value to account for coincident edges
// adjust the winding value to account for coincident edges
if (!pairs->apply(DEBUG_ITER_ONLY_PARAMS(SAFETY_COUNT - safetyHatch))) {
return false;
}
DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->apply");
// For each coincident pair that overlaps another, when the receivers (the 1st of the pair)
// are different, construct a new pair to resolve their mutual span
if (!pairs->findOverlaps(&overlaps)) {
if (!pairs->findOverlaps(&overlaps DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) {
return false;
}
if (!--safetyHatch) {
SkASSERT(globalState->debugSkipAssert());
return false;
}
DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->findOverlaps");
} while (!overlaps.isEmpty());
calcAngles(contourList);
sortAngles(contourList);
calc_angles(contourList DEBUG_COIN_PARAMS());
sort_angles(contourList);
if (globalState->angleCoincidence()) {
(void) missingCoincidence(contourList);
if (!coincidence->apply()) {
(void) missing_coincidence(contourList DEBUG_COIN_PARAMS());
if (!coincidence->apply(DEBUG_COIN_ONLY_PARAMS())) {
return false;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,9 @@
#include <stdlib.h>
#include <stdio.h>
enum class SkOpPhase : char;
class SkOpContourHead;
#ifdef SK_RELEASE
#define FORCE_RELEASE 1
#else
@ -48,9 +51,10 @@
#define DEBUG_ALIGNMENT 0
#define DEBUG_ANGLE 0
#define DEBUG_ASSEMBLE 0
#define DEBUG_COINCIDENCE 0
#define DEBUG_COINCIDENCE_ORDER 0
#define DEBUG_COINCIDENCE_VERBOSE 0
#define DEBUG_COINCIDENCE 0 // sanity checking
#define DEBUG_COINCIDENCE_DUMP 0 // accumulate and dump which algorithms fired
#define DEBUG_COINCIDENCE_ORDER 0 // for well behaved curves, check if pairs match up in t-order
#define DEBUG_COINCIDENCE_VERBOSE 0 // usually whether the next function generates coincidence
#define DEBUG_CUBIC_BINARY_SEARCH 0
#define DEBUG_CUBIC_SPLIT 0
#define DEBUG_DUMP_SEGMENTS 0
@ -78,8 +82,9 @@
#define DEBUG_ANGLE 1
#define DEBUG_ASSEMBLE 1
#define DEBUG_COINCIDENCE 01
#define DEBUG_COINCIDENCE_DUMP 0
#define DEBUG_COINCIDENCE_ORDER 0 // tight arc quads may generate out-of-order coincdence spans
#define DEBUG_COINCIDENCE_VERBOSE 0
#define DEBUG_COINCIDENCE_VERBOSE 01
#define DEBUG_CUBIC_BINARY_SEARCH 0
#define DEBUG_CUBIC_SPLIT 1
#define DEBUG_DUMP_SEGMENTS 1
@ -127,11 +132,65 @@
extern int gDumpTSectNum;
#endif
#if DEBUG_COINCIDENCE
#define DEBUG_COINCIDENCE_HEALTH(contourList, id) \
SkPathOpsDebug::CheckHealth(contourList, id)
#if DEBUG_COINCIDENCE || DEBUG_COINCIDENCE_DUMP
#define DEBUG_COIN 1
#else
#define DEBUG_COINCIDENCE_HEALTH(contourList, id)
#define DEBUG_COIN 0
#endif
#if DEBUG_COIN
#define DEBUG_COIN_DECLARE_ONLY_PARAMS() \
int lineNo, SkOpPhase phase, int iteration
#define DEBUG_COIN_DECLARE_PARAMS() \
, DEBUG_COIN_DECLARE_ONLY_PARAMS()
#define DEBUG_COIN_ONLY_PARAMS() \
__LINE__, SkOpPhase::kNoChange, 0
#define DEBUG_COIN_PARAMS() \
, DEBUG_COIN_ONLY_PARAMS()
#define DEBUG_ITER_ONLY_PARAMS(iteration) \
__LINE__, SkOpPhase::kNoChange, iteration
#define DEBUG_ITER_PARAMS(iteration) \
, DEBUG_ITER_ONLY_PARAMS(iteration)
#define DEBUG_PHASE_ONLY_PARAMS(phase) \
__LINE__, SkOpPhase::phase, 0
#define DEBUG_PHASE_PARAMS(phase) \
, DEBUG_PHASE_ONLY_PARAMS(phase)
#define DEBUG_SET_PHASE() \
this->globalState()->debugSetPhase(__func__, lineNo, phase, iteration)
#define DEBUG_STATIC_SET_PHASE(obj) \
obj->globalState()->debugSetPhase(__func__, lineNo, phase, iteration)
#elif DEBUG_VALIDATE
#define DEBUG_COIN_DECLARE_ONLY_PARAMS() \
SkOpPhase phase
#define DEBUG_COIN_DECLARE_PARAMS() \
, DEBUG_COIN_DECLARE_ONLY_PARAMS()
#define DEBUG_COIN_ONLY_PARAMS() \
SkOpPhase::kNoChange
#define DEBUG_COIN_PARAMS() \
, DEBUG_COIN_ONLY_PARAMS()
#define DEBUG_ITER_ONLY_PARAMS(iteration) \
SkOpPhase::kNoChange
#define DEBUG_ITER_PARAMS(iteration) \
, DEBUG_ITER_ONLY_PARAMS(iteration)
#define DEBUG_PHASE_ONLY_PARAMS(phase) \
SkOpPhase::phase
#define DEBUG_PHASE_PARAMS(phase) \
, DEBUG_PHASE_ONLY_PARAMS(phase)
#define DEBUG_SET_PHASE() \
this->globalState()->debugSetPhase(phase)
#define DEBUG_STATIC_SET_PHASE(obj) \
obj->globalState()->debugSetPhase(phase)
#else
#define DEBUG_COIN_DECLARE_ONLY_PARAMS()
#define DEBUG_COIN_DECLARE_PARAMS()
#define DEBUG_COIN_ONLY_PARAMS()
#define DEBUG_COIN_PARAMS()
#define DEBUG_ITER_ONLY_PARAMS(iteration)
#define DEBUG_ITER_PARAMS(iteration)
#define DEBUG_PHASE_ONLY_PARAMS(phase)
#define DEBUG_PHASE_PARAMS(phase)
#define DEBUG_SET_PHASE()
#define DEBUG_STATIC_SET_PHASE(obj)
#endif
#define CUBIC_DEBUG_STR "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}"
@ -173,8 +232,71 @@
class SkPathOpsDebug {
public:
static const char* kLVerbStr[];
#if DEBUG_COIN
struct GlitchLog;
enum GlitchType {
kUninitialized_Glitch,
kAddCorruptCoin_Glitch,
kAddExpandedCoin_Glitch,
kAddExpandedFail_Glitch,
kAddIfCollapsed_Glitch,
kAddIfMissingCoin_Glitch,
kAddMissingCoin_Glitch,
kAddMissingExtend_Glitch,
kAddOrOverlap_Glitch,
kCollapsedCoin_Glitch,
kCollapsedDone_Glitch,
kCollapsedOppValue_Glitch,
kCollapsedSpan_Glitch,
kCollapsedWindValue_Glitch,
kCorrectEnd_Glitch,
kDeletedCoin_Glitch,
kExpandCoin_Glitch,
kFail_Glitch,
kMarkCoinEnd_Glitch,
kMarkCoinInsert_Glitch,
kMarkCoinMissing_Glitch,
kMarkCoinStart_Glitch,
kMergeContained_Glitch,
kMergeMatches_Glitch,
kMissingCoin_Glitch,
kMissingDone_Glitch,
kMissingIntersection_Glitch,
kMoveMultiple_Glitch,
kMoveNearbyClearAll_Glitch,
kMoveNearbyClearAll2_Glitch,
kMoveNearbyMerge_Glitch,
kMoveNearbyMergeFinal_Glitch,
kMoveNearbyRelease_Glitch,
kMoveNearbyReleaseFinal_Glitch,
kReleasedSpan_Glitch,
kReturnFalse_Glitch,
kUnaligned_Glitch,
kUnalignedHead_Glitch,
kUnalignedTail_Glitch,
};
struct CoinDictEntry {
int fIteration;
int fLineNumber;
GlitchType fGlitchType;
const char* fFunctionName;
};
struct CoinDict {
void add(const CoinDictEntry& key);
void add(const CoinDict& dict);
void dump(const char* str, bool visitCheck) const;
SkTDArray<CoinDictEntry> fDict;
};
static CoinDict gCoinSumChangedDict;
static CoinDict gCoinSumVisitedDict;
static CoinDict gCoinVistedDict;
#endif
#if defined(SK_DEBUG) || !FORCE_RELEASE
static int gContourID;
static int gSegmentID;
@ -189,7 +311,6 @@ public:
static const char* kPathOpStr[];
#endif
static void CoincidentHealth(class SkOpContourHead* contourList, const char* id);
static void MathematicaIze(char* str, size_t bufferSize);
static bool ValidWind(int winding);
static void WindingPrintf(int winding);
@ -209,7 +330,7 @@ public:
static bool ChaseContains(const SkTDArray<class SkOpSpanBase*>& , const class SkOpSpanBase* );
static void CheckHealth(class SkOpContourHead* contourList, const char* id);
static void CheckHealth(class SkOpContourHead* contourList);
static const class SkOpAngle* DebugAngleAngle(const class SkOpAngle*, int id);
static class SkOpContour* DebugAngleContour(class SkOpAngle*, int id);
@ -246,6 +367,11 @@ public:
static const class SkOpPtT* DebugSpanPtT(const class SkOpSpanBase*, int id);
static const class SkOpSegment* DebugSpanSegment(const class SkOpSpanBase*, int id);
static const class SkOpSpanBase* DebugSpanSpan(const class SkOpSpanBase*, int id);
#if DEBUG_COIN
static void DumpCoinDict();
static void DumpGlitchType(GlitchType );
#endif
};
struct SkDQuad;

View File

@ -242,7 +242,8 @@ static void dump_op(const SkPath& one, const SkPath& two, SkPathOp op) {
SK_DECLARE_STATIC_MUTEX(debugWorstLoop);
SkOpGlobalState debugWorstState(nullptr, nullptr SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr));
SkOpGlobalState debugWorstState(nullptr, nullptr SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr)
SkDEBUGPARAMS(nullptr));
void ReportPathOpsDebugging() {
debugWorstState.debugLoopReport();
@ -315,9 +316,13 @@ bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result
;
} while ((current = current->next()));
#if DEBUG_VALIDATE
globalState.setPhase(SkOpGlobalState::kWalking);
globalState.setPhase(SkOpPhase::kWalking);
#endif
if (!HandleCoincidence(contourList, &coincidence)) {
bool success = HandleCoincidence(contourList, &coincidence);
#if DEBUG_COIN
globalState.debugAddToGlobalCoinDicts();
#endif
if (!success) {
return false;
}
#if DEBUG_ALIGNMENT

View File

@ -203,9 +203,13 @@ bool SimplifyDebug(const SkPath& path, SkPath* result
&& (next = next->next()));
} while ((current = current->next()));
#if DEBUG_VALIDATE
globalState.setPhase(SkOpGlobalState::kWalking);
globalState.setPhase(SkOpPhase::kWalking);
#endif
if (!HandleCoincidence(contourList, &coincidence)) {
bool success = HandleCoincidence(contourList, &coincidence);
#if DEBUG_COIN
globalState.debugAddToGlobalCoinDicts();
#endif
if (!success) {
return false;
}
#if DEBUG_DUMP_ALIGNMENT

View File

@ -234,16 +234,19 @@ SkOpGlobalState::SkOpGlobalState(SkOpContourHead* head,
, fNested(0)
, fWindingFailed(false)
, fAngleCoincidence(false)
, fPhase(kIntersecting)
, fPhase(SkOpPhase::kIntersecting)
SkDEBUGPARAMS(fDebugTestName(testName))
SkDEBUGPARAMS(fAngleID(0))
SkDEBUGPARAMS(fCoinID(0))
SkDEBUGPARAMS(fContourID(0))
SkDEBUGPARAMS(fPtTID(0))
SkDEBUGPARAMS(fSegmentID(0))
SkDEBUGPARAMS(fSpanID(0))
SkDEBUGPARAMS(fDebugSkipAssert(debugSkipAssert)) {
SkDEBUGPARAMS(fSpanID(0))
SkDEBUGPARAMS(fDebugSkipAssert(debugSkipAssert)) {
#if DEBUG_T_SECT_LOOP_COUNT
debugResetLoopCounts();
#endif
#if DEBUG_COIN
fPreviousFuncName = nullptr;
#endif
}

View File

@ -29,18 +29,19 @@ class SkOpContourHead;
class SkIntersections;
class SkIntersectionHelper;
enum class SkOpPhase : char {
kNoChange,
kIntersecting,
kWalking,
kFixWinding,
};
class SkOpGlobalState {
public:
SkOpGlobalState(SkOpContourHead* head,
SkChunkAlloc* allocator SkDEBUGPARAMS(bool debugSkipAssert)
SkDEBUGPARAMS(const char* testName));
enum Phase {
kIntersecting,
kWalking,
kFixWinding,
};
enum {
kMaxWindingTries = 10
};
@ -98,6 +99,20 @@ public:
bool debugCheckHealth() const { return fDebugCheckHealth; }
#endif
#if DEBUG_VALIDATE || DEBUG_COIN
void debugSetPhase(const char* funcName DEBUG_COIN_DECLARE_PARAMS()) const;
#endif
#if DEBUG_COIN
void debugAddToCoinChangedDict();
void debugAddToGlobalCoinDicts();
SkPathOpsDebug::CoinDict* debugCoinChangedDict() { return &fCoinChangedDict; }
const SkPathOpsDebug::CoinDictEntry& debugCoinDictEntry() const { return fCoinDictEntry; }
static void DumpCoinDict();
#endif
int nested() const {
return fNested;
}
@ -128,7 +143,7 @@ public:
}
#endif
Phase phase() const {
SkOpPhase phase() const {
return fPhase;
}
@ -152,7 +167,10 @@ public:
fContourHead = contourHead;
}
void setPhase(Phase phase) {
void setPhase(SkOpPhase phase) {
if (SkOpPhase::kNoChange == phase) {
return;
}
SkASSERT(fPhase != phase);
fPhase = phase;
}
@ -174,9 +192,10 @@ private:
bool fAllocatedOpSpan;
bool fWindingFailed;
bool fAngleCoincidence;
Phase fPhase;
SkOpPhase fPhase;
#ifdef SK_DEBUG
const char* fDebugTestName;
void* fDebugReporter;
int fAngleID;
int fCoinID;
int fContourID;
@ -191,6 +210,12 @@ private:
SkPoint fDebugWorstPts[24];
float fDebugWorstWeight[6];
#endif
#if DEBUG_COIN
SkPathOpsDebug::CoinDict fCoinChangedDict;
SkPathOpsDebug::CoinDict fCoinVisitedDict;
SkPathOpsDebug::CoinDictEntry fCoinDictEntry;
const char* fPreviousFuncName;
#endif
#if DEBUG_COINCIDENCE
bool fDebugCheckHealth;
#endif

View File

@ -346,7 +346,7 @@ bool SkOpSpan::sortableTop(SkOpContour* contourHead) {
#endif
}
if (sumSet) {
if (this->globalState()->phase() == SkOpGlobalState::kFixWinding) {
if (this->globalState()->phase() == SkOpPhase::kFixWinding) {
hitSegment->contour()->setCcw(ccw);
} else {
(void) hitSegment->markAndChaseWinding(span, span->next(), windSum, oppSum, nullptr);

View File

@ -330,6 +330,26 @@ const SkOpSpanBase* SkPathOpsDebug::DebugSpanSpan(const SkOpSpanBase* span, int
return span->debugSpan(id);
}
#if DEBUG_COIN
void SkPathOpsDebug::DumpCoinDict() {
gCoinSumChangedDict.dump("unused coin algorithm", false);
gCoinSumVisitedDict.dump("visited coin function", true);
}
void SkPathOpsDebug::CoinDict::dump(const char* str, bool visitCheck) const {
int count = fDict.count();
for (int index = 0; index < count; ++index) {
const auto& entry = fDict[index];
if (visitCheck || entry.fGlitchType == kUninitialized_Glitch) {
SkDebugf("%s %s : line %d iteration %d", str, entry.fFunctionName,
entry.fLineNumber, entry.fIteration);
DumpGlitchType(entry.fGlitchType);
SkDebugf("\n");
}
}
}
#endif
void SkOpContour::dumpContours() const {
SkOpContour* contour = this->globalState()->contourHead();
do {

View File

@ -43,6 +43,7 @@ public:
virtual void reportFailed(const skiatest::Failure&) = 0;
virtual bool allowExtendedTest() const;
virtual bool verbose() const;
virtual void* stats() const { return nullptr; }
};
#define REPORT_FAILURE(reporter, cond, message) \

View File

@ -12,6 +12,7 @@
#include "SkCommonFlags.h"
#include "SkGraphics.h"
#include "SkOSFile.h"
#include "SkPathOpsDebug.h"
#include "SkTArray.h"
#include "SkTaskGroup.h"
#include "SkTemplates.h"
@ -27,6 +28,9 @@ using namespace skiatest;
using namespace sk_gpu_test;
DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
#if DEBUG_COIN
DEFINE_bool2(coinTest, c, false, "detect unused coincidence algorithms.");
#endif
// need to explicitly declare this, or we get some weird infinite loop llist
template TestRegistry* TestRegistry::gHead;
@ -82,7 +86,7 @@ public:
void operator()() {
struct TestReporter : public skiatest::Reporter {
public:
TestReporter() : fError(false), fTestCount(0) {}
TestReporter() : fError(false), fTestCount(0), fStats(nullptr) {}
void bumpTestCount() override { ++fTestCount; }
bool allowExtendedTest() const override {
return FLAGS_extendedTest;
@ -92,6 +96,8 @@ public:
SkDebugf("\nFAILED: %s", failure.toString().c_str());
fError = true;
}
void* stats() { return fStats; }
void* fStats;
bool fError;
int fTestCount;
} reporter;
@ -219,6 +225,12 @@ int test_main() {
}
SkDebugf("\n");
#if DEBUG_COIN
if (FLAGS_coinTest) {
SkPathOpsDebug::DumpCoinDict();
}
#endif
return (status.failCount() == 0) ? 0 : 1;
}