aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pipe/SkGPipeWrite.cpp
diff options
context:
space:
mode:
authorGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-11-12 14:32:38 +0000
committerGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-11-12 14:32:38 +0000
commit59c3ab637b7cb23c1afc098a2967518788a671ea (patch)
tree353fff6583fc92307ab87bdfd2e2c9b4e5e4eba3 /src/pipe/SkGPipeWrite.cpp
parentd6bea606c6930b3f7a8093b9a7bb78c7e3efb287 (diff)
Fix a memory leak in SkGPipeCanvas.
In cross process mode (currently unused but tested on the bots), SkGPipeCanvas has a tangle of circular references, which prevents it from being deleted. Break the chain of references. R=junov@chromium.org Review URL: https://codereview.chromium.org/69633003 git-svn-id: http://skia.googlecode.com/svn/trunk@12237 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/pipe/SkGPipeWrite.cpp')
-rw-r--r--src/pipe/SkGPipeWrite.cpp118
1 files changed, 71 insertions, 47 deletions
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index b61de1c912..4324080325 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -167,32 +167,63 @@ public:
///////////////////////////////////////////////////////////////////////////////
+/**
+ * If SkBitmaps are to be flattened to send to the reader, this class is
+ * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so.
+ */
+class BitmapShuttle : public SkBitmapHeap::ExternalStorage {
+public:
+ BitmapShuttle(SkGPipeCanvas*);
+
+ ~BitmapShuttle();
+
+ virtual bool insert(const SkBitmap& bitmap, int32_t slot) SK_OVERRIDE;
+
+ /**
+ * Remove the SkGPipeCanvas used for insertion. After this, calls to
+ * insert will crash.
+ */
+ void removeCanvas();
+
+private:
+ SkGPipeCanvas* fCanvas;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
class SkGPipeCanvas : public SkCanvas {
public:
SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags,
uint32_t width, uint32_t height);
virtual ~SkGPipeCanvas();
- void finish() {
- if (!fDone) {
- if (this->needOpBytes()) {
- this->writeOp(kDone_DrawOp);
- this->doNotify();
- if (shouldFlattenBitmaps(fFlags)) {
- // In this case, a BitmapShuttle is reffed by the SkBitmapHeap
- // and refs this canvas. Unref the SkBitmapHeap to end the
- // circular reference. When shouldFlattenBitmaps is false,
- // there is no circular reference, so the SkBitmapHeap can be
- // safely unreffed in the destructor.
- fBitmapHeap->unref();
- // This eliminates a similar circular reference (Canvas owns
- // the FlattenableHeap which holds a ref to the SkBitmapHeap).
- fFlattenableHeap.setBitmapStorage(NULL);
- fBitmapHeap = NULL;
- }
- }
- fDone = true;
+ /**
+ * Called when nothing else is to be written to the stream. Any repeated
+ * calls are ignored.
+ *
+ * @param notifyReaders Whether to send a message to the reader(s) that
+ * the writer is through sending commands. Should generally be true,
+ * unless there is an error which prevents further messages from
+ * being sent.
+ */
+ void finish(bool notifyReaders) {
+ if (fDone) {
+ return;
+ }
+ if (notifyReaders && this->needOpBytes()) {
+ this->writeOp(kDone_DrawOp);
+ this->doNotify();
}
+ if (shouldFlattenBitmaps(fFlags)) {
+ // The following circular references exist:
+ // fFlattenableHeap -> fWriteBuffer -> fBitmapStorage -> fExternalStorage -> fCanvas
+ // fBitmapHeap -> fExternalStorage -> fCanvas
+ // fFlattenableHeap -> fBitmapStorage -> fExternalStorage -> fCanvas
+
+ // Break them all by destroying the final link to this SkGPipeCanvas.
+ fBitmapShuttle->removeCanvas();
+ }
+ fDone = true;
}
void flushRecording(bool detachCurrentBlock);
@@ -306,9 +337,11 @@ private:
// if a new SkFlatData was added when in cross process mode
void flattenFactoryNames();
- FlattenableHeap fFlattenableHeap;
- FlatDictionary fFlatDictionary;
- int fCurrFlatIndex[kCount_PaintFlats];
+ FlattenableHeap fFlattenableHeap;
+ FlatDictionary fFlatDictionary;
+ SkAutoTUnref<BitmapShuttle> fBitmapShuttle;
+ int fCurrFlatIndex[kCount_PaintFlats];
+
int flattenToIndex(SkFlattenable* obj, PaintFlats);
// Common code used by drawBitmap*. Behaves differently depending on the
@@ -390,24 +423,6 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
///////////////////////////////////////////////////////////////////////////////
-/**
- * If SkBitmaps are to be flattened to send to the reader, this class is
- * provided to the SkBitmapHeap to tell the SkGPipeCanvas to do so.
- */
-class BitmapShuttle : public SkBitmapHeap::ExternalStorage {
-public:
- BitmapShuttle(SkGPipeCanvas*);
-
- ~BitmapShuttle();
-
- virtual bool insert(const SkBitmap& bitmap, int32_t slot) SK_OVERRIDE;
-
-private:
- SkGPipeCanvas* fCanvas;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
#define MIN_BLOCK_SIZE (16 * 1024)
#define BITMAPS_TO_KEEP 5
#define FLATTENABLES_TO_KEEP 10
@@ -440,9 +455,8 @@ SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
}
if (shouldFlattenBitmaps(flags)) {
- BitmapShuttle* shuttle = SkNEW_ARGS(BitmapShuttle, (this));
- fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (shuttle, BITMAPS_TO_KEEP));
- shuttle->unref();
+ fBitmapShuttle.reset(SkNEW_ARGS(BitmapShuttle, (this)));
+ fBitmapHeap = SkNEW_ARGS(SkBitmapHeap, (fBitmapShuttle.get(), BITMAPS_TO_KEEP));
} else {
fBitmapHeap = SkNEW_ARGS(SkBitmapHeap,
(BITMAPS_TO_KEEP, controller->numberOfReaders()));
@@ -456,7 +470,7 @@ SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
}
SkGPipeCanvas::~SkGPipeCanvas() {
- this->finish();
+ this->finish(true);
SkSafeUnref(fFactorySet);
SkSafeUnref(fBitmapHeap);
}
@@ -474,7 +488,8 @@ bool SkGPipeCanvas::needOpBytes(size_t needed) {
size_t blockSize = SkMax32(MIN_BLOCK_SIZE, needed);
void* block = fController->requestBlock(blockSize, &fBlockSize);
if (NULL == block) {
- fDone = true;
+ // Do not notify the readers, which would call this function again.
+ this->finish(false);
return false;
}
SkASSERT(SkIsAlign4(fBlockSize));
@@ -1179,7 +1194,7 @@ SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t
void SkGPipeWriter::endRecording() {
if (fCanvas) {
- fCanvas->finish();
+ fCanvas->finish(true);
fCanvas->unref();
fCanvas = NULL;
}
@@ -1211,9 +1226,18 @@ BitmapShuttle::BitmapShuttle(SkGPipeCanvas* canvas) {
}
BitmapShuttle::~BitmapShuttle() {
- fCanvas->unref();
+ this->removeCanvas();
}
bool BitmapShuttle::insert(const SkBitmap& bitmap, int32_t slot) {
+ SkASSERT(fCanvas != NULL);
return fCanvas->shuttleBitmap(bitmap, slot);
}
+
+void BitmapShuttle::removeCanvas() {
+ if (NULL == fCanvas) {
+ return;
+ }
+ fCanvas->unref();
+ fCanvas = NULL;
+}