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:
parent
1818701746
commit
ab87d7abf1
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user