diff options
-rw-r--r-- | gyp/core.gyp | 2 | ||||
-rw-r--r-- | gyp/effects.gyp | 1 | ||||
-rw-r--r-- | include/core/SkBitmap.h | 7 | ||||
-rw-r--r-- | include/core/SkFlattenableBuffers.h | 2 | ||||
-rw-r--r-- | include/core/SkOrderedReadBuffer.h | 14 | ||||
-rw-r--r-- | include/core/SkOrderedWriteBuffer.h | 12 | ||||
-rw-r--r-- | src/core/SkBitmap.cpp | 42 | ||||
-rw-r--r-- | src/core/SkBitmapHeap.cpp | 258 | ||||
-rw-r--r-- | src/core/SkBitmapHeap.h | 248 | ||||
-rw-r--r-- | src/core/SkFlattenableBuffers.cpp | 12 | ||||
-rw-r--r-- | src/core/SkOrderedReadBuffer.cpp | 40 | ||||
-rw-r--r-- | src/core/SkOrderedWriteBuffer.cpp | 24 | ||||
-rw-r--r-- | src/core/SkPictureFlat.cpp | 33 | ||||
-rw-r--r-- | src/core/SkPictureFlat.h | 74 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.cpp | 17 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.h | 4 | ||||
-rw-r--r-- | src/core/SkPictureRecord.cpp | 65 | ||||
-rw-r--r-- | src/core/SkPictureRecord.h | 43 | ||||
-rw-r--r-- | tests/CanvasTest.cpp | 9 |
19 files changed, 621 insertions, 286 deletions
diff --git a/gyp/core.gyp b/gyp/core.gyp index 6af2a57e4e..49b2b85bd7 100644 --- a/gyp/core.gyp +++ b/gyp/core.gyp @@ -14,6 +14,8 @@ '../src/core/SkAlphaRuns.cpp', '../src/core/SkAntiRun.h', '../src/core/SkBitmap.cpp', + '../src/core/SkBitmapHeap.cpp', + '../src/core/SkBitmapHeap.h', '../src/core/SkBitmapProcShader.cpp', '../src/core/SkBitmapProcShader.h', '../src/core/SkBitmapProcState.cpp', diff --git a/gyp/effects.gyp b/gyp/effects.gyp index 0a9e8d7d57..86308b767e 100644 --- a/gyp/effects.gyp +++ b/gyp/effects.gyp @@ -5,6 +5,7 @@ 'type': 'static_library', 'include_dirs': [ '../include/effects', + '../src/core', ], 'sources': [ '../include/effects/Sk1DPathEffect.h', diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index b4f86eaee7..eba3e0b087 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -548,6 +548,13 @@ public: bool extractAlpha(SkBitmap* dst, const SkPaint* paint, Allocator* allocator, SkIPoint* offset) const; + /** The following two functions provide the means to both flatten and + unflatten the bitmap AND its pixels into the provided buffer. + It is recommended that you do not call these functions directly, + but instead call the write/readBitmap functions on the respective + buffers as they can optimize the recording process and avoid recording + duplicate bitmaps and pixelRefs. + */ void flatten(SkFlattenableWriteBuffer&) const; void unflatten(SkFlattenableReadBuffer&); diff --git a/include/core/SkFlattenableBuffers.h b/include/core/SkFlattenableBuffers.h index d87539ec8e..6137724333 100644 --- a/include/core/SkFlattenableBuffers.h +++ b/include/core/SkFlattenableBuffers.h @@ -87,7 +87,6 @@ public: // helper functions virtual void* readFunctionPtr(); virtual void readPaint(SkPaint* paint); - virtual SkRefCnt* readRefCntPtr(); virtual void readBitmap(SkBitmap* bitmap) = 0; virtual SkTypeface* readTypeface() = 0; @@ -147,7 +146,6 @@ public: // helper functions virtual void writeFunctionPtr(void* ptr); virtual void writePaint(const SkPaint& paint); - virtual void writeRefCntPtr(SkRefCnt* refCnt); virtual void writeBitmap(const SkBitmap& bitmap) = 0; virtual void writeTypeface(SkTypeface* typeface) = 0; diff --git a/include/core/SkOrderedReadBuffer.h b/include/core/SkOrderedReadBuffer.h index 5651e7c1e7..8462b7f89d 100644 --- a/include/core/SkOrderedReadBuffer.h +++ b/include/core/SkOrderedReadBuffer.h @@ -11,13 +11,14 @@ #include "SkRefCnt.h" #include "SkBitmap.h" +#include "SkBitmapHeap.h" #include "SkFlattenableBuffers.h" #include "SkReader32.h" #include "SkPath.h" class SkOrderedReadBuffer : public SkFlattenableReadBuffer { public: - SkOrderedReadBuffer() : INHERITED() {} + SkOrderedReadBuffer(); SkOrderedReadBuffer(const void* data, size_t size); SkOrderedReadBuffer(SkStream* stream); virtual ~SkOrderedReadBuffer(); @@ -63,14 +64,11 @@ public: // helpers to get info about arrays and binary data virtual uint32_t getArrayCount() SK_OVERRIDE; - virtual SkRefCnt* readRefCntPtr() SK_OVERRIDE; - virtual void readBitmap(SkBitmap* bitmap) SK_OVERRIDE; virtual SkTypeface* readTypeface() SK_OVERRIDE; - void setRefCntArray(SkRefCnt* array[], int count) { - fRCArray = array; - fRCCount = count; + void setBitmapStorage(SkBitmapHeapReader* bitmapStorage) { + SkRefCnt_SafeAssign(fBitmapStorage, bitmapStorage); } void setTypefaceArray(SkTypeface* array[], int count) { @@ -103,9 +101,7 @@ private: SkReader32 fReader; void* fMemoryPtr; - SkRefCnt** fRCArray; - int fRCCount; - + SkBitmapHeapReader* fBitmapStorage; SkTypeface** fTFArray; int fTFCount; diff --git a/include/core/SkOrderedWriteBuffer.h b/include/core/SkOrderedWriteBuffer.h index 8cd2d810f1..7be2a90bc3 100644 --- a/include/core/SkOrderedWriteBuffer.h +++ b/include/core/SkOrderedWriteBuffer.h @@ -13,6 +13,7 @@ #include "SkRefCnt.h" #include "SkBitmap.h" +#include "SkBitmapHeap.h" #include "SkPath.h" #include "SkWriter32.h" @@ -59,8 +60,6 @@ public: virtual void writePath(const SkPath& path) SK_OVERRIDE; virtual size_t writeStream(SkStream* stream, size_t length) SK_OVERRIDE; - virtual void writeRefCntPtr(SkRefCnt* refCnt) SK_OVERRIDE; - virtual void writeBitmap(const SkBitmap& bitmap) SK_OVERRIDE; virtual void writeTypeface(SkTypeface* typeface) SK_OVERRIDE; @@ -72,16 +71,17 @@ public: SkRefCntSet* getTypefaceRecorder() const { return fTFSet; } SkRefCntSet* setTypefaceRecorder(SkRefCntSet*); - SkRefCntSet* getRefCntRecorder() const { return fRCSet; } - SkRefCntSet* setRefCntRecorder(SkRefCntSet*); + void setBitmapHeap(SkBitmapHeap* bitmapHeap) { + SkRefCnt_SafeAssign(fBitmapHeap, bitmapHeap); + } private: SkFactorySet* fFactorySet; SkNamedFactorySet* fNamedFactorySet; SkWriter32 fWriter; - SkRefCntSet* fRCSet; - SkRefCntSet* fTFSet; + SkBitmapHeap* fBitmapHeap; + SkRefCntSet* fTFSet; typedef SkFlattenableWriteBuffer INHERITED; }; diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index 70060f2901..e59c506983 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -1365,21 +1365,9 @@ bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, enum { SERIALIZE_PIXELTYPE_NONE, - SERIALIZE_PIXELTYPE_REF_DATA, - SERIALIZE_PIXELTYPE_REF_PTR + SERIALIZE_PIXELTYPE_REF_DATA }; -/* - It is tricky to know how much to flatten. If we don't have a pixelref (i.e. - we just have pixels, then we can only flatten the pixels, or write out an - empty bitmap. - - With a pixelref, we still have the question of recognizing when two sitings - of the same pixelref are the same, and when they are different. Perhaps we - should look at the generationID and keep a record of that in some dictionary - associated with the buffer. SkGLTextureCache does this sort of thing to know - when to create a new texture. -*/ void SkBitmap::flatten(SkFlattenableWriteBuffer& buffer) const { buffer.writeInt(fWidth); buffer.writeInt(fHeight); @@ -1387,26 +1375,6 @@ void SkBitmap::flatten(SkFlattenableWriteBuffer& buffer) const { buffer.writeInt(fConfig); buffer.writeBool(this->isOpaque()); - /* If we are called in this mode, then it is up to the caller to manage - the owner-counts on the pixelref, as we just record the ptr itself. - */ - if (!buffer.persistBitmapPixels()) { - if (fPixelRef) { - buffer.writeInt(SERIALIZE_PIXELTYPE_REF_PTR); - buffer.writeUInt(fPixelRefOffset); - buffer.writeRefCntPtr(fPixelRef); - return; - } else { - // we ignore the non-persist request, since we don't have a ref - // ... or we could just write an empty bitmap... - // (true) will write an empty bitmap, (false) will flatten the pix - if (true) { - buffer.writeInt(SERIALIZE_PIXELTYPE_NONE); - return; - } - } - } - if (fPixelRef) { if (fPixelRef->getFactory()) { buffer.writeInt(SERIALIZE_PIXELTYPE_REF_DATA); @@ -1434,12 +1402,6 @@ void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) { int reftype = buffer.readInt(); switch (reftype) { - case SERIALIZE_PIXELTYPE_REF_PTR: { - size_t offset = buffer.readUInt(); - SkPixelRef* pr = (SkPixelRef*)buffer.readRefCntPtr(); - this->setPixelRef(pr, offset); - break; - } case SERIALIZE_PIXELTYPE_REF_DATA: { size_t offset = buffer.readUInt(); SkPixelRef* pr = buffer.readFlattenableT<SkPixelRef>(); @@ -1472,7 +1434,7 @@ SkBitmap::RLEPixels::~RLEPixels() { void SkBitmap::validate() const { SkASSERT(fConfig < kConfigCount); SkASSERT(fRowBytes >= (unsigned)ComputeRowBytes((Config)fConfig, fWidth)); - SkASSERT(fFlags <= (kImageIsOpaque_Flag | kImageIsVolatile_Flag)); + SkASSERT(fFlags <= (kImageIsOpaque_Flag | kImageIsVolatile_Flag | kImageIsImmutable_Flag)); SkASSERT(fPixelLockCount >= 0); SkASSERT(NULL == fColorTable || (unsigned)fColorTable->getRefCnt() < 10000); SkASSERT((uint8_t)ComputeBytesPerPixel((Config)fConfig) == fBytesPerPixel); diff --git a/src/core/SkBitmapHeap.cpp b/src/core/SkBitmapHeap.cpp new file mode 100644 index 0000000000..7cff8eaace --- /dev/null +++ b/src/core/SkBitmapHeap.cpp @@ -0,0 +1,258 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkBitmapHeap.h" + +#include "SkBitmap.h" +#include "SkFlattenableBuffers.h" +#include "SkTSearch.h" + +SkBitmapHeapEntry::SkBitmapHeapEntry() + : fSlot(-1) + , fRefCount(0) + , fBytesAllocated(0) + , fMoreRecentlyUsed(NULL) + , fLessRecentlyUsed(NULL) { +} + +SkBitmapHeapEntry::~SkBitmapHeapEntry() { + SkASSERT(0 == fRefCount); +} + +void SkBitmapHeapEntry::addReferences(int count) { + if (0 == fRefCount) { + // If there are no current owners then the heap manager + // will be the only one able to modify it, so it does not + // need to be an atomic operation. + fRefCount = count; + } else { + sk_atomic_add(&fRefCount, count); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +SkBitmapHeap::SkBitmapHeap(int32_t preferredSize, int32_t ownerCount) + : INHERITED() + , fExternalStorage(NULL) + , fMostRecentlyUsed(NULL) + , fLeastRecentlyUsed(NULL) + , fPreferredCount(preferredSize) + , fOwnerCount(ownerCount) + , fBytesAllocated(0) { +} + +SkBitmapHeap::SkBitmapHeap(ExternalStorage* storage, int32_t preferredSize) + : INHERITED() + , fExternalStorage(storage) + , fMostRecentlyUsed(NULL) + , fLeastRecentlyUsed(NULL) + , fPreferredCount(preferredSize) + , fOwnerCount(IGNORE_OWNERS) + , fBytesAllocated(0) { +} + +SkBitmapHeap::~SkBitmapHeap() { + fStorage.deleteAll(); + SkSafeUnref(fExternalStorage); +} + +SkTRefArray<SkBitmap>* SkBitmapHeap::extractBitmaps() const { + const int size = fStorage.count(); + SkTRefArray<SkBitmap>* array = NULL; + if (size > 0) { + array = SkTRefArray<SkBitmap>::Create(size); + for (int i = 0; i < size; i++) { + // make a shallow copy of the bitmap + array->writableAt(i) = fStorage[i]->fBitmap; + } + } + return array; +} + +// We just "used" the entry. Update our LRU accordingly +void SkBitmapHeap::setMostRecentlyUsed(SkBitmapHeapEntry* entry) { + SkASSERT(entry != NULL); + if (entry == fMostRecentlyUsed) { + return; + } + // Remove info from its prior place, and make sure to cover the hole. + if (fLeastRecentlyUsed == entry) { + SkASSERT(entry->fMoreRecentlyUsed != NULL); + fLeastRecentlyUsed = entry->fMoreRecentlyUsed; + } + if (entry->fMoreRecentlyUsed != NULL) { + SkASSERT(fMostRecentlyUsed != entry); + entry->fMoreRecentlyUsed->fLessRecentlyUsed = entry->fLessRecentlyUsed; + } + if (entry->fLessRecentlyUsed != NULL) { + SkASSERT(fLeastRecentlyUsed != entry); + entry->fLessRecentlyUsed->fMoreRecentlyUsed = entry->fMoreRecentlyUsed; + } + entry->fMoreRecentlyUsed = NULL; + // Set up the head and tail pointers properly. + if (fMostRecentlyUsed != NULL) { + SkASSERT(NULL == fMostRecentlyUsed->fMoreRecentlyUsed); + fMostRecentlyUsed->fMoreRecentlyUsed = entry; + entry->fLessRecentlyUsed = fMostRecentlyUsed; + } + fMostRecentlyUsed = entry; + if (NULL == fLeastRecentlyUsed) { + fLeastRecentlyUsed = entry; + } +} + +// iterate through our LRU cache and try to find an entry to evict +SkBitmapHeapEntry* SkBitmapHeap::findEntryToReplace(const SkBitmap& replacement) { + SkASSERT(fPreferredCount != UNLIMITED_SIZE); + SkASSERT(fStorage.count() >= fPreferredCount); + + SkBitmapHeapEntry* iter = fLeastRecentlyUsed; + while (iter != NULL) { + if (iter->fRefCount > 0) { + // If the least recently used bitmap has not been unreferenced + // by its owner, then according to our LRU specifications a more + // recently used one can not have used all it's references yet either. + return NULL; + } + if (replacement.pixelRef() && replacement.pixelRef() == iter->fBitmap.pixelRef()) { + // Do not replace a bitmap with a new one using the same + // pixel ref. Instead look for a different one that will + // potentially free up more space. + iter = iter->fMoreRecentlyUsed; + } else { + return iter; + } + } + return NULL; +} + +int SkBitmapHeap::findInLookupTable(const SkBitmap& bitmap, SkBitmapHeapEntry** entry) { + LookupEntry indexEntry; + indexEntry.fGenerationId = bitmap.getGenerationID(); + indexEntry.fPixelOffset = bitmap.pixelRefOffset(); + indexEntry.fWidth = bitmap.width(); + indexEntry.fHeight = bitmap.height(); + int index = SkTSearch<const LookupEntry>(fLookupTable.begin(), + fLookupTable.count(), + indexEntry, sizeof(indexEntry)); + + if (index < 0) { + // insert ourselves into the bitmapIndex + index = ~index; + fLookupTable.insert(index, 1, &indexEntry); + } else if (entry != NULL) { + // populate the entry if needed + *entry = fStorage[fLookupTable[index].fStorageSlot]; + } + + return index; +} + +bool SkBitmapHeap::copyBitmap(const SkBitmap& originalBitmap, SkBitmap& copiedBitmap) { + SkASSERT(!fExternalStorage); + + // If the bitmap is mutable, we need to do a deep copy, since the + // caller may modify it afterwards. + if (originalBitmap.isImmutable()) { + copiedBitmap = originalBitmap; +// TODO if we have the pixel ref in the heap we could pass it here to avoid a potential deep copy +// else if (sharedPixelRef != NULL) { +// copiedBitmap = orig; +// copiedBitmap.setPixelRef(sharedPixelRef, originalBitmap.pixelRefOffset()); + } else if (originalBitmap.empty()) { + copiedBitmap.reset(); + } else if (!originalBitmap.deepCopyTo(&copiedBitmap, originalBitmap.getConfig())) { + return false; + } + copiedBitmap.setImmutable(); + return true; +} + +int32_t SkBitmapHeap::insert(const SkBitmap& originalBitmap) { + SkBitmapHeapEntry* entry = NULL; + int searchIndex = this->findInLookupTable(originalBitmap, &entry); + + // check to see if we already had a copy of the bitmap in the heap + if (entry) { + if (fOwnerCount != IGNORE_OWNERS) { + entry->addReferences(fOwnerCount); + } + if (fPreferredCount != UNLIMITED_SIZE) { + this->setMostRecentlyUsed(entry); + } + return entry->fSlot; + } + + // decide if we need to evict an existing heap entry or create a new one + if (fPreferredCount != UNLIMITED_SIZE && fStorage.count() >= fPreferredCount) { + // iterate through our LRU cache and try to find an entry to evict + entry = this->findEntryToReplace(originalBitmap); + // we found an entry to evict + if (entry) { + // remove the bitmap index for the deleted entry + SkDEBUGCODE(int count = fLookupTable.count();) + int index = findInLookupTable(entry->fBitmap, NULL); + SkASSERT(count == fLookupTable.count()); + + fLookupTable.remove(index); + fBytesAllocated -= entry->fBytesAllocated; + + // update the current search index now that we have removed one + if (index < searchIndex) { + searchIndex--; + } + } + } + + // if we didn't have an entry yet we need to create one + if (!entry) { + entry = SkNEW(SkBitmapHeapEntry); + fStorage.append(1, &entry); + entry->fSlot = fStorage.count() - 1; + fBytesAllocated += sizeof(SkBitmapHeapEntry); + } + + // create a copy of the bitmap + bool copySucceeded; + if (fExternalStorage) { + copySucceeded = fExternalStorage->insert(originalBitmap, entry->fSlot); + } else { + copySucceeded = copyBitmap(originalBitmap, entry->fBitmap); + } + + // if the copy failed then we must abort + if (!copySucceeded) { + // delete the index + fLookupTable.remove(searchIndex); + // free the slot + fStorage.remove(entry->fSlot); + SkDELETE(entry); + return INVALID_SLOT; + } + + // update the index with the appropriate slot in the heap + fLookupTable[searchIndex].fStorageSlot = entry->fSlot; + + // compute the space taken by the this entry + // TODO if there is a shared pixel ref don't count it + // If the SkBitmap does not share an SkPixelRef with an SkBitmap already + // in the SharedHeap, also include the size of its pixels. + entry->fBytesAllocated += originalBitmap.getSize(); + + // add the bytes from this entry to the total count + fBytesAllocated += entry->fBytesAllocated; + + if (fOwnerCount != IGNORE_OWNERS) { + entry->addReferences(fOwnerCount); + } + if (fPreferredCount != UNLIMITED_SIZE) { + this->setMostRecentlyUsed(entry); + } + return entry->fSlot; +} diff --git a/src/core/SkBitmapHeap.h b/src/core/SkBitmapHeap.h new file mode 100644 index 0000000000..bcfd0393c6 --- /dev/null +++ b/src/core/SkBitmapHeap.h @@ -0,0 +1,248 @@ + +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef SkBitmapHeap_DEFINED +#define SkBitmapHeap_DEFINED + +#include "SkBitmap.h" +#include "SkFlattenable.h" +#include "SkRefCnt.h" +#include "SkTDArray.h" +#include "SkThread.h" +#include "SkTRefArray.h" + +/** + * SkBitmapHeapEntry provides users of SkBitmapHeap (using internal storage) with a means to... + * (1) get access a bitmap in the heap + * (2) indicate they are done with bitmap by releasing their reference (if they were an owner). + */ +class SkBitmapHeapEntry : SkNoncopyable { +public: + ~SkBitmapHeapEntry(); + + int32_t getSlot() { return fSlot; } + + SkBitmap* getBitmap() { return &fBitmap; } + + void releaseRef() { + sk_atomic_dec(&fRefCount); + } + +private: + SkBitmapHeapEntry(); + + void addReferences(int count); + + int32_t fSlot; + int32_t fRefCount; + + SkBitmap fBitmap; + // Keep track of the bytes allocated for this bitmap. When replacing the + // bitmap or removing this HeapEntry we know how much memory has been + // reclaimed. + size_t fBytesAllocated; + // TODO: Generalize the LRU caching mechanism + SkBitmapHeapEntry* fMoreRecentlyUsed; + SkBitmapHeapEntry* fLessRecentlyUsed; + + friend class SkBitmapHeap; +}; + + +class SkBitmapHeapReader : public SkRefCnt { +public: + SkBitmapHeapReader() : INHERITED() {} + virtual SkBitmap* getBitmap(int32_t slot) const = 0; + virtual void releaseRef(int32_t slot) = 0; +private: + typedef SkRefCnt INHERITED; +}; + + +/** + * TODO: stores immutable bitmaps into a heap + */ +class SkBitmapHeap : public SkBitmapHeapReader { +public: + class ExternalStorage : public SkRefCnt { + public: + virtual bool insert(const SkBitmap& bitmap, int32_t slot) = 0; + }; + + static const int32_t UNLIMITED_SIZE = -1; + static const int32_t IGNORE_OWNERS = -1; + static const int32_t INVALID_SLOT = -1; + + /** + * Constructs a heap that is responsible for allocating and managing its own storage. In the + * case where we choose to allow the heap to grow indefinitely (i.e. UNLIMITED_SIZE) we + * guarantee that once allocated in the heap a bitmap's index in the heap is immutable. + * Otherwise we guarantee the bitmaps placement in the heap until its owner count goes to zero. + * + * @param preferredSize Specifies the preferred maximum number of bitmaps to store. This is + * not a hard limit as it can grow larger if the number of bitmaps in the heap with active + * owners exceeds this limit. + * @param ownerCount The number of owners to assign to each inserted bitmap. NOTE: while a + * bitmap in the heap has a least one owner it can't be removed. + */ + SkBitmapHeap(int32_t preferredSize = UNLIMITED_SIZE, int32_t ownerCount = IGNORE_OWNERS); + + /** + * Constructs a heap that defers the responsibility of storing the bitmaps to an external + * function. This is especially useful if the bitmaps will be used in a separate process as the + * external storage can ensure the data is properly shuttled to the appropriate processes. + * + * Our LRU implementation assumes that inserts into the external storage are consumed in the + * order that they are inserted (i.e. SkPipe). This ensures that we don't need to query the + * external storage to see if a slot in the heap is eligible to be overwritten. + * + * @param externalStorage The class responsible for storing the bitmaps inserted into the heap + * @param heapSize The maximum size of the heap. Because of the sequential limitation imposed + * by our LRU implementation we can guarantee that the heap will never grow beyond this size. + */ + SkBitmapHeap(ExternalStorage* externalStorage, int32_t heapSize = UNLIMITED_SIZE); + + ~SkBitmapHeap(); + + /** + * Makes a shallow copy of all bitmaps currently in the heap and returns them as an array. The + * array indices match their position in the heap. + * + * @return a ptr to an array of bitmaps or NULL if external storage is being used. + */ + SkTRefArray<SkBitmap>* extractBitmaps() const; + + /** + * Retrieves the bitmap from the specified slot in the heap + * + * @return The bitmap located at that slot or NULL if external storage is being used. + */ + virtual SkBitmap* getBitmap(int32_t slot) const SK_OVERRIDE { + SkASSERT(fExternalStorage == NULL); + SkBitmapHeapEntry* entry = getEntry(slot); + if (entry) { + return &entry->fBitmap; + } + return NULL; + } + + /** + * Retrieves the bitmap from the specified slot in the heap + * + * @return The bitmap located at that slot or NULL if external storage is being used. + */ + virtual void releaseRef(int32_t slot) SK_OVERRIDE { + SkASSERT(fExternalStorage == NULL); + if (fOwnerCount != IGNORE_OWNERS) { + SkBitmapHeapEntry* entry = getEntry(slot); + if (entry) { + entry->releaseRef(); + } + } + } + + /** + * Inserts a bitmap into the heap. The stored version of bitmap is guaranteed to be immutable + * and is not dependent on the lifecycle of the provided bitmap. + * + * @param bitmap the bitmap to be inserted into the heap + * @return the slot in the heap where the bitmap is stored or INVALID_SLOT if the bitmap could + * not be added to the heap. If it was added the slot will remain valid... + * (1) indefinitely if no owner count has been specified. + * (2) until all owners have called releaseRef on the appropriate SkBitmapHeapEntry* + */ + int32_t insert(const SkBitmap& bitmap); + + /** + * Retrieves an entry from the heap at a given slot. + * + * @param slot the slot in the heap where a bitmap was stored. + * @return a SkBitmapHeapEntry that wraps the bitmap or NULL if external storage is used. + */ + SkBitmapHeapEntry* getEntry(int32_t slot) const { + SkASSERT(slot <= fStorage.count()); + if (fExternalStorage != NULL) { + return NULL; + } + return fStorage[slot]; + } + + /** + * Returns a count of the number of items currently in the heap + */ + int count() const { + SkASSERT(fExternalStorage != NULL || fStorage.count() == fLookupTable.count()); + return fLookupTable.count(); + } + + /** + * Returns the total number of bytes allocated by the bitmaps in the heap + */ + size_t bytesAllocated() const { + return fBytesAllocated; + } + +private: + struct LookupEntry { + uint32_t fGenerationId; // SkPixelRef GenerationID. + size_t fPixelOffset; + uint32_t fWidth; + uint32_t fHeight; + + uint32_t fStorageSlot; // slot of corresponding bitmap in fStorage. + + bool operator < (const LookupEntry& other) const { + if (this->fGenerationId != other.fGenerationId) { + return this->fGenerationId < other.fGenerationId; + } else if(this->fPixelOffset != other.fPixelOffset) { + return this->fPixelOffset < other.fPixelOffset; + } else if(this->fWidth != other.fWidth) { + return this->fWidth < other.fWidth; + } else { + return this->fHeight < other.fHeight; + } + } + bool operator != (const LookupEntry& other) const { + return this->fGenerationId != other.fGenerationId + || this->fPixelOffset != other.fPixelOffset + || this->fWidth != other.fWidth + || this->fHeight != other.fHeight; + } + }; + + /** + * Searches for the bitmap in the lookup table and returns the bitmaps index within the table. + * If the bitmap was not already in the table it is added. + * + * @param bitmap The bitmap we using as a key to search the lookup table + * @param entry A pointer to a SkBitmapHeapEntry* that if non-null AND the bitmap is found + * in the lookup table is populated with the entry from the heap storage. + */ + int findInLookupTable(const SkBitmap& bitmap, SkBitmapHeapEntry** entry); + + SkBitmapHeapEntry* findEntryToReplace(const SkBitmap& replacement); + bool copyBitmap(const SkBitmap& originalBitmap, SkBitmap& copiedBitmap); + void setMostRecentlyUsed(SkBitmapHeapEntry* entry); + + // searchable index that maps to entries in the heap + SkTDArray<LookupEntry> fLookupTable; + + // heap storage + SkTDArray<SkBitmapHeapEntry*> fStorage; + ExternalStorage* fExternalStorage; + + SkBitmapHeapEntry* fMostRecentlyUsed; + SkBitmapHeapEntry* fLeastRecentlyUsed; + + const int32_t fPreferredCount; + const int32_t fOwnerCount; + size_t fBytesAllocated; + + typedef SkBitmapHeapReader INHERITED; +}; + +#endif // SkBitmapHeap_DEFINED diff --git a/src/core/SkFlattenableBuffers.cpp b/src/core/SkFlattenableBuffers.cpp index e5a9545e1a..50a47d5c47 100644 --- a/src/core/SkFlattenableBuffers.cpp +++ b/src/core/SkFlattenableBuffers.cpp @@ -34,13 +34,6 @@ void SkFlattenableReadBuffer::readPaint(SkPaint* paint) { paint->unflatten(*this); } -SkRefCnt* SkFlattenableReadBuffer::readRefCntPtr() { - void* ptrStorage[] = { NULL }; - SkASSERT(sizeof(void*) == this->getArrayCount()); - this->readByteArray(*ptrStorage); - return (SkRefCnt*)ptrStorage[0]; -} - /////////////////////////////////////////////////////////////////////////////// SkFlattenableWriteBuffer::SkFlattenableWriteBuffer() { @@ -58,11 +51,6 @@ void SkFlattenableWriteBuffer::writePaint(const SkPaint& paint) { paint.flatten(*this); } -void SkFlattenableWriteBuffer::writeRefCntPtr(SkRefCnt* refCnt) { - void* ptrStorage[] = { (void*)refCnt }; - this->writeByteArray(ptrStorage, sizeof(void*)); -} - void SkFlattenableWriteBuffer::flattenObject(SkFlattenable* obj, SkFlattenableWriteBuffer& buffer) { obj->flatten(buffer); } diff --git a/src/core/SkOrderedReadBuffer.cpp b/src/core/SkOrderedReadBuffer.cpp index a502c5d99a..5835c34aef 100644 --- a/src/core/SkOrderedReadBuffer.cpp +++ b/src/core/SkOrderedReadBuffer.cpp @@ -10,14 +10,23 @@ #include "SkStream.h" #include "SkTypeface.h" +SkOrderedReadBuffer::SkOrderedReadBuffer() : INHERITED() { + fMemoryPtr = NULL; + + fBitmapStorage = NULL; + fTFArray = NULL; + fTFCount = 0; -SkOrderedReadBuffer::SkOrderedReadBuffer(const void* data, size_t size) { + fFactoryTDArray = NULL; + fFactoryArray = NULL; + fFactoryCount = 0; +} + +SkOrderedReadBuffer::SkOrderedReadBuffer(const void* data, size_t size) : INHERITED() { fReader.setMemory(data, size); fMemoryPtr = NULL; - fRCArray = NULL; - fRCCount = 0; - + fBitmapStorage = NULL; fTFArray = NULL; fTFCount = 0; @@ -31,10 +40,19 @@ SkOrderedReadBuffer::SkOrderedReadBuffer(SkStream* stream) { fMemoryPtr = sk_malloc_throw(length); stream->read(fMemoryPtr, length); fReader.setMemory(fMemoryPtr, length); + + fBitmapStorage = NULL; + fTFArray = NULL; + fTFCount = 0; + + fFactoryTDArray = NULL; + fFactoryArray = NULL; + fFactoryCount = 0; } SkOrderedReadBuffer::~SkOrderedReadBuffer() { sk_free(fMemoryPtr); + SkSafeUnref(fBitmapStorage); } bool SkOrderedReadBuffer::readBool() { @@ -145,20 +163,16 @@ uint32_t SkOrderedReadBuffer::getArrayCount() { return *(uint32_t*)fReader.peek(); } -SkRefCnt* SkOrderedReadBuffer::readRefCntPtr() { - if (fRCArray) { +void SkOrderedReadBuffer::readBitmap(SkBitmap* bitmap) { + if (fBitmapStorage) { const uint32_t index = fReader.readU32(); - SkASSERT(index <= (unsigned)fRCCount); - return fRCArray[index - 1]; + *bitmap = *fBitmapStorage->getBitmap(index); + fBitmapStorage->releaseRef(index); } else { - return INHERITED::readRefCntPtr(); + bitmap->unflatten(*this); } } -void SkOrderedReadBuffer::readBitmap(SkBitmap* bitmap) { - bitmap->unflatten(*this); -} - SkTypeface* SkOrderedReadBuffer::readTypeface() { uint32_t index = fReader.readU32(); diff --git a/src/core/SkOrderedWriteBuffer.cpp b/src/core/SkOrderedWriteBuffer.cpp index 9dd70fb1cf..f7d6dbbe1d 100644 --- a/src/core/SkOrderedWriteBuffer.cpp +++ b/src/core/SkOrderedWriteBuffer.cpp @@ -14,7 +14,7 @@ SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize) , fFactorySet(NULL) , fNamedFactorySet(NULL) , fWriter(minSize) - , fRCSet(NULL) + , fBitmapHeap(NULL) , fTFSet(NULL) { } @@ -23,14 +23,14 @@ SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize, void* storage, size_t , fFactorySet(NULL) , fNamedFactorySet(NULL) , fWriter(minSize, storage, storageSize) - , fRCSet(NULL) + , fBitmapHeap(NULL) , fTFSet(NULL) { } SkOrderedWriteBuffer::~SkOrderedWriteBuffer() { SkSafeUnref(fFactorySet); SkSafeUnref(fNamedFactorySet); - SkSafeUnref(fRCSet); + SkSafeUnref(fBitmapHeap); SkSafeUnref(fTFSet); } @@ -132,19 +132,14 @@ bool SkOrderedWriteBuffer::writeToStream(SkWStream* stream) { return fWriter.writeToStream(stream); } -void SkOrderedWriteBuffer::writeRefCntPtr(SkRefCnt* refCnt) { - SkASSERT(!isCrossProcess()); - if (NULL == fRCSet) { - INHERITED::writeRefCntPtr(refCnt); +void SkOrderedWriteBuffer::writeBitmap(const SkBitmap& bitmap) { + if (fBitmapHeap) { + fWriter.write32(fBitmapHeap->insert(bitmap)); } else { - this->write32(fRCSet->add(refCnt)); + bitmap.flatten(*this); } } -void SkOrderedWriteBuffer::writeBitmap(const SkBitmap& bitmap) { - bitmap.flatten(*this); -} - void SkOrderedWriteBuffer::writeTypeface(SkTypeface* obj) { if (NULL == obj || NULL == fTFSet) { fWriter.write32(0); @@ -171,11 +166,6 @@ SkNamedFactorySet* SkOrderedWriteBuffer::setNamedFactoryRecorder(SkNamedFactoryS return rec; } -SkRefCntSet* SkOrderedWriteBuffer::setRefCntRecorder(SkRefCntSet* rec) { - SkRefCnt_SafeAssign(fRCSet, rec); - return rec; -} - SkRefCntSet* SkOrderedWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) { SkRefCnt_SafeAssign(fTFSet, rec); return rec; diff --git a/src/core/SkPictureFlat.cpp b/src/core/SkPictureFlat.cpp index a593e36c00..bd4419219c 100644 --- a/src/core/SkPictureFlat.cpp +++ b/src/core/SkPictureFlat.cpp @@ -18,13 +18,13 @@ /////////////////////////////////////////////////////////////////////////////// -SkRefCntPlayback::SkRefCntPlayback() : fCount(0), fArray(NULL) {} +SkTypefacePlayback::SkTypefacePlayback() : fCount(0), fArray(NULL) {} -SkRefCntPlayback::~SkRefCntPlayback() { +SkTypefacePlayback::~SkTypefacePlayback() { this->reset(NULL); } -void SkRefCntPlayback::reset(const SkRefCntSet* rec) { +void SkTypefacePlayback::reset(const SkRefCntSet* rec) { for (int i = 0; i < fCount; i++) { SkASSERT(fArray[i]); fArray[i]->unref(); @@ -44,7 +44,7 @@ void SkRefCntPlayback::reset(const SkRefCntSet* rec) { } } -void SkRefCntPlayback::setCount(int count) { +void SkTypefacePlayback::setCount(int count) { this->reset(NULL); fCount = count; @@ -52,7 +52,7 @@ void SkRefCntPlayback::setCount(int count) { sk_bzero(fArray, count * sizeof(SkRefCnt*)); } -SkRefCnt* SkRefCntPlayback::set(int index, SkRefCnt* obj) { +SkRefCnt* SkTypefacePlayback::set(int index, SkRefCnt* obj) { SkASSERT((unsigned)index < (unsigned)fCount); SkRefCnt_SafeAssign(fArray[index], obj); return obj; @@ -61,30 +61,25 @@ SkRefCnt* SkRefCntPlayback::set(int index, SkRefCnt* obj) { /////////////////////////////////////////////////////////////////////////////// SkFlatController::SkFlatController() -: fPixelRefSet(NULL) +: fBitmapHeap(NULL) , fTypefaceSet(NULL) -, fPixelRefPlayback(NULL) , fTypefacePlayback(NULL) , fFactorySet(NULL) {} SkFlatController::~SkFlatController() { - SkSafeUnref(fPixelRefSet); + SkSafeUnref(fBitmapHeap); SkSafeUnref(fTypefaceSet); SkSafeUnref(fFactorySet); } -void SkFlatController::setPixelRefSet(SkRefCntSet *set) { - SkRefCnt_SafeAssign(fPixelRefSet, set); +void SkFlatController::setBitmapHeap(SkBitmapHeap* heap) { + SkRefCnt_SafeAssign(fBitmapHeap, heap); } void SkFlatController::setTypefaceSet(SkRefCntSet *set) { SkRefCnt_SafeAssign(fTypefaceSet, set); } -void SkFlatController::setPixelRefPlayback(SkRefCntPlayback* playback) { - fPixelRefPlayback = playback; -} - void SkFlatController::setTypefacePlayback(SkTypefacePlayback* playback) { fTypefacePlayback = playback; } @@ -104,7 +99,7 @@ SkFlatData* SkFlatData::Create(SkFlatController* controller, const void* obj, intptr_t storage[256]; SkOrderedWriteBuffer buffer(256, storage, sizeof(storage)); - buffer.setRefCntRecorder(controller->getPixelRefSet()); + buffer.setBitmapHeap(controller->getBitmapHeap()); buffer.setTypefaceRecorder(controller->getTypefaceSet()); buffer.setNamedFactoryRecorder(controller->getNamedFactorySet()); buffer.setFlags(writeBufferflags); @@ -134,16 +129,18 @@ SkFlatData* SkFlatData::Create(SkFlatController* controller, const void* obj, void SkFlatData::unflatten(void* result, void (*unflattenProc)(SkOrderedReadBuffer&, void*), - SkRefCntPlayback* refCntPlayback, + SkBitmapHeap* bitmapHeap, SkTypefacePlayback* facePlayback) const { SkOrderedReadBuffer buffer(this->data(), fFlatSize); - if (refCntPlayback) { - refCntPlayback->setupBuffer(buffer); + + if (bitmapHeap) { + buffer.setBitmapStorage(bitmapHeap); } if (facePlayback) { facePlayback->setupBuffer(buffer); } + unflattenProc(buffer, result); SkASSERT(fFlatSize == (int32_t)buffer.offset()); } diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h index c4605aa1e2..0f846fd509 100644 --- a/src/core/SkPictureFlat.h +++ b/src/core/SkPictureFlat.h @@ -12,6 +12,7 @@ #include "SkChunkAlloc.h" #include "SkBitmap.h" +#include "SkBitmapHeap.h" #include "SkOrderedReadBuffer.h" #include "SkOrderedWriteBuffer.h" #include "SkPicture.h" @@ -83,10 +84,10 @@ static inline bool ClipParams_unpackDoAA(uint32_t packed) { /////////////////////////////////////////////////////////////////////////////// -class SkRefCntPlayback { +class SkTypefacePlayback { public: - SkRefCntPlayback(); - virtual ~SkRefCntPlayback(); + SkTypefacePlayback(); + virtual ~SkTypefacePlayback(); int count() const { return fCount; } @@ -95,8 +96,8 @@ public: void setCount(int count); SkRefCnt* set(int index, SkRefCnt*); - virtual void setupBuffer(SkOrderedReadBuffer& buffer) const { - buffer.setRefCntArray(fArray, fCount); + void setupBuffer(SkOrderedReadBuffer& buffer) const { + buffer.setTypefaceArray((SkTypeface**)fArray, fCount); } protected: @@ -104,13 +105,6 @@ protected: SkRefCnt** fArray; }; -class SkTypefacePlayback : public SkRefCntPlayback { -public: - virtual void setupBuffer(SkOrderedReadBuffer& buffer) const { - buffer.setTypefaceArray((SkTypeface**)fArray, fCount); - } -}; - class SkFactoryPlayback { public: SkFactoryPlayback(int count) : fCount(count) { @@ -180,19 +174,12 @@ public: virtual void unalloc(void* ptr) = 0; /** - * Used during creation of SkFlatData objects. Only used for storing refs to - * SkPixelRefs. If the objects being flattened have SkPixelRefs (i.e. - * SkBitmaps or SkPaints, which may have SkBitmapShaders), this should be - * set by the protected setPixelRefSet. - */ - SkRefCntSet* getPixelRefSet() { return fPixelRefSet; } - - /** - * Used during unflattening of the SkFlatData objects in the - * SkFlatDictionary. Needs to be set by the protected setPixelRefPlayback - * and needs to be reset to the SkRefCntSet passed to setPixelRefSet. + * Used during creation and unflattening of SkFlatData objects. If the + * objects being flattened contain bitmaps they are stored in this heap + * and the flattenable stores the index to the bitmap on the heap. + * This should be set by the protected setBitmapHeap. */ - SkRefCntPlayback* getPixelRefPlayback() { return fPixelRefPlayback; } + SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; } /** * Used during creation of SkFlatData objects. If a typeface recorder is @@ -216,10 +203,9 @@ public: protected: /** - * Set an SkRefCntSet to be used to store SkPixelRefs during flattening. Ref - * counted. + * Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted. */ - void setPixelRefSet(SkRefCntSet*); + void setBitmapHeap(SkBitmapHeap*); /** * Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref @@ -228,13 +214,6 @@ protected: void setTypefaceSet(SkRefCntSet*); /** - * Set an SkRefCntPlayback to be used to find references to SkPixelRefs - * during unflattening. Should be reset to the set provided to - * setPixelRefSet. - */ - void setPixelRefPlayback(SkRefCntPlayback*); - - /** * Set an SkTypefacePlayback to be used to find references to SkTypefaces * during unflattening. Should be reset to the set provided to * setTypefaceSet. @@ -249,9 +228,8 @@ protected: SkNamedFactorySet* setNamedFactorySet(SkNamedFactorySet*); private: - SkRefCntSet* fPixelRefSet; + SkBitmapHeap* fBitmapHeap; SkRefCntSet* fTypefaceSet; - SkRefCntPlayback* fPixelRefPlayback; SkTypefacePlayback* fTypefacePlayback; SkNamedFactorySet* fFactorySet; }; @@ -321,7 +299,7 @@ public: void unflatten(void* result, void (*unflattenProc)(SkOrderedReadBuffer&, void*), - SkRefCntPlayback* refCntPlayback = NULL, + SkBitmapHeap* bitmapHeap = NULL, SkTypefacePlayback* facePlayback = NULL) const; // When we purge an entry, we want to reuse an old index for the new entry, @@ -495,9 +473,8 @@ private: int index = element->index() - 1; SkASSERT((unsigned)index < (unsigned)count); element->unflatten(&array[index], fUnflattenProc, - fController->getPixelRefPlayback(), + fController->getBitmapHeap(), fController->getTypefacePlayback()); - } } @@ -581,16 +558,12 @@ class SkChunkFlatController : public SkFlatController { public: SkChunkFlatController(size_t minSize) : fHeap(minSize) - , fRefSet(SkNEW(SkRefCntSet)) , fTypefaceSet(SkNEW(SkRefCntSet)) { - this->setPixelRefSet(fRefSet); this->setTypefaceSet(fTypefaceSet); - this->setPixelRefPlayback(&fRefPlayback); this->setTypefacePlayback(&fTypefacePlayback); } ~SkChunkFlatController() { - fRefSet->unref(); fTypefaceSet->unref(); } @@ -602,24 +575,17 @@ public: (void) fHeap.unalloc(ptr); } - void reset() { - fHeap.reset(); - fRefSet->reset(); - fTypefaceSet->reset(); - fRefPlayback.reset(NULL); - fTypefacePlayback.reset(NULL); - } - void setupPlaybacks() const { - fRefPlayback.reset(fRefSet); fTypefacePlayback.reset(fTypefaceSet); } + void setBitmapStorage(SkBitmapHeap* heap) { + this->setBitmapHeap(heap); + } + private: SkChunkAlloc fHeap; - SkRefCntSet* fRefSet; SkRefCntSet* fTypefaceSet; - mutable SkRefCntPlayback fRefPlayback; mutable SkTypefacePlayback fTypefacePlayback; }; diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index f05aeaab9e..8ed5fe0e78 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -78,15 +78,14 @@ SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record) { } // copy over the refcnt dictionary to our reader - // - record.fHeap.setupPlaybacks(); - fBitmaps = record.getBitmaps().unflattenToArray(); - fMatrices = record.getMatrices().unflattenToArray(); - fPaints = record.getPaints().unflattenToArray(); - fRegions = record.getRegions().unflattenToArray(); - - fPathHeap = record.fPathHeap; - SkSafeRef(fPathHeap); + record.fFlattenableHeap.setupPlaybacks(); + + fBitmaps = record.fBitmapHeap.extractBitmaps(); + fMatrices = record.fMatrices.unflattenToArray(); + fPaints = record.fPaints.unflattenToArray(); + fRegions = record.fRegions.unflattenToArray(); + + SkRefCnt_SafeAssign(fPathHeap, record.fPathHeap); const SkTDArray<SkPicture* >& pictures = record.getPictureRefs(); fPictureCount = pictures.count(); diff --git a/src/core/SkPicturePlayback.h b/src/core/SkPicturePlayback.h index 2110c71962..9cc2fd34cd 100644 --- a/src/core/SkPicturePlayback.h +++ b/src/core/SkPicturePlayback.h @@ -72,7 +72,7 @@ private: const SkBitmap& getBitmap(SkReader32& reader) { int index = reader.readInt(); - return (*fBitmaps)[index - 1]; + return (*fBitmaps)[index]; } const SkMatrix* getMatrix(SkReader32& reader) { @@ -179,7 +179,7 @@ private: int fPictureCount; SkTypefacePlayback fTFPlayback; - SkFactoryPlayback* fFactoryPlayback; + SkFactoryPlayback* fFactoryPlayback; #ifdef SK_BUILD_FOR_ANDROID SkMutex fDrawMutex; #endif diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp index c3f3ad12cf..fb4f991f51 100644 --- a/src/core/SkPictureRecord.cpp +++ b/src/core/SkPictureRecord.cpp @@ -17,11 +17,10 @@ enum { }; SkPictureRecord::SkPictureRecord(uint32_t flags) : - fHeap(HEAP_BLOCK_SIZE), - fBitmaps(&fHeap), - fMatrices(&fHeap), - fPaints(&fHeap), - fRegions(&fHeap), + fFlattenableHeap(HEAP_BLOCK_SIZE), + fMatrices(&fFlattenableHeap), + fPaints(&fFlattenableHeap), + fRegions(&fFlattenableHeap), fWriter(MIN_WRITER_SIZE), fRecordFlags(flags) { #ifdef SK_DEBUG_SIZE @@ -32,12 +31,15 @@ SkPictureRecord::SkPictureRecord(uint32_t flags) : fRestoreOffsetStack.setReserve(32); fInitialSaveCount = kNoInitialSave; + fFlattenableHeap.setBitmapStorage(&fBitmapHeap); fPathHeap = NULL; // lazy allocate fFirstSavedLayerIndex = kNoSavedLayerIndex; } SkPictureRecord::~SkPictureRecord() { - reset(); + SkSafeUnref(fPathHeap); + fFlattenableHeap.setBitmapStorage(NULL); + fPictureRefs.unrefAll(); } /////////////////////////////////////////////////////////////////////////////// @@ -518,25 +520,8 @@ void SkPictureRecord::drawData(const void* data, size_t length) { /////////////////////////////////////////////////////////////////////////////// -void SkPictureRecord::reset() { - SkSafeUnref(fPathHeap); - fPathHeap = NULL; - - fBitmaps.reset(); - fBitmapIndexCache.reset(); - fMatrices.reset(); - fPaints.reset(); - fPictureRefs.unrefAll(); - fRegions.reset(); - fWriter.reset(); - fHeap.reset(); - - fRestoreOffsetStack.setCount(1); - fRestoreOffsetStack.top() = 0; -} - void SkPictureRecord::addBitmap(const SkBitmap& bitmap) { - addInt(find(bitmap)); + addInt(fBitmapHeap.insert(bitmap)); } void SkPictureRecord::addMatrix(const SkMatrix& matrix) { @@ -637,38 +622,6 @@ void SkPictureRecord::addText(const void* text, size_t byteLength) { /////////////////////////////////////////////////////////////////////////////// -int SkPictureRecord::find(const SkBitmap& bitmap) { - int dictionaryIndex = 0; - BitmapIndexCacheEntry entry; - const bool flattenPixels = !bitmap.isImmutable(); - if (flattenPixels) { - // Flattened bitmap may be very large. First attempt a fast lookup - // based on generation ID to avoid unnecessary flattening in - // fBitmaps.find() - entry.fGenerationId = bitmap.getGenerationID(); - entry.fPixelOffset = bitmap.pixelRefOffset(); - entry.fWidth = bitmap.width(); - entry.fHeight = bitmap.height(); - dictionaryIndex = - SkTSearch<const BitmapIndexCacheEntry>(fBitmapIndexCache.begin(), - fBitmapIndexCache.count(), entry, sizeof(entry)); - if (dictionaryIndex >= 0) { - return fBitmapIndexCache[dictionaryIndex].fIndex; - } - } - - uint32_t writeFlags = flattenPixels ? - SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag : 0; - int index = fBitmaps.find(bitmap, writeFlags); - - if (flattenPixels) { - entry.fIndex = index; - dictionaryIndex = ~dictionaryIndex; - *fBitmapIndexCache.insert(dictionaryIndex) = entry; - } - return index; -} - #ifdef SK_DEBUG_SIZE size_t SkPictureRecord::size() const { size_t result = 0; diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h index cd429da919..50cf4db099 100644 --- a/src/core/SkPictureRecord.h +++ b/src/core/SkPictureRecord.h @@ -71,23 +71,10 @@ public: void addFontMetricsTopBottom(const SkPaint& paint, SkScalar minY, SkScalar maxY); - const SkBitmapDictionary& getBitmaps() const { - return fBitmaps; - } - const SkMatrixDictionary& getMatrices() const { - return fMatrices; - } - const SkPaintDictionary& getPaints() const { - return fPaints; - } const SkTDArray<SkPicture* >& getPictureRefs() const { return fPictureRefs; } - const SkRegionDictionary& getRegions() const { - return fRegions; - } - void reset(); void setFlags(uint32_t recordFlags) { fRecordFlags = recordFlags; } @@ -98,31 +85,6 @@ public: void endRecording(); private: - struct BitmapIndexCacheEntry { - uint32_t fGenerationId; // SkPixelRef GenerationID. - size_t fPixelOffset; - uint32_t fWidth; - uint32_t fHeight; - uint32_t fIndex; // Index of corresponding flattened bitmap in fBitmaps. - bool operator < (const BitmapIndexCacheEntry& other) const { - if (this->fGenerationId != other.fGenerationId) { - return this->fGenerationId < other.fGenerationId; - } else if(this->fPixelOffset != other.fPixelOffset) { - return this->fPixelOffset < other.fPixelOffset; - } else if(this->fWidth != other.fWidth) { - return this->fWidth < other.fWidth; - } else { - return this->fHeight < other.fHeight; - } - } - bool operator != (const BitmapIndexCacheEntry& other) const { - return this->fGenerationId != other.fGenerationId - || this->fPixelOffset != other.fPixelOffset - || this->fWidth != other.fWidth - || this->fHeight != other.fHeight; - } - }; - void recordRestoreOffsetPlaceholder(SkRegion::Op); void fillRestoreOffsetPlaceholdersForCurrentStackLevel( uint32_t restoreOffset); @@ -199,10 +161,9 @@ public: #endif private: - SkChunkFlatController fHeap; + SkBitmapHeap fBitmapHeap; + SkChunkFlatController fFlattenableHeap; - SkTDArray<BitmapIndexCacheEntry> fBitmapIndexCache; - SkBitmapDictionary fBitmaps; SkMatrixDictionary fMatrices; SkPaintDictionary fPaints; SkRegionDictionary fRegions; diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp index 866bf0ca22..2e15ebb17b 100644 --- a/tests/CanvasTest.cpp +++ b/tests/CanvasTest.cpp @@ -659,13 +659,8 @@ private: CanvasTestStep* testStep) { REPORTER_ASSERT_MESSAGE(reporter, - referenceRecord->fBitmaps.count() == - testRecord->fBitmaps.count(), testStep->assertMessage()); - for (int i = 0; i < referenceRecord->fBitmaps.count(); ++i) { - REPORTER_ASSERT_MESSAGE(reporter, - EQ(referenceRecord->fBitmaps[i], testRecord->fBitmaps[i]), - testStep->assertMessage()); - } + referenceRecord->fBitmapHeap.count() == + testRecord->fBitmapHeap.count(), testStep->assertMessage()); REPORTER_ASSERT_MESSAGE(reporter, referenceRecord->fMatrices.count() == testRecord->fMatrices.count(), testStep->assertMessage()); |