Adding a silent playback option to SkGPipeRead
Testing state consistency after silent playback in CanvasTest indirectly
through SkDeferredCanvas.

BUG=http://code.google.com/p/chromium/issues/detail?id=146178
TEST=CanvasTest unit test, and bench with --mode deferredSilent
Review URL: https://codereview.appspot.com/6542047

git-svn-id: http://skia.googlecode.com/svn/trunk@5619 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index 137ecb7..1f13daf 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -67,6 +67,14 @@
     SkGPipeState();
     ~SkGPipeState();
 
+    void setSilent(bool silent) {
+        fSilent = silent;
+    }
+
+    bool shouldDraw() {
+        return !fSilent;
+    }
+
     void setFlags(unsigned flags) {
         if (fFlags != flags) {
             fFlags = flags;
@@ -183,6 +191,7 @@
     SkTDArray<SkTypeface*>    fTypefaces;
     SkTDArray<SkFlattenable::Factory> fFactoryArray;
     SkTDArray<SkBitmap*>      fBitmaps;
+    bool                      fSilent;
     // Only used when sharing bitmaps with the writer.
     SkBitmapHeap*             fSharedHeap;
     unsigned                  fFlags;
@@ -308,7 +317,9 @@
 
 static void drawPaint_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                          SkGPipeState* state) {
-    canvas->drawPaint(state->paint());
+    if (state->shouldDraw()) {
+        canvas->drawPaint(state->paint());
+    }
 }
 
 static void drawPoints_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@@ -316,19 +327,26 @@
     SkCanvas::PointMode mode = (SkCanvas::PointMode)DrawOp_unpackFlags(op32);
     size_t count = reader->readU32();
     const SkPoint* pts = skip<SkPoint>(reader, count);
-    canvas->drawPoints(mode, count, pts, state->paint());
+    if (state->shouldDraw()) {
+        canvas->drawPoints(mode, count, pts, state->paint());
+    }
 }
 
 static void drawRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                         SkGPipeState* state) {
-    canvas->drawRect(*skip<SkRect>(reader), state->paint());
+    const SkRect* rect = skip<SkRect>(reader);
+    if (state->shouldDraw()) {
+        canvas->drawRect(*rect, state->paint());
+    }
 }
 
 static void drawPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                         SkGPipeState* state) {
     SkPath path;
     reader->readPath(&path);
-    canvas->drawPath(path, state->paint());
+    if (state->shouldDraw()) {
+        canvas->drawPath(path, state->paint());
+    }
 }
 
 static void drawVertices_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@@ -358,9 +376,10 @@
         indexCount = reader->readU32();
         indices = skipAlign<uint16_t>(reader, indexCount);
     }
-
-    canvas->drawVertices(mode, vertexCount, verts, texs, colors, xfer,
-                         indices, indexCount, state->paint());
+    if (state->shouldDraw()) {
+        canvas->drawVertices(mode, vertexCount, verts, texs, colors, xfer,
+                             indices, indexCount, state->paint());
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -370,7 +389,9 @@
     size_t len = reader->readU32();
     const void* text = reader->skip(SkAlign4(len));
     const SkScalar* xy = skip<SkScalar>(reader, 2);
-    canvas->drawText(text, len, xy[0], xy[1], state->paint());
+    if (state->shouldDraw()) {
+        canvas->drawText(text, len, xy[0], xy[1], state->paint());
+    }
 }
 
 static void drawPosText_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@@ -379,7 +400,9 @@
     const void* text = reader->skip(SkAlign4(len));
     size_t posCount = reader->readU32();    // compute by our writer
     const SkPoint* pos = skip<SkPoint>(reader, posCount);
-    canvas->drawPosText(text, len, pos, state->paint());
+    if (state->shouldDraw()) {
+        canvas->drawPosText(text, len, pos, state->paint());
+    }
 }
 
 static void drawPosTextH_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@@ -389,7 +412,9 @@
     size_t posCount = reader->readU32();    // compute by our writer
     const SkScalar* xpos = skip<SkScalar>(reader, posCount);
     SkScalar constY = reader->readScalar();
-    canvas->drawPosTextH(text, len, xpos, constY, state->paint());
+    if (state->shouldDraw()) {
+        canvas->drawPosTextH(text, len, xpos, constY, state->paint());
+    }
 }
 
 static void drawTextOnPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@@ -406,8 +431,9 @@
         reader->readMatrix(&matrixStorage);
         matrix = &matrixStorage;
     }
-
-    canvas->drawTextOnPath(text, len, path, matrix, state->paint());
+    if (state->shouldDraw()) {
+        canvas->drawTextOnPath(text, len, path, matrix, state->paint());
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -461,7 +487,10 @@
     bool hasPaint = SkToBool(DrawOp_unpackFlags(op32) & kDrawBitmap_HasPaint_DrawOpFlag);
     SkScalar left = reader->readScalar();
     SkScalar top = reader->readScalar();
-    canvas->drawBitmap(*holder.getBitmap(), left, top, hasPaint ? &state->paint() : NULL);
+    const SkBitmap* bitmap = holder.getBitmap();
+    if (state->shouldDraw()) {
+        canvas->drawBitmap(*bitmap, left, top, hasPaint ? &state->paint() : NULL);
+    }
 }
 
 static void drawBitmapMatrix_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@@ -470,8 +499,11 @@
     bool hasPaint = SkToBool(DrawOp_unpackFlags(op32) & kDrawBitmap_HasPaint_DrawOpFlag);
     SkMatrix matrix;
     reader->readMatrix(&matrix);
-    canvas->drawBitmapMatrix(*holder.getBitmap(), matrix,
-                             hasPaint ? &state->paint() : NULL);
+    const SkBitmap* bitmap = holder.getBitmap();
+    if (state->shouldDraw()) {
+        canvas->drawBitmapMatrix(*bitmap, matrix,
+                                 hasPaint ? &state->paint() : NULL);
+    }
 }
 
 static void drawBitmapNine_rp(SkCanvas* canvas, SkReader32* reader,
@@ -480,8 +512,11 @@
     bool hasPaint = SkToBool(DrawOp_unpackFlags(op32) & kDrawBitmap_HasPaint_DrawOpFlag);
     const SkIRect* center = skip<SkIRect>(reader);
     const SkRect* dst = skip<SkRect>(reader);
-    canvas->drawBitmapNine(*holder.getBitmap(), *center, *dst,
-                           hasPaint ? &state->paint() : NULL);
+    const SkBitmap* bitmap = holder.getBitmap();
+    if (state->shouldDraw()) {
+        canvas->drawBitmapNine(*bitmap, *center, *dst,
+                               hasPaint ? &state->paint() : NULL);
+    }
 }
 
 static void drawBitmapRect_rp(SkCanvas* canvas, SkReader32* reader,
@@ -497,7 +532,10 @@
         src = NULL;
     }
     const SkRect* dst = skip<SkRect>(reader);
-    canvas->drawBitmapRectToRect(*holder.getBitmap(), src, *dst, hasPaint ? &state->paint() : NULL);
+    const SkBitmap* bitmap = holder.getBitmap();
+    if (state->shouldDraw()) {
+        canvas->drawBitmapRectToRect(*bitmap, src, *dst, hasPaint ? &state->paint() : NULL);
+    }
 }
 
 static void drawSprite_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@@ -505,7 +543,10 @@
     BitmapHolder holder(reader, op32, state);
     bool hasPaint = SkToBool(DrawOp_unpackFlags(op32) & kDrawBitmap_HasPaint_DrawOpFlag);
     const SkIPoint* point = skip<SkIPoint>(reader);
-    canvas->drawSprite(*holder.getBitmap(), point->fX, point->fY, hasPaint ? &state->paint() : NULL);
+    const SkBitmap* bitmap = holder.getBitmap();
+    if (state->shouldDraw()) {
+        canvas->drawSprite(*bitmap, point->fX, point->fY, hasPaint ? &state->paint() : NULL);
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -518,7 +559,9 @@
         size = reader->readU32();
     }
     const void* data = reader->skip(SkAlign4(size));
-    canvas->drawData(data, size);
+    if (state->shouldDraw()) {
+        canvas->drawData(data, size);
+    }
 }
 
 static void drawPicture_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@@ -677,6 +720,7 @@
 
 SkGPipeState::SkGPipeState()
     : fReader(0)
+    , fSilent(false)
     , fSharedHeap(NULL)
     , fFlags(0) {
 
@@ -714,7 +758,7 @@
 }
 
 SkGPipeReader::Status SkGPipeReader::playback(const void* data, size_t length,
-                                              size_t* bytesRead, bool readAtom) {
+                                              uint32_t playbackFlags, size_t* bytesRead) {
     if (NULL == fCanvas) {
         return kError_Status;
     }
@@ -723,6 +767,8 @@
         fState = new SkGPipeState;
     }
 
+    fState->setSilent(playbackFlags & kSilent_PlaybackFlag);
+
     SkASSERT(SK_ARRAY_COUNT(gReadTable) == (kDone_DrawOp + 1));
 
     const ReadProc* table = gReadTable;
@@ -746,7 +792,7 @@
             break;
         }
         table[op](canvas, reader.getReader32(), op32, fState);
-        if (readAtom &&
+        if ((playbackFlags & kReadAtom_PlaybackFlag) &&
             (table[op] != paintOp_rp &&
              table[op] != def_Typeface_rp &&
              table[op] != def_PaintFlat_rp &&
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index ef93c9c..a3306c5 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -151,7 +151,7 @@
     virtual ~DeferredPipeController();
     virtual void* requestBlock(size_t minRequest, size_t* actual) SK_OVERRIDE;
     virtual void notifyWritten(size_t bytes) SK_OVERRIDE;
-    void playback();
+    void playback(bool silent);
     void reset();
     bool hasRecorded() const { return fAllocator.blockCount() != 0; }
     size_t storageAllocatedForRecording() const { return fAllocator.totalCapacity(); }
@@ -202,15 +202,16 @@
     fBytesWritten += bytes;
 }
 
-void DeferredPipeController::playback() {
-
+void DeferredPipeController::playback(bool silent) {
+    uint32_t flags = silent ? SkGPipeReader::kSilent_PlaybackFlag : 0;
     for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
-        fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize);
+        fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize,
+                         flags);
     }
     fBlockList.reset();
 
     if (fBlock) {
-        fReader.playback(fBlock, fBytesWritten);
+        fReader.playback(fBlock, fBytesWritten, flags);
         fBlock = NULL;
     }
 
@@ -241,7 +242,7 @@
     bool isFreshFrame();
     size_t storageAllocatedForRecording() const;
     size_t freeMemoryIfPossible(size_t bytesToFree);
-    void flushPendingCommands();
+    void flushPendingCommands(bool silent);
     void skipPendingCommands();
     void setMaxRecordingStorage(size_t);
     void recordedDrawCommand();
@@ -359,7 +360,7 @@
 }
 
 DeferredDevice::~DeferredDevice() {
-    this->flushPendingCommands();
+    this->flushPendingCommands(true);
     SkSafeUnref(fImmediateCanvas);
 }
 
@@ -428,7 +429,7 @@
     return ret;
 }
 
-void DeferredDevice::flushPendingCommands() {
+void DeferredDevice::flushPendingCommands(bool silent) {
     if (!fPipeController.hasRecorded()) {
         return;
     }
@@ -436,7 +437,7 @@
         fNotificationClient->prepareForDraw();
     }
     fPipeWriter.flushRecording(true);
-    fPipeController.playback();
+    fPipeController.playback(silent);
     if (fNotificationClient) {
         fNotificationClient->flushedDrawCommands();
     }
@@ -444,7 +445,7 @@
 }
 
 void DeferredDevice::flush() {
-    this->flushPendingCommands();
+    this->flushPendingCommands(false);
     fImmediateCanvas->flush();
 }
 
@@ -467,7 +468,7 @@
         size_t tryFree = storageAllocated - fMaxRecordingStorageBytes;
         if (this->freeMemoryIfPossible(tryFree) < tryFree) {
             // Flush is necessary to free more space.
-            this->flushPendingCommands();
+            this->flushPendingCommands(false);
             // Free as much as possible to avoid oscillating around fMaxRecordingStorageBytes
             // which could cause a high flushing frequency.
             this->freeMemoryIfPossible(~0U);
@@ -499,7 +500,7 @@
 }
 
 SkGpuRenderTarget* DeferredDevice::accessRenderTarget() {
-    this->flushPendingCommands();
+    this->flushPendingCommands(false);
     return fImmediateDevice->accessRenderTarget();
 }
 
@@ -515,7 +516,7 @@
         SkCanvas::kNative_Premul_Config8888 != config8888 &&
         kPMColorAlias != config8888) {
         //Special case config: no deferral
-        this->flushPendingCommands();
+        this->flushPendingCommands(false);
         fImmediateDevice->writePixels(bitmap, x, y, config8888);
         return;
     }
@@ -523,7 +524,7 @@
     SkPaint paint;
     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
     if (shouldDrawImmediately(&bitmap, NULL)) {
-        this->flushPendingCommands();
+        this->flushPendingCommands(false);
         fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
     } else {
         this->recordingCanvas()->drawSprite(bitmap, x, y, &paint);
@@ -533,7 +534,7 @@
 }
 
 const SkBitmap& DeferredDevice::onAccessBitmap(SkBitmap*) {
-    this->flushPendingCommands();
+    this->flushPendingCommands(false);
     return fImmediateDevice->accessBitmap(false);
 }
 
@@ -552,7 +553,7 @@
 
 bool DeferredDevice::onReadPixels(
     const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
-    this->flushPendingCommands();
+    this->flushPendingCommands(false);
     return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
                                                    x, y, config8888);
 }
@@ -614,7 +615,7 @@
     if (val != fDeferredDrawing) {
         if (fDeferredDrawing) {
             // Going live.
-            this->getDeferredDevice()->flushPendingCommands();
+            this->getDeferredDevice()->flushPendingCommands(false);
         }
         fDeferredDrawing = val;
     }
@@ -628,6 +629,12 @@
     return this->getDeferredDevice()->isFreshFrame();
 }
 
+void SkDeferredCanvas::silentFlush() {
+    if (fDeferredDrawing) {
+        this->getDeferredDevice()->flushPendingCommands(true);
+    }
+}
+
 SkDeferredCanvas::~SkDeferredCanvas() {
 }