ef284a84f5
missing unrefs in megalooper GM missing reset capability in oval renderer This CL also expands the instance counting system to some recently adding classes (e.g., SkFontStyleSet) R=bsalomon@google.com, jvanverth@google.com Author: robertphillips@google.com Review URL: https://chromiumcodereview.appspot.com/18461007 git-svn-id: http://skia.googlecode.com/svn/trunk@10030 2bbb7eff-a529-9590-31e7-b0007b416f81
207 lines
5.4 KiB
C++
207 lines
5.4 KiB
C++
/*
|
|
* Copyright 2013 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "SkLruImageCache.h"
|
|
|
|
SK_DEFINE_INST_COUNT(SkImageCache)
|
|
SK_DEFINE_INST_COUNT(SkLruImageCache)
|
|
|
|
static intptr_t NextGenerationID() {
|
|
static intptr_t gNextID;
|
|
do {
|
|
gNextID++;
|
|
} while (SkImageCache::UNINITIALIZED_ID == gNextID);
|
|
return gNextID;
|
|
}
|
|
|
|
class CachedPixels : public SkNoncopyable {
|
|
|
|
public:
|
|
CachedPixels(size_t length)
|
|
: fLength(length)
|
|
, fID(NextGenerationID())
|
|
, fLocked(false) {
|
|
fAddr = sk_malloc_throw(length);
|
|
}
|
|
|
|
~CachedPixels() {
|
|
sk_free(fAddr);
|
|
}
|
|
|
|
void* getData() { return fAddr; }
|
|
|
|
intptr_t getID() const { return fID; }
|
|
|
|
size_t getLength() const { return fLength; }
|
|
|
|
void lock() { SkASSERT(!fLocked); fLocked = true; }
|
|
|
|
void unlock() { SkASSERT(fLocked); fLocked = false; }
|
|
|
|
bool isLocked() const { return fLocked; }
|
|
|
|
private:
|
|
void* fAddr;
|
|
size_t fLength;
|
|
const intptr_t fID;
|
|
bool fLocked;
|
|
SK_DECLARE_INTERNAL_LLIST_INTERFACE(CachedPixels);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
SkLruImageCache::SkLruImageCache(size_t budget)
|
|
: fRamBudget(budget)
|
|
, fRamUsed(0) {}
|
|
|
|
SkLruImageCache::~SkLruImageCache() {
|
|
// Don't worry about updating pointers. All will be deleted.
|
|
Iter iter;
|
|
CachedPixels* pixels = iter.init(fLRU, Iter::kTail_IterStart);
|
|
while (pixels != NULL) {
|
|
CachedPixels* prev = iter.prev();
|
|
SkASSERT(!pixels->isLocked());
|
|
#ifdef SK_DEBUG
|
|
fRamUsed -= pixels->getLength();
|
|
#endif
|
|
SkDELETE(pixels);
|
|
pixels = prev;
|
|
}
|
|
#ifdef SK_DEBUG
|
|
SkASSERT(fRamUsed == 0);
|
|
#endif
|
|
}
|
|
|
|
#ifdef SK_DEBUG
|
|
SkImageCache::MemoryStatus SkLruImageCache::getMemoryStatus(intptr_t ID) const {
|
|
if (SkImageCache::UNINITIALIZED_ID == ID) {
|
|
return SkImageCache::kFreed_MemoryStatus;
|
|
}
|
|
SkAutoMutexAcquire ac(&fMutex);
|
|
CachedPixels* pixels = this->findByID(ID);
|
|
if (NULL == pixels) {
|
|
return SkImageCache::kFreed_MemoryStatus;
|
|
}
|
|
if (pixels->isLocked()) {
|
|
return SkImageCache::kPinned_MemoryStatus;
|
|
}
|
|
return SkImageCache::kUnpinned_MemoryStatus;
|
|
}
|
|
|
|
void SkLruImageCache::purgeAllUnpinnedCaches() {
|
|
SkAutoMutexAcquire ac(&fMutex);
|
|
this->purgeTilAtOrBelow(0);
|
|
}
|
|
#endif
|
|
|
|
size_t SkLruImageCache::setImageCacheLimit(size_t newLimit) {
|
|
size_t oldLimit = fRamBudget;
|
|
SkAutoMutexAcquire ac(&fMutex);
|
|
fRamBudget = newLimit;
|
|
this->purgeIfNeeded();
|
|
return oldLimit;
|
|
}
|
|
|
|
void* SkLruImageCache::allocAndPinCache(size_t bytes, intptr_t* ID) {
|
|
SkAutoMutexAcquire ac(&fMutex);
|
|
CachedPixels* pixels = SkNEW_ARGS(CachedPixels, (bytes));
|
|
if (ID != NULL) {
|
|
*ID = pixels->getID();
|
|
}
|
|
pixels->lock();
|
|
fRamUsed += bytes;
|
|
fLRU.addToHead(pixels);
|
|
this->purgeIfNeeded();
|
|
return pixels->getData();
|
|
}
|
|
|
|
void* SkLruImageCache::pinCache(intptr_t ID, SkImageCache::DataStatus* status) {
|
|
SkASSERT(ID != SkImageCache::UNINITIALIZED_ID);
|
|
SkAutoMutexAcquire ac(&fMutex);
|
|
CachedPixels* pixels = this->findByID(ID);
|
|
if (NULL == pixels) {
|
|
return NULL;
|
|
}
|
|
if (pixels != fLRU.head()) {
|
|
fLRU.remove(pixels);
|
|
fLRU.addToHead(pixels);
|
|
}
|
|
SkASSERT(status != NULL);
|
|
// This cache will never return pinned memory whose data has been overwritten.
|
|
*status = SkImageCache::kRetained_DataStatus;
|
|
pixels->lock();
|
|
return pixels->getData();
|
|
}
|
|
|
|
void SkLruImageCache::releaseCache(intptr_t ID) {
|
|
SkASSERT(ID != SkImageCache::UNINITIALIZED_ID);
|
|
SkAutoMutexAcquire ac(&fMutex);
|
|
CachedPixels* pixels = this->findByID(ID);
|
|
SkASSERT(pixels != NULL);
|
|
pixels->unlock();
|
|
this->purgeIfNeeded();
|
|
}
|
|
|
|
void SkLruImageCache::throwAwayCache(intptr_t ID) {
|
|
SkASSERT(ID != SkImageCache::UNINITIALIZED_ID);
|
|
SkAutoMutexAcquire ac(&fMutex);
|
|
CachedPixels* pixels = this->findByID(ID);
|
|
if (pixels != NULL) {
|
|
if (pixels->isLocked()) {
|
|
pixels->unlock();
|
|
}
|
|
this->removePixels(pixels);
|
|
}
|
|
}
|
|
|
|
void SkLruImageCache::removePixels(CachedPixels* pixels) {
|
|
// Mutex is already locked.
|
|
SkASSERT(!pixels->isLocked());
|
|
const size_t size = pixels->getLength();
|
|
SkASSERT(size <= fRamUsed);
|
|
fLRU.remove(pixels);
|
|
SkDELETE(pixels);
|
|
fRamUsed -= size;
|
|
}
|
|
|
|
CachedPixels* SkLruImageCache::findByID(intptr_t ID) const {
|
|
// Mutex is already locked.
|
|
Iter iter;
|
|
// Start from the head, most recently used.
|
|
CachedPixels* pixels = iter.init(fLRU, Iter::kHead_IterStart);
|
|
while (pixels != NULL) {
|
|
if (pixels->getID() == ID) {
|
|
return pixels;
|
|
}
|
|
pixels = iter.next();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void SkLruImageCache::purgeIfNeeded() {
|
|
// Mutex is already locked.
|
|
if (fRamBudget > 0) {
|
|
this->purgeTilAtOrBelow(fRamBudget);
|
|
}
|
|
}
|
|
|
|
void SkLruImageCache::purgeTilAtOrBelow(size_t limit) {
|
|
// Mutex is already locked.
|
|
if (fRamUsed > limit) {
|
|
Iter iter;
|
|
// Start from the tail, least recently used.
|
|
CachedPixels* pixels = iter.init(fLRU, Iter::kTail_IterStart);
|
|
while (pixels != NULL && fRamUsed > limit) {
|
|
CachedPixels* prev = iter.prev();
|
|
if (!pixels->isLocked()) {
|
|
this->removePixels(pixels);
|
|
}
|
|
pixels = prev;
|
|
}
|
|
}
|
|
}
|