Required adding a new feature to SkBitmapHeap, allowing it to defer
adding owners, since sometimes we flatten a shader, but then do not
unflatten it, since we already had a copy in the heap, so the owners
never get removed.
Reviewed at https://codereview.appspot.com/6464053/
Review URL: https://codereview.appspot.com/6465047
git-svn-id: http://skia.googlecode.com/svn/trunk@5082
2bbb7eff-a529-9590-31e7-
b0007b416f81
, fLeastRecentlyUsed(NULL)
, fPreferredCount(preferredSize)
, fOwnerCount(ownerCount)
- , fBytesAllocated(0) {
+ , fBytesAllocated(0)
+ , fDeferAddingOwners(false) {
}
SkBitmapHeap::SkBitmapHeap(ExternalStorage* storage, int32_t preferredSize)
, fLeastRecentlyUsed(NULL)
, fPreferredCount(preferredSize)
, fOwnerCount(IGNORE_OWNERS)
- , fBytesAllocated(0) {
+ , fBytesAllocated(0)
+ , fDeferAddingOwners(false) {
SkSafeRef(storage);
}
if (heapEntry->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.
+ // recently used one can not have used all its references yet either.
return NULL;
}
if (replacement.getGenerationID() == iter->fGenerationId) {
if (entry) {
// Already had a copy of the bitmap in the heap.
if (fOwnerCount != IGNORE_OWNERS) {
- entry->addReferences(fOwnerCount);
+ if (fDeferAddingOwners) {
+ *fDeferredEntries.append() = entry->fSlot;
+ } else {
+ entry->addReferences(fOwnerCount);
+ }
}
if (fPreferredCount != UNLIMITED_SIZE) {
LookupEntry* lookupEntry = fLookupTable[searchIndex];
}
return entry->fSlot;
}
+
+void SkBitmapHeap::deferAddingOwners() {
+ fDeferAddingOwners = true;
+}
+
+void SkBitmapHeap::endAddingOwnersDeferral(bool add) {
+ if (add) {
+ for (int i = 0; i < fDeferredEntries.count(); i++) {
+ SkASSERT(fOwnerCount != IGNORE_OWNERS);
+ SkBitmapHeapEntry* heapEntry = this->getEntry(fDeferredEntries[i]);
+ SkASSERT(heapEntry != NULL);
+ heapEntry->addReferences(fOwnerCount);
+ }
+ }
+ fDeferAddingOwners = false;
+ fDeferredEntries.reset();
+}
*/
size_t freeMemoryIfPossible(size_t bytesToFree);
+ /**
+ * Defer any increments of owner counts until endAddingOwnersDeferral is called. So if an
+ * existing SkBitmap is inserted into the SkBitmapHeap, its corresponding SkBitmapHeapEntry will
+ * not have addReferences called on it, and the client does not need to make a corresponding
+ * call to releaseRef. Only meaningful if this SkBitmapHeap was created with an owner count not
+ * equal to IGNORE_OWNERS.
+ */
+ void deferAddingOwners();
+
+ /**
+ * Resume adding references when duplicate SkBitmaps are inserted.
+ * @param add If true, add references to the SkBitmapHeapEntrys whose SkBitmaps were re-inserted
+ * while deferring.
+ */
+ void endAddingOwnersDeferral(bool add);
+
private:
struct LookupEntry {
LookupEntry(const SkBitmap& bm)
const int32_t fOwnerCount;
size_t fBytesAllocated;
+ bool fDeferAddingOwners;
+ SkTDArray<int> fDeferredEntries;
+
typedef SkBitmapHeapReader INHERITED;
};
~SkRefCntTDArray() { this->unrefAll(); }
};
-class SkGPipeState {
+class SkGPipeState : public SkBitmapHeapReader {
public:
SkGPipeState();
~SkGPipeState();
bm->unflatten(*fReader);
}
- SkBitmap* getBitmap(unsigned index) {
+ /**
+ * Override of SkBitmapHeapReader, so that SkOrderedReadBuffer can use
+ * these SkBitmaps for bitmap shaders.
+ */
+ virtual SkBitmap* getBitmap(int32_t index) const SK_OVERRIDE {
return fBitmaps[index];
}
+ /**
+ * Needed to be a non-abstract subclass of SkBitmapHeapReader.
+ */
+ virtual void releaseRef(int32_t) SK_OVERRIDE {}
+
void setSharedHeap(SkBitmapHeap* heap) {
SkASSERT(!shouldFlattenBitmaps(fFlags) || NULL == heap);
SkRefCnt_SafeAssign(fSharedHeap, heap);
+ this->updateReader();
}
SkBitmapHeap* getSharedHeap() const {
} else {
fReader->setFactoryArray(NULL);
}
+
+ if (shouldFlattenBitmaps(fFlags)) {
+ fReader->setBitmapStorage(this);
+ } else {
+ fReader->setBitmapStorage(fSharedHeap);
+ }
}
SkOrderedReadBuffer* fReader;
SkPaint fPaint;
virtual void unalloc(void* ptr) SK_OVERRIDE;
+ void setBitmapStorage(SkBitmapHeap* heap) {
+ this->setBitmapHeap(heap);
+ }
+
const SkFlatData* flatToReplace() const;
// Mark an SkFlatData as one that should not be returned by flatToReplace.
// there is no circular reference, so the SharedHeap can be
// safely unreffed in the destructor.
fSharedHeap->unref();
+ // This eliminates a similar circular reference (Canvas owns
+ // the FlattenableHeap which holds a ref to fSharedHeap).
+ fFlattenableHeap.setBitmapStorage(NULL);
fSharedHeap = NULL;
}
}
if (isCrossProcess(fFlags)) {
writeBufferFlags = SkFlattenableWriteBuffer::kCrossProcess_Flag;
} else {
- // Needed for bitmap shaders.
- writeBufferFlags = SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag;
+ // TODO: See if we can safely move this into the controller
+ writeBufferFlags = 0;
}
+ fSharedHeap->deferAddingOwners();
bool added, replaced;
const SkFlatData* flat = fFlatDictionary.findAndReplace(
*obj, writeBufferFlags, fFlattenableHeap.flatToReplace(), &added, &replaced);
+ fSharedHeap->endAddingOwnersDeferral(added);
int index = flat->index();
if (added) {
if (isCrossProcess(fFlags)) {
fWriter.writePtr(static_cast<void*>(fSharedHeap));
}
}
+ fFlattenableHeap.setBitmapStorage(fSharedHeap);
this->doNotify();
}