Make SkDeferredCanvas query SkGPipeWriter for space allocated for bitmaps.
SkGPipe now has a method to report how much memory is used for its shared heap. BUG=http://code.google.com/p/skia/issues/detail?id=738 TEST=DeferredCanvasTest Review URL: https://codereview.appspot.com/6445046 git-svn-id: http://skia.googlecode.com/svn/trunk@4791 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
1c31f63323
commit
15011ee5e4
@ -629,7 +629,7 @@ static PipeFlagComboData gPipeWritingFlagCombos[] = {
|
||||
{ "", 0 },
|
||||
{ " cross-process", SkGPipeWriter::kCrossProcess_Flag },
|
||||
{ " cross-process, shared address", SkGPipeWriter::kCrossProcess_Flag
|
||||
| SkGPipeWriter::kSharedAddressSpace_SkGPipeFlag }
|
||||
| SkGPipeWriter::kSharedAddressSpace_Flag }
|
||||
};
|
||||
|
||||
static ErrorBitfield test_pipe_playback(GM* gm,
|
||||
|
@ -89,7 +89,7 @@ public:
|
||||
* in spite of being cross process, it will have shared address space
|
||||
* with the reader, so the two can share large objects (like SkBitmaps)
|
||||
*/
|
||||
kSharedAddressSpace_SkGPipeFlag = 1 << 1
|
||||
kSharedAddressSpace_Flag = 1 << 1
|
||||
};
|
||||
|
||||
SkCanvas* startRecording(SkGPipeController*, uint32_t flags = 0);
|
||||
@ -106,9 +106,17 @@ public:
|
||||
*/
|
||||
void flushRecording(bool detachCurrentBlock);
|
||||
|
||||
/**
|
||||
* Return the amount of bytes being used for recording. Note that this
|
||||
* does not include the amount of storage written to the stream, which is
|
||||
* controlled by the SkGPipeController.
|
||||
* Currently only returns the amount used for SkBitmaps, since they are
|
||||
* potentially unbounded (if the client is not calling playback).
|
||||
*/
|
||||
size_t storageAllocatedForRecording();
|
||||
|
||||
private:
|
||||
class SkGPipeCanvas* fCanvas;
|
||||
SkGPipeController* fController;
|
||||
SkFactorySet fFactorySet;
|
||||
SkWriter32 fWriter;
|
||||
};
|
||||
|
@ -245,12 +245,6 @@ public:
|
||||
void contentsCleared();
|
||||
void setMaxRecordingStorage(size_t);
|
||||
|
||||
// FIXME: Temporary solution for tracking memory usage, pending
|
||||
// resolution of http://code.google.com/p/skia/issues/detail?id=738
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
void accountForTempBitmapStorage(const SkBitmap& bitmap);
|
||||
#endif
|
||||
|
||||
virtual uint32_t getDeviceCapabilities() SK_OVERRIDE;
|
||||
virtual int width() const SK_OVERRIDE;
|
||||
virtual int height() const SK_OVERRIDE;
|
||||
@ -339,9 +333,6 @@ public:
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
DeferredPipeController fPipeController;
|
||||
SkGPipeWriter fPipeWriter;
|
||||
// FIXME: Temporary solution for tracking memory usage, pending
|
||||
// resolution of http://code.google.com/p/skia/issues/detail?id=738
|
||||
size_t fTempBitmapStorage;
|
||||
#else
|
||||
SkPicture fPicture;
|
||||
#endif
|
||||
@ -359,13 +350,6 @@ protected:
|
||||
virtual SkCanvas* canvasForDrawIter();
|
||||
|
||||
private:
|
||||
// FIXME: Temporary solution for tracking memory usage, pending
|
||||
// resolution of http://code.google.com/p/skia/issues/detail?id=738
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
friend class AutoImmediateDrawIfNeeded;
|
||||
void accountForTempBitmapStorage(const SkBitmap& bitmap) const;
|
||||
#endif
|
||||
|
||||
SkCanvas* drawingCanvas() const;
|
||||
bool isFullFrame(const SkRect*, const SkPaint*) const;
|
||||
void validate() const;
|
||||
|
@ -144,6 +144,7 @@ public:
|
||||
BitmapInfo(SkBitmap* bitmap, uint32_t genID, int toBeDrawnCount)
|
||||
: fBitmap(bitmap)
|
||||
, fGenID(genID)
|
||||
, fBytesAllocated(0)
|
||||
, fMoreRecentlyUsed(NULL)
|
||||
, fLessRecentlyUsed(NULL)
|
||||
, fToBeDrawnCount(toBeDrawnCount)
|
||||
@ -177,7 +178,13 @@ public:
|
||||
// Store the generation ID of the original bitmap, since copying does
|
||||
// not copy this field, so fBitmap's generation ID will not be useful
|
||||
// for comparing.
|
||||
// FIXME: Is it reasonable to make copying a bitmap/pixelref copy the
|
||||
// generation ID?
|
||||
uint32_t fGenID;
|
||||
// Keep track of the bytes allocated for this bitmap. When replacing the
|
||||
// bitmap or removing this BitmapInfo we know how much memory has been
|
||||
// reclaimed.
|
||||
size_t fBytesAllocated;
|
||||
// TODO: Generalize the LRU caching mechanism
|
||||
BitmapInfo* fMoreRecentlyUsed;
|
||||
BitmapInfo* fLessRecentlyUsed;
|
||||
@ -187,7 +194,7 @@ private:
|
||||
|
||||
static inline bool shouldFlattenBitmaps(uint32_t flags) {
|
||||
return flags & SkGPipeWriter::kCrossProcess_Flag
|
||||
&& !(flags & SkGPipeWriter::kSharedAddressSpace_SkGPipeFlag);
|
||||
&& !(flags & SkGPipeWriter::kSharedAddressSpace_Flag);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -161,18 +161,31 @@ public:
|
||||
, fMostRecentlyUsed(NULL)
|
||||
, fLeastRecentlyUsed(NULL)
|
||||
, fCanDoShallowCopies(shallow)
|
||||
, fNumberOfReaders(numOfReaders) {}
|
||||
, fNumberOfReaders(numOfReaders)
|
||||
, fBytesAllocated(0) {}
|
||||
~SharedHeap() {
|
||||
BitmapInfo* iter = fMostRecentlyUsed;
|
||||
while (iter != NULL) {
|
||||
SkDEBUGCODE(fBytesAllocated -= (iter->fBytesAllocated + sizeof(BitmapInfo)));
|
||||
BitmapInfo* next = iter->fLessRecentlyUsed;
|
||||
SkDELETE(iter);
|
||||
fBitmapCount--;
|
||||
iter = next;
|
||||
}
|
||||
SkASSERT(0 == fBitmapCount);
|
||||
SkASSERT(0 == fBytesAllocated);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the approximate number of bytes allocated.
|
||||
*
|
||||
* Not exact. Some SkBitmaps may share SkPixelRefs, in which case only one
|
||||
* SkBitmap will take the size of the SkPixelRef into account (the first
|
||||
* one). It is possible that the one which accounts for the SkPixelRef has
|
||||
* been removed, in which case we will no longer be counting those bytes.
|
||||
*/
|
||||
size_t bytesAllocated() { return fBytesAllocated; }
|
||||
|
||||
/*
|
||||
* Add a copy of a bitmap to the heap.
|
||||
* @param bm The SkBitmap to be copied and placed in the heap.
|
||||
@ -190,6 +203,10 @@ public:
|
||||
while (iter != NULL) {
|
||||
if (genID == iter->fGenID) {
|
||||
SkBitmap* storedBitmap = iter->fBitmap;
|
||||
// TODO: Perhaps we can share code with
|
||||
// SkPictureRecord::PixelRefDictionaryEntry/
|
||||
// BitmapIndexCacheEntry so we can do a binary search for a
|
||||
// matching bitmap
|
||||
if (orig.pixelRefOffset() != storedBitmap->pixelRefOffset()
|
||||
|| orig.width() != storedBitmap->width()
|
||||
|| orig.height() != storedBitmap->height()) {
|
||||
@ -246,13 +263,23 @@ public:
|
||||
}
|
||||
BitmapInfo* info;
|
||||
if (NULL == replace) {
|
||||
fBytesAllocated += sizeof(BitmapInfo);
|
||||
info = SkNEW_ARGS(BitmapInfo, (copy, genID, fNumberOfReaders));
|
||||
fBitmapCount++;
|
||||
} else {
|
||||
fBytesAllocated -= replace->fBytesAllocated;
|
||||
replace->fGenID = genID;
|
||||
replace->addDraws(fNumberOfReaders);
|
||||
info = replace;
|
||||
}
|
||||
// Always include the size of the SkBitmap struct.
|
||||
info->fBytesAllocated = sizeof(SkBitmap);
|
||||
// If the SkBitmap does not share an SkPixelRef with an SkBitmap already
|
||||
// in the SharedHeap, also include the size of its pixels.
|
||||
if (NULL == sharedPixelRef) {
|
||||
info->fBytesAllocated += orig.getSize();
|
||||
}
|
||||
fBytesAllocated += info->fBytesAllocated;
|
||||
this->setMostRecentlyUsed(info);
|
||||
return info;
|
||||
}
|
||||
@ -265,6 +292,7 @@ private:
|
||||
BitmapInfo* fMostRecentlyUsed;
|
||||
const bool fCanDoShallowCopies;
|
||||
const int fNumberOfReaders;
|
||||
size_t fBytesAllocated;
|
||||
};
|
||||
|
||||
// We just "used" info. Update our LRU accordingly
|
||||
@ -352,6 +380,10 @@ public:
|
||||
|
||||
void flushRecording(bool detachCurrentBlock);
|
||||
|
||||
size_t storageAllocatedForRecording() {
|
||||
return fSharedHeap.bytesAllocated();
|
||||
}
|
||||
|
||||
// overrides from SkCanvas
|
||||
virtual int save(SaveFlags) SK_OVERRIDE;
|
||||
virtual int saveLayer(const SkRect* bounds, const SkPaint*,
|
||||
@ -1251,3 +1283,7 @@ void SkGPipeWriter::flushRecording(bool detachCurrentBlock){
|
||||
fCanvas->flushRecording(detachCurrentBlock);
|
||||
}
|
||||
|
||||
size_t SkGPipeWriter::storageAllocatedForRecording() {
|
||||
return NULL == fCanvas ? 0 : fCanvas->storageAllocatedForRecording();
|
||||
}
|
||||
|
||||
|
@ -35,13 +35,6 @@ public:
|
||||
} else {
|
||||
fCanvas = NULL;
|
||||
}
|
||||
// FIXME: Temporary solution for tracking memory usage, pending
|
||||
// resolution of http://code.google.com/p/skia/issues/detail?id=738
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
if (canvas.isDeferredDrawing()) {
|
||||
canvas.accountForTempBitmapStorage(bitmap);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
~AutoImmediateDrawIfNeeded() {
|
||||
@ -143,16 +136,6 @@ void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) {
|
||||
this->getDeferredDevice()->setMaxRecordingStorage(maxStorage);
|
||||
}
|
||||
|
||||
// FIXME: Temporary solution for tracking memory usage, pending
|
||||
// resolution of http://code.google.com/p/skia/issues/detail?id=738
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
void SkDeferredCanvas::accountForTempBitmapStorage(const SkBitmap& bitmap) const {
|
||||
if (fDeferredDrawing) {
|
||||
this->getDeferredDevice()->accountForTempBitmapStorage(bitmap);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void SkDeferredCanvas::validate() const {
|
||||
SkASSERT(getDevice());
|
||||
}
|
||||
@ -563,7 +546,6 @@ SkDeferredCanvas::DeferredDevice::DeferredDevice(
|
||||
fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
fPipeController.setPlaybackCanvas(fImmediateCanvas);
|
||||
fTempBitmapStorage = 0;
|
||||
#endif
|
||||
beginRecording();
|
||||
}
|
||||
@ -579,26 +561,10 @@ void SkDeferredCanvas::DeferredDevice::setMaxRecordingStorage(size_t maxStorage)
|
||||
recordingCanvas(); // Accessing the recording canvas applies the new limit.
|
||||
}
|
||||
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
void SkDeferredCanvas::DeferredDevice::accountForTempBitmapStorage(const SkBitmap& bitmap) {
|
||||
// SkGPipe will store copies of mutable bitmaps. The memory allocations
|
||||
// and deallocations for these bitmaps are not tracked by the writer or
|
||||
// the controller, so we do as best we can to track consumption here
|
||||
if (!bitmap.isImmutable()) {
|
||||
// FIXME: Temporary solution for tracking memory usage, pending
|
||||
// resolution of http://code.google.com/p/skia/issues/detail?id=738
|
||||
// This does not take into account duplicates of previously
|
||||
// copied bitmaps that will not get copied again.
|
||||
fTempBitmapStorage += bitmap.getSize();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void SkDeferredCanvas::DeferredDevice::endRecording() {
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
fPipeWriter.endRecording();
|
||||
fPipeController.reset();
|
||||
fTempBitmapStorage = 0;
|
||||
#else
|
||||
fPicture.endRecording();
|
||||
#endif
|
||||
@ -607,7 +573,6 @@ void SkDeferredCanvas::DeferredDevice::endRecording() {
|
||||
|
||||
void SkDeferredCanvas::DeferredDevice::beginRecording() {
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
SkASSERT(0 == fTempBitmapStorage);
|
||||
fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0);
|
||||
#else
|
||||
fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
|
||||
@ -679,7 +644,6 @@ void SkDeferredCanvas::DeferredDevice::flushPending() {
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
fPipeWriter.flushRecording(true);
|
||||
fPipeController.playback();
|
||||
fTempBitmapStorage = 0;
|
||||
#else
|
||||
fPicture.draw(fImmediateCanvas);
|
||||
this->beginRecording();
|
||||
@ -693,8 +657,9 @@ void SkDeferredCanvas::DeferredDevice::flush() {
|
||||
|
||||
SkCanvas* SkDeferredCanvas::DeferredDevice::recordingCanvas() {
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
if (fPipeController.storageAllocatedForRecording() + fTempBitmapStorage >
|
||||
fMaxRecordingStorageBytes) {
|
||||
if (fPipeController.storageAllocatedForRecording()
|
||||
+ fPipeWriter.storageAllocatedForRecording()
|
||||
> fMaxRecordingStorageBytes) {
|
||||
this->flushPending();
|
||||
}
|
||||
#endif
|
||||
@ -741,11 +706,6 @@ void SkDeferredCanvas::DeferredDevice::writePixels(const SkBitmap& bitmap,
|
||||
this->flushPending();
|
||||
fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
|
||||
} else {
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
// FIXME: Temporary solution for tracking memory usage, pending
|
||||
// resolution of http://code.google.com/p/skia/issues/detail?id=738
|
||||
this->accountForTempBitmapStorage(bitmap);
|
||||
#endif
|
||||
recordingCanvas()->drawSprite(bitmap, x, y, &paint);
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ static void TestDeferredCanvasMemoryLimit(skiatest::Reporter* reporter) {
|
||||
|
||||
// SkPicture path is not fixed
|
||||
#if SK_DEFERRED_CANVAS_USES_GPIPE
|
||||
REPORTER_ASSERT(reporter, mockDevice.fDrawBitmapCallCount == 3);
|
||||
REPORTER_ASSERT(reporter, mockDevice.fDrawBitmapCallCount == 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user