From: commit-bot@chromium.org Date: Thu, 20 Mar 2014 20:25:14 +0000 (+0000) Subject: Fix cull nesting assertion. X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~8576 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=520cf8b33e788268432c6314c52dfcef22e776ae;p=platform%2Fupstream%2FlibSkiaSharp.git Fix cull nesting assertion. Cull rects are in local coordinates and cannot be compared directly. No wonder it was so hard enforcing this in Blink :o This moves the validation logic into SkCanvas, using a device-space cull stack (debug build only). There are still some Blink bugs causing violations, so for now I'd like to keep this as an error message only. R=reed@google.com, robertphillips@google.com Author: fmalita@chromium.org Review URL: https://codereview.chromium.org/200923008 git-svn-id: http://skia.googlecode.com/svn/trunk@13885 2bbb7eff-a529-9590-31e7-b0007b416f81 --- diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index fa433b3..f5d4fe6 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -1063,20 +1063,13 @@ public: * is not enforced, but the information might be used to quick-reject command blocks, * so an incorrect bounding box may result in incomplete rendering. */ - void pushCull(const SkRect& cullRect) { - ++fCullCount; - this->onPushCull(cullRect); - } + void pushCull(const SkRect& cullRect); /** * Terminates the current culling block, and restores the previous one (if any). */ - void popCull() { - if (fCullCount > 0) { - --fCullCount; - this->onPopCull(); - } - } + void popCull(); + ////////////////////////////////////////////////////////////////////////// /** Get the current bounder object. @@ -1394,6 +1387,9 @@ private: }; #ifdef SK_DEBUG + // The cull stack rects are in device-space + SkTDArray fCullStack; + void validateCull(const SkIRect&); void validateClip() const; #else void validateClip() const {} diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index cd2065b..787d89d 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -1162,6 +1162,60 @@ void SkCanvas::onPopCull() { } ///////////////////////////////////////////////////////////////////////////// +#ifdef SK_DEBUG +// Ensure that cull rects are monotonically nested in device space. +void SkCanvas::validateCull(const SkIRect& devCull) { + if (fCullStack.isEmpty() + || devCull.isEmpty() + || fCullStack.top().contains(devCull)) { + return; + } + + SkDEBUGF(("Invalid cull: [%d %d %d %d] (previous cull: [%d %d %d %d])\n", + devCull.x(), devCull.y(), devCull.right(), devCull.bottom(), + fCullStack.top().x(), fCullStack.top().y(), + fCullStack.top().right(), fCullStack.top().bottom())); + +#ifdef ASSERT_NESTED_CULLING + SkDEBUGFAIL("Invalid cull."); +#endif +} +#endif + +void SkCanvas::pushCull(const SkRect& cullRect) { + ++fCullCount; + this->onPushCull(cullRect); + +#ifdef SK_DEBUG + // Map the cull rect into device space. + SkRect mappedCull; + this->getTotalMatrix().mapRect(&mappedCull, cullRect); + + // Take clipping into account. + SkIRect devClip, devCull; + mappedCull.roundOut(&devCull); + this->getClipDeviceBounds(&devClip); + if (!devCull.intersect(devClip)) { + devCull.setEmpty(); + } + + this->validateCull(devCull); + fCullStack.push(devCull); // balanced in popCull +#endif +} + +void SkCanvas::popCull() { + SkASSERT(fCullStack.count() == fCullCount); + + if (fCullCount > 0) { + --fCullCount; + this->onPopCull(); + + SkDEBUGCODE(fCullStack.pop()); + } +} + +///////////////////////////////////////////////////////////////////////////// void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index 55670ba..ce21d95 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -1559,18 +1559,6 @@ void SkPictureRecord::endCommentGroup() { // [op/size] [rect] [skip offset] static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect); void SkPictureRecord::onPushCull(const SkRect& cullRect) { - // Skip identical cull rects. - if (!fCullOffsetStack.isEmpty()) { - const SkRect& prevCull = fWriter.readTAt(fCullOffsetStack.top() - sizeof(SkRect)); - if (prevCull == cullRect) { - // Skipped culls are tracked on the stack, but they point to the previous offset. - fCullOffsetStack.push(fCullOffsetStack.top()); - return; - } - - SkASSERT(prevCull.contains(cullRect)); - } - uint32_t size = kPushCullOpSize; size_t initialOffset = this->addDraw(PUSH_CULL, &size); // PUSH_CULL's size should stay constant (used to rewind). @@ -1588,11 +1576,6 @@ void SkPictureRecord::onPopCull() { uint32_t cullSkipOffset = fCullOffsetStack.top(); fCullOffsetStack.pop(); - // Skipped push, do the same for pop. - if (!fCullOffsetStack.isEmpty() && cullSkipOffset == fCullOffsetStack.top()) { - return; - } - // Collapse empty push/pop pairs. if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) { SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);