diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkCanvas.cpp | 9 | ||||
-rw-r--r-- | src/core/SkPictureFlat.h | 4 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.cpp | 30 | ||||
-rw-r--r-- | src/core/SkPictureRecord.cpp | 66 | ||||
-rw-r--r-- | src/core/SkPictureRecord.h | 4 |
5 files changed, 108 insertions, 5 deletions
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 5ba6e8f6dc..a67891e659 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -490,6 +490,7 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device) { fAllowSimplifyClip = false; fDeviceCMDirty = false; fSaveLayerCount = 0; + fCullCount = 0; fMetaData = NULL; fMCRec = (MCRec*)fMCStack.push_back(); @@ -1002,6 +1003,14 @@ bool SkAutoROCanvasPixels::asROBitmap(SkBitmap* bitmap) const { } } +void SkCanvas::onPushCull(const SkRect& cullRect) { + // do nothing. Subclasses may do something +} + +void SkCanvas::onPopCull() { + // do nothing. Subclasses may do something +} + ///////////////////////////////////////////////////////////////////////////// void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h index 77b29c4d34..041352c6f8 100644 --- a/src/core/SkPictureFlat.h +++ b/src/core/SkPictureFlat.h @@ -65,8 +65,10 @@ enum DrawType { // new ops -- feel free to re-alphabetize on next version bump DRAW_DRRECT, + PUSH_CULL, + POP_CULL, - LAST_DRAWTYPE_ENUM = DRAW_DRRECT + LAST_DRAWTYPE_ENUM = POP_CULL }; // In the 'match' method, this constant will match any flavor of DRAW_BITMAP* diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index b546d397c0..a8279ca089 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -707,7 +707,8 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) #endif #ifdef SPEW_CLIP_SKIPPING - SkipClipRec skipRect, skipRRect, skipRegion, skipPath; + SkipClipRec skipRect, skipRRect, skipRegion, skipPath, skipCull; + int opCount = 0; #endif #ifdef SK_BUILD_FOR_ANDROID @@ -772,6 +773,10 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) } #endif +#ifdef SPEW_CLIP_SKIPPING + opCount++; +#endif + size_t curOffset = reader.offset(); uint32_t size; DrawType op = read_op_and_size(&reader, &size); @@ -867,6 +872,21 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) reader.setOffset(offsetToRestore); } } break; + case PUSH_CULL: { + const SkRect& cullRect = reader.skipT<SkRect>(); + size_t offsetToRestore = reader.readInt(); + if (offsetToRestore && canvas.quickReject(cullRect)) { +#ifdef SPEW_CLIP_SKIPPING + skipCull.recordSkip(offsetToRestore - reader.offset()); +#endif + reader.setOffset(offsetToRestore); + } else { + canvas.pushCull(cullRect); + } + } break; + case POP_CULL: + canvas.popCull(); + break; case CONCAT: { SkMatrix matrix; this->getMatrix(reader, &matrix); @@ -1124,10 +1144,12 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) #ifdef SPEW_CLIP_SKIPPING { - size_t size = skipRect.fSize + skipRRect.fSize + skipPath.fSize + skipRegion.fSize; - SkDebugf("--- Clip skips %d%% rect:%d rrect:%d path:%d rgn:%d\n", + size_t size = skipRect.fSize + skipRRect.fSize + skipPath.fSize + skipRegion.fSize + + skipCull.fSize; + SkDebugf("--- Clip skips %d%% rect:%d rrect:%d path:%d rgn:%d cull:%d\n", size * 100 / reader.offset(), skipRect.fCount, skipRRect.fCount, - skipPath.fCount, skipRegion.fCount); + skipPath.fCount, skipRegion.fCount, skipCull.fCount); + SkDebugf("--- Total ops: %d\n", opCount); } #endif // this->dumpSize(); 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) { diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index 2fb99faf37..dc439a108d 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -120,6 +120,8 @@ private: }; #endif + SkTDArray<uint32_t> fCullOffsetStack; + /* * Write the 'drawType' operation and chunk size to the skp. 'size' * can potentially be increased if the chunk size needs its own storage @@ -223,6 +225,8 @@ protected: return NULL; } virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) SK_OVERRIDE; + virtual void onPushCull(const SkRect&) SK_OVERRIDE; + virtual void onPopCull() SK_OVERRIDE; // Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been // tweaked by paint.computeFastBounds(). |