| |
| /* |
| * 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 |
| } |