SkCanvas::resetForNextPicture()
authormtklein <mtklein@chromium.org>
Wed, 8 Apr 2015 18:25:48 +0000 (11:25 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 8 Apr 2015 18:25:48 +0000 (11:25 -0700)
No diffs against head for DM --config 8888 gpu 2ndpic-8888 2ndpic-gpu.

  picture_overhead_draw 1.62us ->  1.6us 0.99x
picture_overhead_nodraw  792ns ->  342ns 0.43x

tiles and serialization modes will also test this a bit.

BUG=chromium:470553

Committed: https://skia.googlesource.com/skia/+/f920e468ac66a36c9653d1b11181480295044c7d

Review URL: https://codereview.chromium.org/1067893002

include/core/SkBitmapDevice.h
include/core/SkCanvas.h
include/core/SkPictureRecorder.h
src/core/SkBitmapDevice.cpp
src/core/SkCanvas.cpp
src/core/SkPictureRecorder.cpp
src/core/SkRecorder.cpp
src/core/SkRecorder.h
tests/PictureTest.cpp

index 9d8c4c5..69adc9a 100644 (file)
@@ -150,6 +150,8 @@ private:
 
     SkBitmap    fBitmap;
 
+    void setNewSize(const SkISize&);  // Used by SkCanvas for resetForNextPicture().
+
     typedef SkBaseDevice INHERITED;
 };
 
index 853877d..828b923 100644 (file)
@@ -1301,6 +1301,8 @@ private:
     SkCanvas(const SkIRect& bounds, InitFlags);
     SkCanvas(SkBaseDevice*, const SkSurfaceProps*, InitFlags);
 
+    void resetForNextPicture(const SkIRect& bounds);
+
     // needs gettotalclip()
     friend class SkCanvasStateUtils;
 
index b25e26b..0459737 100644 (file)
@@ -96,6 +96,7 @@ private:
     friend class SkPictureRecorderReplayTester; // for unit testing
     void partialReplay(SkCanvas* canvas) const;
 
+    bool                          fActivelyRecording;
     uint32_t                      fFlags;
     SkRect                        fCullRect;
     SkAutoTUnref<SkBBoxHierarchy> fBBH;
index 5fae2b5..5b2fc38 100644 (file)
@@ -103,6 +103,11 @@ SkImageInfo SkBitmapDevice::imageInfo() const {
     return fBitmap.info();
 }
 
+void SkBitmapDevice::setNewSize(const SkISize& size) {
+    SkASSERT(!fBitmap.pixelRef());
+    fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight));
+}
+
 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
     SkASSERT(bm.width() == fBitmap.width());
     SkASSERT(bm.height() == fBitmap.height());
index ec21955..63a9241 100644 (file)
@@ -135,6 +135,13 @@ struct DeviceCM {
         SkDELETE(fPaint);
     }
 
+    void reset(const SkIRect& bounds) {
+        SkASSERT(!fPaint);
+        SkASSERT(!fNext);
+        SkASSERT(fDevice);
+        fClip.setRect(bounds);
+    }
+
     void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
                   const SkClipStack& clipStack, SkRasterClip* updateClip) {
         int x = fDevice->getOrigin().x();
@@ -224,6 +231,15 @@ public:
         SkDELETE(fLayer);
         dec_rec();
     }
+
+    void reset(const SkIRect& bounds) {
+        SkASSERT(fLayer);
+        SkASSERT(fDeferredSaveCount == 0);
+
+        fMatrix.reset();
+        fRasterClip.setRect(bounds);
+        fLayer->reset(bounds);
+    }
 };
 
 class SkDrawIter : public SkDraw {
@@ -425,6 +441,18 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
 
 ////////////////////////////////////////////////////////////////////////////
 
+void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
+    this->restoreToCount(1);
+    fCachedLocalClipBounds.setEmpty();
+    fCachedLocalClipBoundsDirty = true;
+    fClipStack->reset();
+    fMCRec->reset(bounds);
+
+    // We're peering through a lot of structs here.  Only at this scope do we
+    // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
+    static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
+}
+
 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
     fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
     fCachedLocalClipBounds.setEmpty();
index 850be27..f622e66 100644 (file)
 #include "SkRecordOpts.h"
 #include "SkTypes.h"
 
-SkPictureRecorder::SkPictureRecorder() {}
+SkPictureRecorder::SkPictureRecorder() {
+    fActivelyRecording = false;
+    fRecorder.reset(SkNEW_ARGS(SkRecorder, (nullptr, SkRect::MakeWH(0,0))));
+}
 
 SkPictureRecorder::~SkPictureRecorder() {}
 
@@ -31,15 +34,18 @@ SkCanvas* SkPictureRecorder::beginRecording(const SkRect& cullRect,
     }
 
     fRecord.reset(SkNEW(SkRecord));
-    fRecorder.reset(SkNEW_ARGS(SkRecorder, (fRecord.get(), cullRect)));
+    fRecorder->reset(fRecord.get(), cullRect);
+    fActivelyRecording = true;
     return this->getRecordingCanvas();
 }
 
 SkCanvas* SkPictureRecorder::getRecordingCanvas() {
-    return fRecorder.get();
+    return fActivelyRecording ? fRecorder.get() : nullptr;
 }
 
 SkPicture* SkPictureRecorder::endRecordingAsPicture() {
+    fActivelyRecording = false;
+    fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
     // TODO: delay as much of this work until just before first playback?
     SkRecordOptimize(fRecord);
 
@@ -73,7 +79,6 @@ SkPicture* SkPictureRecorder::endRecordingAsPicture() {
     }
 
     // release our refs now, so only the picture will be the owner.
-    fRecorder.reset(NULL);
     fRecord.reset(NULL);
     fBBH.reset(NULL);
 
@@ -158,6 +163,8 @@ protected:
 };
 
 SkDrawable* SkPictureRecorder::endRecordingAsDrawable() {
+    fActivelyRecording = false;
+    fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
     // TODO: delay as much of this work until just before first playback?
     SkRecordOptimize(fRecord);
 
@@ -171,7 +178,6 @@ SkDrawable* SkPictureRecorder::endRecordingAsDrawable() {
                                          SkToBool(fFlags & kComputeSaveLayerInfo_RecordFlag)));
 
     // release our refs now, so only the drawable will be the owner.
-    fRecorder.reset(NULL);
     fRecord.reset(NULL);
     fBBH.reset(NULL);
 
index aafb540..8684a8e 100644 (file)
@@ -39,6 +39,12 @@ SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds)
     : SkCanvas(bounds.roundOut(), SkCanvas::kConservativeRasterClip_InitFlag)
     , fRecord(record) {}
 
+void SkRecorder::reset(SkRecord* record, const SkRect& bounds) {
+    this->forgetRecord();
+    fRecord = record;
+    this->resetForNextPicture(bounds.roundOut());
+}
+
 void SkRecorder::forgetRecord() {
     fDrawableList.reset(NULL);
     fRecord = NULL;
index 834a2b6..6842aec 100644 (file)
@@ -39,6 +39,8 @@ public:
     SkRecorder(SkRecord*, int width, int height);   // legacy version
     SkRecorder(SkRecord*, const SkRect& bounds);
 
+    void reset(SkRecord*, const SkRect& bounds);
+
     SkDrawableList* getDrawableList() const { return fDrawableList.get(); }
     SkDrawableList* detachDrawableList() { return fDrawableList.detach(); }
 
index 14e703f..153695b 100644 (file)
@@ -1311,3 +1311,15 @@ DEF_TEST(Picture_BitmapLeak, r) {
     REPORTER_ASSERT(r, mut.pixelRef()->unique());
     REPORTER_ASSERT(r, immut.pixelRef()->unique());
 }
+
+// getRecordingCanvas() should return a SkCanvas when recording, null when not recording.
+DEF_TEST(Picture_getRecordingCanvas, r) {
+    SkPictureRecorder rec;
+    REPORTER_ASSERT(r, !rec.getRecordingCanvas());
+    for (int i = 0; i < 3; i++) {
+        rec.beginRecording(100, 100);
+        REPORTER_ASSERT(r, rec.getRecordingCanvas());
+        rec.endRecording()->unref();
+        REPORTER_ASSERT(r, !rec.getRecordingCanvas());
+    }
+}