Fixing a deferred canvas optimization that purges pending draws when the canvas is...
authorjunov@chromium.org <junov@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 15 Aug 2012 19:49:22 +0000 (19:49 +0000)
committerjunov@chromium.org <junov@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 15 Aug 2012 19:49:22 +0000 (19:49 +0000)
It appears that the recording canvas returns a save count of 1 when the save stack is empty.
In order to pass Canvas unit tests when a clear occurs, changes to SkGPipe were necessary
to allow SkDeferredCanvas to set the device bounds on the SkGPipeCanvas.  A positive
side effect of this change is that graphics primitives that fall outside of the device
bounds will now always be culled at the recording stage (as opposed playback).

BUG=http://code.google.com/p/skia/issues/detail?id=782
TEST=deferred_canvas_record bench test
Review URL: https://codereview.appspot.com/6454157

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

include/pipe/SkGPipe.h
src/pipe/SkGPipeWrite.cpp
src/utils/SkDeferredCanvas.cpp

index 40ab30a..bbe504a 100644 (file)
@@ -103,7 +103,9 @@ public:
         kSharedAddressSpace_Flag        = 1 << 1
     };
 
-    SkCanvas* startRecording(SkGPipeController*, uint32_t flags = 0);
+    SkCanvas* startRecording(SkGPipeController*, uint32_t flags = 0,
+        uint32_t width = kDefaultRecordingCanvasSize,
+        uint32_t height = kDefaultRecordingCanvasSize);
 
     // called in destructor, but can be called sooner once you know there
     // should be no more drawing calls made into the recording canvas.
@@ -136,6 +138,10 @@ public:
     size_t freeMemoryIfPossible(size_t bytesToFree);
 
 private:
+    enum {
+        kDefaultRecordingCanvasSize = 32767,
+    };
+
     SkGPipeCanvas* fCanvas;
     SkWriter32     fWriter;
 };
index 4f408fd..aad4c8a 100644 (file)
@@ -163,7 +163,8 @@ public:
 
 class SkGPipeCanvas : public SkCanvas {
 public:
-    SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags);
+    SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags,
+                  uint32_t width, uint32_t height);
     virtual ~SkGPipeCanvas();
 
     void finish() {
@@ -400,7 +401,8 @@ private:
 #define FLATTENABLES_TO_KEEP 10
 
 SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
-                             SkWriter32* writer, uint32_t flags)
+                             SkWriter32* writer, uint32_t flags, 
+                             uint32_t width, uint32_t height)
 : fFactorySet(isCrossProcess(flags) ? SkNEW(SkNamedFactorySet) : NULL)
 , fWriter(*writer)
 , fFlags(flags)
@@ -414,10 +416,9 @@ SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
     sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
 
     // we need a device to limit our clip
-    // should the caller give us the bounds?
     // We don't allocate pixels for the bitmap
     SkBitmap bitmap;
-    bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
+    bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
     SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
     this->setDevice(device)->unref();
 
@@ -1091,10 +1092,11 @@ SkGPipeWriter::~SkGPipeWriter() {
     this->endRecording();
 }
 
-SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags) {
+SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags,
+                                        uint32_t width, uint32_t height) {
     if (NULL == fCanvas) {
         fWriter.reset(NULL, 0);
-        fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, flags));
+        fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, flags, width, height));
     }
     controller->setCanvas(fCanvas);
     return fCanvas;
index bf3ce16..c66e09c 100644 (file)
@@ -348,6 +348,7 @@ DeferredDevice::DeferredDevice(
     SkDevice* immediateDevice, SkDeferredCanvas::NotificationClient* notificationClient) :
     SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
              immediateDevice->height(), immediateDevice->isOpaque())
+    , fRecordingCanvas(NULL)
     , fFreshFrame(true)
     , fPreviousStorageAllocated(0){
 
@@ -378,7 +379,9 @@ void DeferredDevice::endRecording() {
 }
 
 void DeferredDevice::beginRecording() {
-    fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0);
+    SkASSERT(NULL == fRecordingCanvas);
+    fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0, 
+        fImmediateDevice->width(), fImmediateDevice->height());
 }
     
 void DeferredDevice::setNotificationClient(
@@ -392,8 +395,9 @@ void DeferredDevice::contentsCleared() {
 
         // TODO: find a way to transfer the state stack and layers
         // to the new recording canvas.  For now, purging only works
-        // with an empty stack.
-        if (fRecordingCanvas->getSaveCount() == 0) {
+        // with an empty stack.  A save count of 1 means an empty stack.
+        SkASSERT(fRecordingCanvas->getSaveCount() >= 1);
+        if (fRecordingCanvas->getSaveCount() == 1) {
 
             // Save state that is trashed by the purge
             SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();