Counterproposal for skirting the BBH when the query fully contains the picture.
BUG=skia:
R=reed@google.com, robertphillips@google.com, mtklein@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/485703002
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index 7af955a..8825123 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -197,12 +197,18 @@
SkASSERT(NULL != canvas);
SkASSERT(NULL != fData.get() || NULL != fRecord.get());
+ // If the query contains the whole picture, don't bother with the BBH.
+ SkRect clipBounds = { 0, 0, 0, 0 };
+ (void)canvas->getClipBounds(&clipBounds);
+ const bool useBBH = !clipBounds.contains(SkRect::MakeWH(this->width(), this->height()));
+
if (NULL != fData.get()) {
SkPicturePlayback playback(this);
+ playback.setUseBBH(useBBH);
playback.draw(canvas, callback);
}
if (NULL != fRecord.get()) {
- SkRecordDraw(*fRecord, canvas, fBBH.get(), callback);
+ SkRecordDraw(*fRecord, canvas, useBBH ? fBBH.get() : NULL, callback);
}
}
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index bc5e7eb..fda8488 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -17,13 +17,15 @@
if (NULL != bbh) {
// Draw only ops that affect pixels in the canvas's current clip.
SkIRect query;
-#if 1 // TODO: Why is this the right way to make the query? I'd think it'd be the else branch.
- SkRect clipBounds;
- canvas->getClipBounds(&clipBounds);
+
+ // The SkRecord and BBH were recorded in identity space. This canvas
+ // is not necessarily in that same space. getClipBounds() returns us
+ // this canvas' clip bounds transformed back into identity space, which
+ // lets us query the BBH.
+ SkRect clipBounds = { 0, 0, 0, 0 };
+ (void)canvas->getClipBounds(&clipBounds);
clipBounds.roundOut(&query);
-#else
- canvas->getClipDeviceBounds(&query);
-#endif
+
SkTDArray<void*> ops;
bbh->search(query, &ops);
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index b7e4bb6..61cc502 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
+#include "SkBBoxHierarchy.h"
#include "SkBlurImageFilter.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
@@ -662,7 +663,7 @@
}
#ifdef SK_DEBUG
-// Ensure that deleting an empty SkPicture does not assert. Asserts only fire
+// Ensure that deleting an empty SkPicture does not assert. Asserts only fire
// in debug mode, so only run in debug mode.
static void test_deleting_empty_picture() {
SkPictureRecorder recorder;
@@ -1716,3 +1717,49 @@
REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
}
+
+struct CountingBBH : public SkBBoxHierarchy {
+ mutable int searchCalls;
+
+ CountingBBH() : searchCalls(0) {}
+
+ virtual void search(const SkIRect& query, SkTDArray<void*>* results) const {
+ this->searchCalls++;
+ }
+
+ // All other methods unimplemented.
+ virtual void insert(void* data, const SkIRect& bounds, bool defer) {}
+ virtual void flushDeferredInserts() {}
+ virtual void clear() {}
+ virtual int getCount() const { return 0; }
+ virtual int getDepth() const { return 0; }
+ virtual void rewindInserts() {}
+};
+
+class SpoonFedBBHFactory : public SkBBHFactory {
+public:
+ explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
+ virtual SkBBoxHierarchy* operator()(int width, int height) const {
+ return SkRef(fBBH);
+ }
+private:
+ SkBBoxHierarchy* fBBH;
+};
+
+// When the canvas clip covers the full picture, we don't need to call the BBH.
+DEF_TEST(Picture_SkipBBH, r) {
+ CountingBBH bbh;
+ SpoonFedBBHFactory factory(&bbh);
+
+ SkPictureRecorder recorder;
+ recorder.beginRecording(320, 240, &factory);
+ SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
+
+ SkCanvas big(640, 480), small(300, 200);
+
+ picture->draw(&big);
+ REPORTER_ASSERT(r, bbh.searchCalls == 0);
+
+ picture->draw(&small);
+ REPORTER_ASSERT(r, bbh.searchCalls == 1);
+}