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
This commit is contained in:
commit-bot@chromium.org 2014-03-20 20:25:14 +00:00
Родитель 933e65d914
Коммит 520cf8b33e
3 изменённых файлов: 60 добавлений и 27 удалений

Просмотреть файл

@ -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<SkIRect> fCullStack;
void validateCull(const SkIRect&);
void validateClip() const;
#else
void validateClip() const {}

Просмотреть файл

@ -1161,6 +1161,60 @@ void SkCanvas::onPopCull() {
// do nothing. Subclasses may do something
}
/////////////////////////////////////////////////////////////////////////////
#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,

Просмотреть файл

@ -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<SkRect>(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);