add picture-record option to speedup complex clips
authorreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 13 Feb 2009 14:56:09 +0000 (14:56 +0000)
committerreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 13 Feb 2009 14:56:09 +0000 (14:56 +0000)
remove hack that stopped picture-playback from culling on clipPath() result

git-svn-id: http://skia.googlecode.com/svn/trunk@92 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkPicture.h
src/core/SkPicture.cpp
src/core/SkPicturePlayback.cpp
src/core/SkPictureRecord.cpp
src/core/SkPictureRecord.h

index fa614c9..be7bad5 100644 (file)
@@ -49,10 +49,28 @@ public:
      */
     void swap(SkPicture& other);
     
+    enum RecordingFlags {
+        /*  This flag specifies that when clipPath() is called, the path will
+            be faithfully recorded, but the recording canvas' current clip will
+            only see the path's bounds. This speeds up the recording process
+            without compromising the fidelity of the playback. The only side-
+            effect for recording is that calling getTotalClip() or related
+            clip-query calls will reflect the path's bounds, not the actual
+            path.
+         */
+        kUsePathBoundsForClip_RecordingFlag = 0x01
+    };
+
     /** Returns the canvas that records the drawing commands.
+        @param width the base width for the picture, as if the recording
+                     canvas' bitmap had this width.
+        @param height the base width for the picture, as if the recording
+                     canvas' bitmap had this height.
+        @param recordFlags optional flags that control recording.
         @return the picture canvas.
     */
-    SkCanvas* beginRecording(int width, int height);
+    SkCanvas* beginRecording(int width, int height, uint32_t recordFlags = 0);
+
     /** Returns the recording canvas if one is active, or NULL if recording is
         not active. This does not alter the refcnt on the canvas (if present).
     */
@@ -103,9 +121,10 @@ private:
 
 class SkAutoPictureRecord : SkNoncopyable {
 public:
-    SkAutoPictureRecord(SkPicture* pict, int width, int height) {
+    SkAutoPictureRecord(SkPicture* pict, int width, int height,
+                        uint32_t recordingFlags = 0) {
         fPicture = pict;
-        fCanvas = pict->beginRecording(width, height);
+        fCanvas = pict->beginRecording(width, height, recordingFlags);
     }
     ~SkAutoPictureRecord() {
         fPicture->endRecording();
index 07cb0a6..343ca2b 100644 (file)
@@ -146,7 +146,8 @@ void SkPicture::swap(SkPicture& other) {
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkCanvas* SkPicture::beginRecording(int width, int height) {
+SkCanvas* SkPicture::beginRecording(int width, int height,
+                                    uint32_t recordingFlags) {
     if (fPlayback) {
         SkDELETE(fPlayback);
         fPlayback = NULL;
@@ -157,7 +158,7 @@ SkCanvas* SkPicture::beginRecording(int width, int height) {
         fRecord = NULL;
     }
 
-    fRecord = SkNEW(SkPictureRecord);
+    fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags));
 
     fWidth = width;
     fHeight = height;
index da17c32..4a3338a 100644 (file)
@@ -3,6 +3,11 @@
 #include "SkTypeface.h"
 #include <new>
 
+/*  Define this to spew out a debug statement whenever we skip the remainder of
+    a save/restore block because a clip... command returned false (empty).
+ */
+#define SPEW_CLIP_SKIPPINGx
+
 SkPicturePlayback::SkPicturePlayback() {
     this->init();
 }
@@ -461,10 +466,31 @@ SkPicturePlayback::SkPicturePlayback(SkStream* stream) {
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
+#ifdef SPEW_CLIP_SKIPPING
+struct SkipClipRec {
+    int     fCount;
+    size_t  fSize;
+    
+    SkipClipRec() {
+        fCount = 0;
+        fSize = 0;
+    }
+    
+    void recordSkip(size_t bytes) {
+        fCount += 1;
+        fSize += bytes;
+    }
+};
+#endif
+
 void SkPicturePlayback::draw(SkCanvas& canvas) {
 #ifdef ENABLE_TIME_DRAW
     SkAutoTime  at("SkPicture::draw", 50);
 #endif
+    
+#ifdef SPEW_CLIP_SKIPPING
+    SkipClipRec skipRect, skipRegion, skipPath;
+#endif
 
     TextContainer text;
     fReader.rewind();
@@ -476,8 +502,10 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
                 SkRegion::Op op = (SkRegion::Op) getInt();
                 size_t offsetToRestore = getInt();
                 // HACK (false) until I can handle op==kReplace 
-                if (!canvas.clipPath(path, op) && false) {
-                    //SkDebugf("---- skip clipPath for %d bytes\n", offsetToRestore - fReader.offset());
+                if (!canvas.clipPath(path, op)) {
+#ifdef SPEW_CLIP_SKIPPING
+                    skipPath.recordSkip(offsetToRestore - fReader.offset());
+#endif
                     fReader.setOffset(offsetToRestore);
                 }
             } break;
@@ -486,7 +514,9 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
                 SkRegion::Op op = (SkRegion::Op) getInt();
                 size_t offsetToRestore = getInt();
                 if (!canvas.clipRegion(region, op)) {
-                    //SkDebugf("---- skip clipDeviceRgn for %d bytes\n", offsetToRestore - fReader.offset());
+#ifdef SPEW_CLIP_SKIPPING
+                    skipRegion.recordSkip(offsetToRestore - fReader.offset());
+#endif
                     fReader.setOffset(offsetToRestore);
                 }
             } break;
@@ -495,7 +525,9 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
                 SkRegion::Op op = (SkRegion::Op) getInt();
                 size_t offsetToRestore = getInt();
                 if (!canvas.clipRect(*rect, op)) {
-                    //SkDebugf("---- skip clipRect for %d bytes\n", offsetToRestore - fReader.offset());
+#ifdef SPEW_CLIP_SKIPPING
+                    skipRect.recordSkip(offsetToRestore - fReader.offset());
+#endif
                     fReader.setOffset(offsetToRestore);
                 }
             } break;
@@ -671,6 +703,14 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
         }
     }
     
+#ifdef SPEW_CLIP_SKIPPING
+    {
+        size_t size =  skipRect.fSize + skipPath.fSize + skipRegion.fSize;
+        SkDebugf("--- Clip skips %d%% rect:%d path:%d rgn:%d\n",
+             size * 100 / fReader.offset(), skipRect.fCount, skipPath.fCount,
+             skipRegion.fCount);
+    }
+#endif
 //    this->dumpSize();
 }
 
index 4f236d6..c1fadc6 100644 (file)
@@ -4,8 +4,8 @@
 #define MIN_WRITER_SIZE 16384
 #define HEAP_BLOCK_SIZE 4096
 
-SkPictureRecord::SkPictureRecord() :
-        fHeap(HEAP_BLOCK_SIZE), fWriter(MIN_WRITER_SIZE) {
+SkPictureRecord::SkPictureRecord(uint32_t flags) :
+        fHeap(HEAP_BLOCK_SIZE), fWriter(MIN_WRITER_SIZE), fRecordFlags(flags) {
     fBitmapIndex = fMatrixIndex = fPaintIndex = fRegionIndex = 1;
 #ifdef SK_DEBUG_SIZE
     fPointBytes = fRectBytes = fTextBytes = 0;
@@ -136,7 +136,14 @@ bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op) {
     fRestoreOffsetStack.top() = offset;
     
     validate();
-    return this->INHERITED::clipPath(path, op);
+    
+    if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
+        SkRect bounds;
+        path.computeBounds(&bounds, SkPath::kFast_BoundsType);
+        return this->INHERITED::clipRect(bounds, op);
+    } else {
+        return this->INHERITED::clipPath(path, op);
+    }
 }
 
 bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
index b23c747..5325e1e 100644 (file)
@@ -11,7 +11,7 @@
 
 class SkPictureRecord : public SkCanvas {
 public:
-    SkPictureRecord();
+    SkPictureRecord(uint32_t recordFlags);
     virtual ~SkPictureRecord();
 
     // overrides from SkCanvas
@@ -171,6 +171,8 @@ private:
     SkRefCntRecorder fRCRecorder;
     SkRefCntRecorder fTFRecorder;
     
+    uint32_t fRecordFlags;
+
     friend class SkPicturePlayback;
 
     typedef SkCanvas INHERITED;