diff options
author | 2014-02-27 17:40:13 +0000 | |
---|---|---|
committer | 2014-02-27 17:40:13 +0000 | |
commit | 210ae2a42613b9048e8e8c4096c5bf4fe2ddf838 (patch) | |
tree | c0310de0eed40822a606c9ebcfc0e9ff0b0b0dd3 /src/core/SkPictureRecord.cpp | |
parent | 6f954b956fc5c36ebbcac404d93ba9349fb0355f (diff) |
Culling API
*** SKP format breaking change ***
Adding a couple of culling primitives: pushCull(SkRect) & popCull().
These are currently only plumbed for SKP playback quickreject.
At record time, we perform a couple of optimizations to trim down the
number of redundant culls:
* collapse empty pushCull/popCull pairs
* skip pushCull/popCull pairs nested within an identical cull rect
Things still missing/to consider:
* use an inlineable, simplified quickreject (Mike's old prototype)
* debugger visualization for cull boxes
* BBH integration: the initial prototype had some minimal BBH support,
but since the optimizations required expensive rewinds and culling
is expected to be a BBH alternative, it got dropped.
R=bsalomon@google.com, reed@google.com, robertphillips@google.com, caryclark@google.com, tomhudson@google.com, iancottrell@google.com
Author: fmalita@chromium.org
Review URL: https://codereview.chromium.org/138013009
git-svn-id: http://skia.googlecode.com/svn/trunk@13611 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core/SkPictureRecord.cpp')
-rw-r--r-- | src/core/SkPictureRecord.cpp | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index be86951ae8..978e2b37c2 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -112,6 +112,8 @@ static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) { 0, // COMMENT - no paint 0, // END_GROUP - no paint 1, // DRAWDRRECT - right after op code + 0, // PUSH_CULL - no paint + 0, // POP_CULL - no paint }; SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1, @@ -220,6 +222,15 @@ bool SkPictureRecord::isDrawingToLayer() const { } /* + * Read the op code from 'offset' in 'writer'. + */ +#ifdef SK_DEBUG +static DrawType peek_op(SkWriter32* writer, int32_t offset) { + return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24); +} +#endif + +/* * Read the op code from 'offset' in 'writer' and extract the size too. */ static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) { @@ -1548,6 +1559,61 @@ void SkPictureRecord::endCommentGroup() { this->validate(initialOffset, size); } +// [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). + SkASSERT(size == kPushCullOpSize); + + this->addRect(cullRect); + fCullOffsetStack.push(fWriter.bytesWritten()); + this->addInt(0); + this->validate(initialOffset, size); +} + +void SkPictureRecord::onPopCull() { + SkASSERT(!fCullOffsetStack.isEmpty()); + + 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); + SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize)); + fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize); + return; + } + + // op only + uint32_t size = kUInt32Size; + size_t initialOffset = this->addDraw(POP_CULL, &size); + + // update the cull skip offset to point past this op. + fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten()); + + this->validate(initialOffset, size); +} + /////////////////////////////////////////////////////////////////////////////// SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) { |