}
int SkPictureRecord::save(SaveFlags flags) {
+ // record the offset to us, making it non-positive to distinguish a save
+ // from a clip entry.
+ fRestoreOffsetStack.push(-(int32_t)fWriter.size());
+
addDraw(SAVE);
addInt(flags);
- fRestoreOffsetStack.push(0);
-
validate();
return this->INHERITED::save(flags);
}
int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
SaveFlags flags) {
+ // record the offset to us, making it non-positive to distinguish a save
+ // from a clip entry.
+ fRestoreOffsetStack.push(-(int32_t)fWriter.size());
+
addDraw(SAVE_LAYER);
addRectPtr(bounds);
addPaintPtr(paint);
addInt(flags);
- fRestoreOffsetStack.push(0);
-
if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
fFirstSavedLayerIndex = fRestoreOffsetStack.count();
}
return fFirstSavedLayerIndex != kNoSavedLayerIndex;
}
+// Return the size of the specified drawType's recorded block, or 0 if this verb
+// is variable sized, and therefore not known.
+static inline uint32_t getSkipableSize(unsigned drawType) {
+ static const uint8_t gSizes[LAST_DRAWTYPE_ENUM + 1] = {
+ 0, // UNUSED,
+ 4, // CLIP_PATH,
+ 4, // CLIP_REGION,
+ 7, // CLIP_RECT,
+ 2, // CONCAT,
+ 0, // DRAW_BITMAP,
+ 0, // DRAW_BITMAP_MATRIX,
+ 0, // DRAW_BITMAP_NINE,
+ 0, // DRAW_BITMAP_RECT,
+ 0, // DRAW_CLEAR,
+ 0, // DRAW_DATA,
+ 0, // DRAW_PAINT,
+ 0, // DRAW_PATH,
+ 0, // DRAW_PICTURE,
+ 0, // DRAW_POINTS,
+ 0, // DRAW_POS_TEXT,
+ 0, // DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
+ 0, // DRAW_POS_TEXT_H,
+ 0, // DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
+ 0, // DRAW_RECT,
+ 0, // DRAW_SPRITE,
+ 0, // DRAW_TEXT,
+ 0, // DRAW_TEXT_ON_PATH,
+ 0, // DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT
+ 0, // DRAW_VERTICES,
+ 0, // RESTORE,
+ 2, // ROTATE,
+ 2, // SAVE,
+ 0, // SAVE_LAYER,
+ 3, // SCALE,
+ 2, // SET_MATRIX,
+ 3, // SKEW,
+ 3, // TRANSLATE,
+ };
+
+ SkASSERT(sizeof(gSizes) == LAST_DRAWTYPE_ENUM + 1);
+ SkASSERT((unsigned)drawType <= (unsigned)LAST_DRAWTYPE_ENUM);
+ return gSizes[drawType] * sizeof(uint32_t);
+}
+
+#ifdef TRACK_COLLAPSE_STATS
+ static int gCollapseCount, gCollapseCalls;
+#endif
+
+/*
+ * Restore has just been called (but not recoreded), so look back at the
+ * matching save(), and see if we can eliminate the pair of them, due to no
+ * intervening matrix/clip calls.
+ *
+ * If so, update the writer and return true, in which case we won't even record
+ * the restore() call. If we still need the restore(), return false.
+ */
+static bool collapseSaveClipRestore(SkWriter32* writer, int32_t offset) {
+#ifdef TRACK_COLLAPSE_STATS
+ gCollapseCalls += 1;
+#endif
+
+ int32_t restoreOffset = (int32_t)writer->size();
+
+ // back up to the save block
+ while (offset > 0) {
+ offset = *writer->peek32(offset);
+ }
+
+ // now offset points to a save
+ offset = -offset;
+ if (SAVE_LAYER == *writer->peek32(offset)) {
+ // not ready to cull these out yet (mrr)
+ return false;
+ }
+ SkASSERT(SAVE == *writer->peek32(offset));
+
+ // Walk forward until we get back to either a draw-verb (abort) or we hit
+ // our restore (success).
+ int32_t saveOffset = offset;
+
+ offset += getSkipableSize(SAVE);
+ while (offset < restoreOffset) {
+ uint32_t* block = writer->peek32(offset);
+ uint32_t op = *block;
+ uint32_t opSize = getSkipableSize(op);
+ if (0 == opSize) {
+ // drawing verb, abort
+ return false;
+ }
+ offset += opSize;
+ }
+
+#ifdef TRACK_COLLAPSE_STATS
+ gCollapseCount += 1;
+ SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
+ (double)gCollapseCount / gCollapseCalls, "%");
+#endif
+
+ writer->rewindToOffset(saveOffset);
+ return true;
+}
+
void SkPictureRecord::restore() {
// FIXME: SkDeferredCanvas needs to be refactored to respect
// save/restore balancing so that the following test can be
return;
}
- fillRestoreOffsetPlaceholdersForCurrentStackLevel(
- (uint32_t)fWriter.size());
-
if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
fFirstSavedLayerIndex = kNoSavedLayerIndex;
}
+ if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top())) {
+ fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size());
+ this->addDraw(RESTORE);
+ }
+
fRestoreOffsetStack.pop();
- addDraw(RESTORE);
validate();
return this->INHERITED::restore();
}
void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(
uint32_t restoreOffset) {
- uint32_t offset = fRestoreOffsetStack.top();
- while (offset) {
+ int32_t offset = fRestoreOffsetStack.top();
+ while (offset > 0) {
uint32_t* peek = fWriter.peek32(offset);
offset = *peek;
*peek = restoreOffset;
}
+
+#ifdef SK_DEBUG
+ // assert that the final offset value points to a save verb
+ uint32_t drawOp = *fWriter.peek32(-offset);
+ SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
+#endif
}
void SkPictureRecord::endRecording() {