From 98b8485a4cc911420e20af2670d21a5478a06264 Mon Sep 17 00:00:00 2001 From: mtklein Date: Tue, 21 Apr 2015 15:23:59 -0700 Subject: [PATCH] O(1) SkPictureUtils::ApproxBytesUsed() Chrome wants to call this more often, and it's quite slow today. Seems like this could be clearer if SkPictureUtils::ApproxBytesUsed() were SkPicture::approxBytesUsed(). BUG=chromium:471873 Review URL: https://codereview.chromium.org/1090943004 --- include/core/SkPicture.h | 9 +++++++-- src/core/SkPicture.cpp | 3 ++- src/core/SkPictureRecorder.cpp | 17 ++++++++++++++--- src/core/SkRecorder.cpp | 7 ++++++- src/core/SkRecorder.h | 4 +++- src/core/SkVarAlloc.cpp | 27 +++++---------------------- src/core/SkVarAlloc.h | 8 +++++--- src/utils/SkPictureUtils.cpp | 12 +----------- tests/PictureTest.cpp | 2 +- 9 files changed, 44 insertions(+), 45 deletions(-) diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index 8a6216e1aa..a565e415eb 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -260,7 +260,11 @@ private: static bool IsValidPictInfo(const SkPictInfo& info); // Takes ownership of the SkRecord and (optional) SnapshotArray, refs the (optional) BBH. - SkPicture(const SkRect& cullRect, SkRecord*, SnapshotArray*, SkBBoxHierarchy*); + SkPicture(const SkRect& cullRect, + SkRecord*, + SnapshotArray*, + SkBBoxHierarchy*, + size_t approxBytesUsedBySubPictures); static SkPicture* Forwardport(const SkPictInfo&, const SkPictureData*); static SkPictureData* Backport(const SkRecord&, const SkPictInfo&, @@ -273,6 +277,7 @@ private: SkAutoTUnref fRecord; SkAutoTUnref fBBH; SkAutoTDelete fDrawablePicts; + const size_t fApproxBytesUsedBySubPictures; // helpers for fDrawablePicts int drawableCount() const; @@ -302,6 +307,6 @@ private: friend class SkPictureUtils; friend class SkRecordedDrawable; }; -SK_COMPILE_ASSERT(sizeof(SkPicture) <= 96, SkPictureSize); +SK_COMPILE_ASSERT(sizeof(SkPicture) <= 104, SkPictureSize); #endif diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index a8ddfe6656..2a33c4db60 100644 --- a/src/core/SkPicture.cpp +++ b/src/core/SkPicture.cpp @@ -480,12 +480,13 @@ bool SkPicture::willPlayBackBitmaps() const { return fAnalysis.fWillPlaybackBitm int SkPicture::approximateOpCount() const { return fRecord->count(); } SkPicture::SkPicture(const SkRect& cullRect, SkRecord* record, SnapshotArray* drawablePicts, - SkBBoxHierarchy* bbh) + SkBBoxHierarchy* bbh, size_t approxBytesUsedBySubPictures) : fUniqueID(0) , fCullRect(cullRect) , fRecord(SkRef(record)) , fBBH(SkSafeRef(bbh)) , fDrawablePicts(drawablePicts) // take ownership + , fApproxBytesUsedBySubPictures(approxBytesUsedBySubPictures) , fAnalysis(*fRecord) {} diff --git a/src/core/SkPictureRecorder.cpp b/src/core/SkPictureRecorder.cpp index f622e66c84..22b1ee3eac 100644 --- a/src/core/SkPictureRecorder.cpp +++ b/src/core/SkPictureRecorder.cpp @@ -9,10 +9,11 @@ #include "SkDrawable.h" #include "SkLayerInfo.h" #include "SkPictureRecorder.h" +#include "SkPictureUtils.h" #include "SkRecord.h" #include "SkRecordDraw.h" -#include "SkRecorder.h" #include "SkRecordOpts.h" +#include "SkRecorder.h" #include "SkTypes.h" SkPictureRecorder::SkPictureRecorder() { @@ -72,7 +73,12 @@ SkPicture* SkPictureRecorder::endRecordingAsPicture() { fCullRect = bbhBound; } - SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullRect, fRecord, pictList, fBBH)); + size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures(); + for (int i = 0; pictList && i < pictList->count(); i++) { + subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]); + } + SkPicture* pict = + SkNEW_ARGS(SkPicture, (fCullRect, fRecord, pictList, fBBH, subPictureBytes)); if (saveLayerData) { pict->EXPERIMENTAL_addAccelData(saveLayerData); @@ -153,7 +159,12 @@ protected: SkRecordComputeLayers(fBounds, *fRecord, pictList, bbh, saveLayerData); } - SkPicture* pict = SkNEW_ARGS(SkPicture, (fBounds, fRecord, pictList, fBBH)); + size_t subPictureBytes = 0; + for (int i = 0; pictList && i < pictList->count(); i++) { + subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]); + } + SkPicture* pict = + SkNEW_ARGS(SkPicture, (fBounds, fRecord, pictList, fBBH, subPictureBytes)); if (saveLayerData) { pict->EXPERIMENTAL_addAccelData(saveLayerData); diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp index 8684a8e2eb..0a2d43edbf 100644 --- a/src/core/SkRecorder.cpp +++ b/src/core/SkRecorder.cpp @@ -5,9 +5,10 @@ * found in the LICENSE file. */ -#include "SkRecorder.h" #include "SkPatchUtils.h" #include "SkPicture.h" +#include "SkPictureUtils.h" +#include "SkRecorder.h" SkDrawableList::~SkDrawableList() { fArray.unrefAll(); @@ -33,10 +34,12 @@ void SkDrawableList::append(SkDrawable* drawable) { SkRecorder::SkRecorder(SkRecord* record, int width, int height) : SkCanvas(SkIRect::MakeWH(width, height), SkCanvas::kConservativeRasterClip_InitFlag) + , fApproxBytesUsedBySubPictures(0) , fRecord(record) {} SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds) : SkCanvas(bounds.roundOut(), SkCanvas::kConservativeRasterClip_InitFlag) + , fApproxBytesUsedBySubPictures(0) , fRecord(record) {} void SkRecorder::reset(SkRecord* record, const SkRect& bounds) { @@ -47,6 +50,7 @@ void SkRecorder::reset(SkRecord* record, const SkRect& bounds) { void SkRecorder::forgetRecord() { fDrawableList.reset(NULL); + fApproxBytesUsedBySubPictures = 0; fRecord = NULL; } @@ -248,6 +252,7 @@ void SkRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, } void SkRecorder::onDrawPicture(const SkPicture* pic, const SkMatrix* matrix, const SkPaint* paint) { + fApproxBytesUsedBySubPictures += SkPictureUtils::ApproximateBytesUsed(pic); APPEND(DrawPicture, this->copy(paint), pic, matrix ? *matrix : SkMatrix::I()); } diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h index 6842aece58..d0a992fc08 100644 --- a/src/core/SkRecorder.h +++ b/src/core/SkRecorder.h @@ -41,6 +41,8 @@ public: void reset(SkRecord*, const SkRect& bounds); + size_t approxBytesUsedBySubPictures() const { return fApproxBytesUsedBySubPictures; } + SkDrawableList* getDrawableList() const { return fDrawableList.get(); } SkDrawableList* detachDrawableList() { return fDrawableList.detach(); } @@ -131,8 +133,8 @@ private: return devBounds; } + size_t fApproxBytesUsedBySubPictures; SkRecord* fRecord; - SkAutoTDelete fDrawableList; }; diff --git a/src/core/SkVarAlloc.cpp b/src/core/SkVarAlloc.cpp index fa89d38c23..5d395d4841 100644 --- a/src/core/SkVarAlloc.cpp +++ b/src/core/SkVarAlloc.cpp @@ -27,13 +27,15 @@ struct SkVarAlloc::Block { }; SkVarAlloc::SkVarAlloc(size_t minLgSize) - : fByte(NULL) + : fBytesAllocated(0) + , fByte(NULL) , fRemaining(0) , fLgSize(minLgSize) , fBlock(NULL) {} SkVarAlloc::SkVarAlloc(size_t minLgSize, char* storage, size_t len) - : fByte(storage) + : fBytesAllocated(0) + , fByte(storage) , fRemaining(len) , fLgSize(minLgSize) , fBlock(NULL) {} @@ -54,6 +56,7 @@ void SkVarAlloc::makeSpace(size_t bytes, unsigned flags) { while (alloc < bytes + sizeof(Block)) { alloc *= 2; } + fBytesAllocated += alloc; fBlock = Block::Alloc(fBlock, alloc, flags); fByte = fBlock->data(); fRemaining = alloc - sizeof(Block); @@ -65,23 +68,3 @@ void SkVarAlloc::makeSpace(size_t bytes, unsigned flags) { //SkASSERT(alloc == malloc_usable_size(fBlock)); #endif } - -static size_t heap_size(void* p) { -#if defined(SK_BUILD_FOR_MAC) - return malloc_size(p); -#elif defined(SK_BUILD_FOR_UNIX) && !defined(__UCLIBC__) - return malloc_usable_size(p); -#elif defined(SK_BUILD_FOR_WIN32) - return _msize(p); -#else - return 0; // Tough luck. -#endif -} - -size_t SkVarAlloc::approxBytesAllocated() const { - size_t sum = 0; - for (Block* b = fBlock; b; b = b->prev) { - sum += heap_size(b); - } - return sum; -} diff --git a/src/core/SkVarAlloc.h b/src/core/SkVarAlloc.h index 8a55b36615..e8236cf992 100644 --- a/src/core/SkVarAlloc.h +++ b/src/core/SkVarAlloc.h @@ -35,12 +35,14 @@ public: } // Returns our best estimate of the number of bytes we've allocated. - // (We intentionally do not track this precisely to save space.) - size_t approxBytesAllocated() const; + // (We may not track this precisely to save space.) + size_t approxBytesAllocated() const { return fBytesAllocated; } private: void makeSpace(size_t bytes, unsigned flags); + size_t fBytesAllocated; + char* fByte; unsigned fRemaining; unsigned fLgSize; @@ -48,6 +50,6 @@ private: struct Block; Block* fBlock; }; -SK_COMPILE_ASSERT(sizeof(SkVarAlloc) <= 24, SkVarAllocSize); +SK_COMPILE_ASSERT(sizeof(SkVarAlloc) <= 32, SkVarAllocSize); #endif//SkVarAlloc_DEFINED diff --git a/src/utils/SkPictureUtils.cpp b/src/utils/SkPictureUtils.cpp index be7c431946..a8a251c927 100644 --- a/src/utils/SkPictureUtils.cpp +++ b/src/utils/SkPictureUtils.cpp @@ -12,13 +12,6 @@ #include "SkRecord.h" #include "SkShader.h" -struct MeasureRecords { - template size_t operator()(const T& op) { return 0; } - size_t operator()(const SkRecords::DrawPicture& op) { - return SkPictureUtils::ApproximateBytesUsed(op.picture); - } -}; - size_t SkPictureUtils::ApproximateBytesUsed(const SkPicture* pict) { size_t byteCount = sizeof(*pict); @@ -26,10 +19,7 @@ size_t SkPictureUtils::ApproximateBytesUsed(const SkPicture* pict) { if (pict->fBBH.get()) { byteCount += pict->fBBH->bytesUsed(); } - MeasureRecords visitor; - for (unsigned curOp = 0; curOp < pict->fRecord->count(); curOp++) { - byteCount += pict->fRecord->visit(curOp, visitor); - } + byteCount += pict->fApproxBytesUsedBySubPictures; return byteCount; } diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp index 2fe6e47ab5..4fe08379dd 100644 --- a/tests/PictureTest.cpp +++ b/tests/PictureTest.cpp @@ -1119,7 +1119,7 @@ static void test_bytes_used(skiatest::Reporter* reporter) { // Protect against any unintentional bloat. size_t approxUsed = SkPictureUtils::ApproximateBytesUsed(empty.get()); - REPORTER_ASSERT(reporter, approxUsed <= 416); + REPORTER_ASSERT(reporter, approxUsed <= 432); // Sanity check of nested SkPictures. SkPictureRecorder r2;