/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkImageRefPool.h" #include "SkImageRef.h" #include "SkThread.h" SkImageRefPool::SkImageRefPool() { fRAMBudget = 0; // means no explicit limit fRAMUsed = 0; fCount = 0; fHead = fTail = NULL; } SkImageRefPool::~SkImageRefPool() { // SkASSERT(NULL == fHead); } void SkImageRefPool::setRAMBudget(size_t size) { if (fRAMBudget != size) { fRAMBudget = size; this->purgeIfNeeded(); } } void SkImageRefPool::justAddedPixels(SkImageRef* ref) { #ifdef DUMP_IMAGEREF_LIFECYCLE SkDebugf("=== ImagePool: add pixels %s [%d %d %d] bytes=%d heap=%d\n", ref->getURI(), ref->fBitmap.width(), ref->fBitmap.height(), ref->fBitmap.bytesPerPixel(), ref->fBitmap.getSize(), (int)fRAMUsed); #endif fRAMUsed += ref->ramUsed(); this->purgeIfNeeded(); } void SkImageRefPool::canLosePixels(SkImageRef* ref) { // the refs near fHead have recently been released (used) // if we purge, we purge from the tail this->detach(ref); this->addToHead(ref); this->purgeIfNeeded(); } void SkImageRefPool::purgeIfNeeded() { // do nothing if we have a zero-budget (i.e. unlimited) if (fRAMBudget != 0) { this->setRAMUsed(fRAMBudget); } } void SkImageRefPool::setRAMUsed(size_t limit) { SkImageRef* ref = fTail; while (NULL != ref && fRAMUsed > limit) { // only purge it if its pixels are unlocked if (!ref->isLocked() && ref->fBitmap.getPixels()) { size_t size = ref->ramUsed(); SkASSERT(size <= fRAMUsed); fRAMUsed -= size; #ifdef DUMP_IMAGEREF_LIFECYCLE SkDebugf("=== ImagePool: purge %s [%d %d %d] bytes=%d heap=%d\n", ref->getURI(), ref->fBitmap.width(), ref->fBitmap.height(), ref->fBitmap.bytesPerPixel(), (int)size, (int)fRAMUsed); #endif // remember the bitmap config (don't call reset), // just clear the pixel memory ref->fBitmap.setPixels(NULL); SkASSERT(NULL == ref->fBitmap.getPixels()); } ref = ref->fPrev; } } /////////////////////////////////////////////////////////////////////////////// void SkImageRefPool::addToHead(SkImageRef* ref) { ref->fNext = fHead; ref->fPrev = NULL; if (fHead) { SkASSERT(NULL == fHead->fPrev); fHead->fPrev = ref; } fHead = ref; if (NULL == fTail) { fTail = ref; } fCount += 1; SkASSERT(computeCount() == fCount); fRAMUsed += ref->ramUsed(); } void SkImageRefPool::addToTail(SkImageRef* ref) { ref->fNext = NULL; ref->fPrev = fTail; if (fTail) { SkASSERT(NULL == fTail->fNext); fTail->fNext = ref; } fTail = ref; if (NULL == fHead) { fHead = ref; } fCount += 1; SkASSERT(computeCount() == fCount); fRAMUsed += ref->ramUsed(); } void SkImageRefPool::detach(SkImageRef* ref) { SkASSERT(fCount > 0); if (fHead == ref) { fHead = ref->fNext; } if (fTail == ref) { fTail = ref->fPrev; } if (ref->fPrev) { ref->fPrev->fNext = ref->fNext; } if (ref->fNext) { ref->fNext->fPrev = ref->fPrev; } ref->fNext = ref->fPrev = NULL; fCount -= 1; SkASSERT(computeCount() == fCount); SkASSERT(fRAMUsed >= ref->ramUsed()); fRAMUsed -= ref->ramUsed(); } int SkImageRefPool::computeCount() const { SkImageRef* ref = fHead; int count = 0; while (ref != NULL) { count += 1; ref = ref->fNext; } #ifdef SK_DEBUG ref = fTail; int count2 = 0; while (ref != NULL) { count2 += 1; ref = ref->fPrev; } SkASSERT(count2 == count); #endif return count; } /////////////////////////////////////////////////////////////////////////////// #include "SkStream.h" void SkImageRefPool::dump() const { #if defined(SK_DEBUG) || defined(DUMP_IMAGEREF_LIFECYCLE) SkDebugf("ImagePool dump: bugdet: %d used: %d count: %d\n", (int)fRAMBudget, (int)fRAMUsed, fCount); SkImageRef* ref = fHead; while (ref != NULL) { SkDebugf(" [%3d %3d %d] ram=%d data=%d locked=%d %s\n", ref->fBitmap.width(), ref->fBitmap.height(), ref->fBitmap.config(), ref->ramUsed(), (int)ref->fStream->getLength(), ref->isLocked(), ref->getURI()); ref = ref->fNext; } #endif }