| Index: skia/gl/SkTextureCache.cpp
|
| ===================================================================
|
| --- skia/gl/SkTextureCache.cpp (revision 16859)
|
| +++ skia/gl/SkTextureCache.cpp (working copy)
|
| @@ -1,363 +0,0 @@
|
| -#include "SkTextureCache.h"
|
| -
|
| -//#define TRACE_HASH_HITS
|
| -//#define TRACE_TEXTURE_CACHE_PURGE
|
| -
|
| -SkTextureCache::Entry::Entry(const SkBitmap& bitmap)
|
| - : fName(0), fKey(bitmap), fPrev(NULL), fNext(NULL) {
|
| -
|
| - fMemSize = SkGL::ComputeTextureMemorySize(bitmap);
|
| - fLockCount = 0;
|
| -}
|
| -
|
| -SkTextureCache::Entry::~Entry() {
|
| - if (fName != 0) {
|
| - glDeleteTextures(1, &fName);
|
| - }
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -SkTextureCache::SkTextureCache(size_t countMax, size_t sizeMax)
|
| - : fHead(NULL), fTail(NULL),
|
| - fTexCountMax(countMax), fTexSizeMax(sizeMax),
|
| - fTexCount(0), fTexSize(0) {
|
| -
|
| - bzero(fHash, sizeof(fHash));
|
| - this->validate();
|
| -}
|
| -
|
| -SkTextureCache::~SkTextureCache() {
|
| -#ifdef SK_DEBUG
|
| - Entry* entry = fHead;
|
| - while (entry) {
|
| - SkASSERT(entry->lockCount() == 0);
|
| - entry = entry->fNext;
|
| - }
|
| -#endif
|
| - this->validate();
|
| -}
|
| -
|
| -void SkTextureCache::deleteAllCaches(bool texturesAreValid) {
|
| - this->validate();
|
| -
|
| - Entry* entry = fHead;
|
| - while (entry) {
|
| - Entry* next = entry->fNext;
|
| - if (!texturesAreValid) {
|
| - entry->abandonTexture();
|
| - }
|
| - SkDELETE(entry);
|
| - entry = next;
|
| - }
|
| -
|
| - fSorted.reset();
|
| - bzero(fHash, sizeof(fHash));
|
| -
|
| - fTexCount = 0;
|
| - fTexSize = 0;
|
| -
|
| - fTail = fHead = NULL;
|
| -
|
| - this->validate();
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -int SkTextureCache::findInSorted(const Key& key) const {
|
| - int count = fSorted.count();
|
| - if (count == 0) {
|
| - return ~0;
|
| - }
|
| -
|
| - Entry** sorted = fSorted.begin();
|
| - int lo = 0;
|
| - int hi = count - 1;
|
| - while (lo < hi) {
|
| - int mid = (hi + lo) >> 1;
|
| - if (sorted[mid]->getKey() < key) {
|
| - lo = mid + 1;
|
| - } else {
|
| - hi = mid;
|
| - }
|
| - }
|
| -
|
| - // hi is now our best guess
|
| - const Entry* entry = sorted[hi];
|
| - if (entry->getKey() == key) {
|
| - return hi;
|
| - }
|
| -
|
| - // return where to insert it
|
| - if (entry->getKey() < key) {
|
| - hi += 1;
|
| - }
|
| - return ~hi; // we twiddle to indicate not-found
|
| -}
|
| -
|
| -#ifdef TRACE_HASH_HITS
|
| -static int gHashHits;
|
| -static int gSortedHits;
|
| -#endif
|
| -
|
| -SkTextureCache::Entry* SkTextureCache::find(const Key& key, int* insert) const {
|
| - int count = fSorted.count();
|
| - if (count == 0) {
|
| - *insert = 0;
|
| - return NULL;
|
| - }
|
| -
|
| - // check the hash first
|
| - int hashIndex = key.getHashIndex();
|
| - Entry* entry = fHash[hashIndex];
|
| - if (NULL != entry && entry->getKey() == key) {
|
| -#ifdef TRACE_HASH_HITS
|
| - gHashHits += 1;
|
| -#endif
|
| - return entry;
|
| - }
|
| -
|
| - int index = this->findInSorted(key);
|
| - if (index >= 0) {
|
| -#ifdef TRACE_HASH_HITS
|
| - gSortedHits += 1;
|
| -#endif
|
| - entry = fSorted[index];
|
| - fHash[hashIndex] = entry;
|
| - return entry;
|
| - }
|
| -
|
| - // ~index is where to insert the entry
|
| - *insert = ~index;
|
| - return NULL;
|
| -}
|
| -
|
| -SkTextureCache::Entry* SkTextureCache::lock(const SkBitmap& bitmap) {
|
| - this->validate();
|
| -
|
| - // call this before we call find(), so we don't reorder after find() and
|
| - // invalidate our index
|
| - this->purgeIfNecessary(SkGL::ComputeTextureMemorySize(bitmap));
|
| -
|
| - Key key(bitmap);
|
| - int index;
|
| - Entry* entry = this->find(key, &index);
|
| -
|
| - if (NULL == entry) {
|
| - entry = SkNEW_ARGS(Entry, (bitmap));
|
| -
|
| - entry->fName = SkGL::BindNewTexture(bitmap, &entry->fTexSize);
|
| - if (0 == entry->fName) {
|
| - SkDELETE(entry);
|
| - return NULL;
|
| - }
|
| - fHash[key.getHashIndex()] = entry;
|
| - *fSorted.insert(index) = entry;
|
| -
|
| - fTexCount += 1;
|
| - fTexSize += entry->memSize();
|
| - } else {
|
| - // detach from our llist
|
| - Entry* prev = entry->fPrev;
|
| - Entry* next = entry->fNext;
|
| - if (prev) {
|
| - prev->fNext = next;
|
| - } else {
|
| - SkASSERT(fHead == entry);
|
| - fHead = next;
|
| - }
|
| - if (next) {
|
| - next->fPrev = prev;
|
| - } else {
|
| - SkASSERT(fTail == entry);
|
| - fTail = prev;
|
| - }
|
| - // now bind the texture
|
| - glBindTexture(GL_TEXTURE_2D, entry->fName);
|
| - }
|
| -
|
| - // add to head of llist for LRU
|
| - entry->fPrev = NULL;
|
| - entry->fNext = fHead;
|
| - if (NULL != fHead) {
|
| - SkASSERT(NULL == fHead->fPrev);
|
| - fHead->fPrev = entry;
|
| - }
|
| - fHead = entry;
|
| - if (NULL == fTail) {
|
| - fTail = entry;
|
| - }
|
| -
|
| - this->validate();
|
| - entry->lock();
|
| -
|
| -#ifdef TRACE_HASH_HITS
|
| - SkDebugf("---- texture cache hash=%d sorted=%d\n", gHashHits, gSortedHits);
|
| -#endif
|
| - return entry;
|
| -}
|
| -
|
| -void SkTextureCache::unlock(Entry* entry) {
|
| - this->validate();
|
| -
|
| -#ifdef SK_DEBUG
|
| - SkASSERT(entry);
|
| - int index = this->findInSorted(entry->getKey());
|
| - SkASSERT(fSorted[index] == entry);
|
| -#endif
|
| -
|
| - SkASSERT(entry->fLockCount > 0);
|
| - entry->unlock();
|
| -}
|
| -
|
| -void SkTextureCache::purgeIfNecessary(size_t extraSize) {
|
| - this->validate();
|
| -
|
| - size_t countMax = fTexCountMax;
|
| - size_t sizeMax = fTexSizeMax;
|
| -
|
| - // take extraSize into account, but watch for underflow of size_t
|
| - if (extraSize > sizeMax) {
|
| - sizeMax = 0;
|
| - } else {
|
| - sizeMax -= extraSize;
|
| - }
|
| -
|
| - Entry* entry = fTail;
|
| - while (entry) {
|
| - if (fTexCount <= countMax && fTexSize <= sizeMax) {
|
| - break;
|
| - }
|
| -
|
| - Entry* prev = entry->fPrev;
|
| - // don't purge an entry that is locked
|
| - if (entry->isLocked()) {
|
| - entry = prev;
|
| - continue;
|
| - }
|
| -
|
| - fTexCount -= 1;
|
| - fTexSize -= entry->memSize();
|
| -
|
| - // remove from our sorted and hash arrays
|
| - int index = this->findInSorted(entry->getKey());
|
| - SkASSERT(index >= 0);
|
| - fSorted.remove(index);
|
| - index = entry->getKey().getHashIndex();
|
| - if (entry == fHash[index]) {
|
| - fHash[index] = NULL;
|
| - }
|
| -
|
| - // now detach it from our llist
|
| - Entry* next = entry->fNext;
|
| - if (prev) {
|
| - prev->fNext = next;
|
| - } else {
|
| - fHead = next;
|
| - }
|
| - if (next) {
|
| - next->fPrev = prev;
|
| - } else {
|
| - fTail = prev;
|
| - }
|
| -
|
| - // now delete it
|
| -#ifdef TRACE_TEXTURE_CACHE_PURGE
|
| - SkDebugf("---- purge texture cache %d size=%d\n",
|
| - entry->name(), entry->memSize());
|
| -#endif
|
| - SkDELETE(entry);
|
| -
|
| - // keep going
|
| - entry = prev;
|
| - }
|
| -
|
| - this->validate();
|
| -}
|
| -
|
| -void SkTextureCache::setMaxCount(size_t count) {
|
| - if (fTexCountMax != count) {
|
| - fTexCountMax = count;
|
| - this->purgeIfNecessary(0);
|
| - }
|
| -}
|
| -
|
| -void SkTextureCache::setMaxSize(size_t size) {
|
| - if (fTexSizeMax != size) {
|
| - fTexSizeMax = size;
|
| - this->purgeIfNecessary(0);
|
| - }
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -
|
| -#ifdef SK_DEBUG
|
| -void SkTextureCache::validate() const {
|
| - if (0 == fTexCount) {
|
| - SkASSERT(0 == fTexSize);
|
| - SkASSERT(NULL == fHead);
|
| - SkASSERT(NULL == fTail);
|
| - return;
|
| - }
|
| -
|
| - SkASSERT(fTexSize); // do we allow a zero-sized texture?
|
| - SkASSERT(fHead);
|
| - SkASSERT(fTail);
|
| -
|
| - SkASSERT(NULL == fHead->fPrev);
|
| - SkASSERT(NULL == fTail->fNext);
|
| - if (1 == fTexCount) {
|
| - SkASSERT(fHead == fTail);
|
| - }
|
| -
|
| - const Entry* entry = fHead;
|
| - size_t count = 0;
|
| - size_t size = 0;
|
| - size_t i;
|
| -
|
| - while (entry != NULL) {
|
| - SkASSERT(count < fTexCount);
|
| - SkASSERT(size < fTexSize);
|
| - size += entry->memSize();
|
| - count += 1;
|
| - if (NULL == entry->fNext) {
|
| - SkASSERT(fTail == entry);
|
| - }
|
| - entry = entry->fNext;
|
| - }
|
| - SkASSERT(count == fTexCount);
|
| - SkASSERT(size == fTexSize);
|
| -
|
| - count = 0;
|
| - size = 0;
|
| - entry = fTail;
|
| - while (entry != NULL) {
|
| - SkASSERT(count < fTexCount);
|
| - SkASSERT(size < fTexSize);
|
| - size += entry->memSize();
|
| - count += 1;
|
| - if (NULL == entry->fPrev) {
|
| - SkASSERT(fHead == entry);
|
| - }
|
| - entry = entry->fPrev;
|
| - }
|
| - SkASSERT(count == fTexCount);
|
| - SkASSERT(size == fTexSize);
|
| -
|
| - SkASSERT(count == (size_t)fSorted.count());
|
| - for (i = 1; i < count; i++) {
|
| - SkASSERT(fSorted[i-1]->getKey() < fSorted[i]->getKey());
|
| - }
|
| -
|
| - for (i = 0; i < kHashCount; i++) {
|
| - if (fHash[i]) {
|
| - size_t index = fHash[i]->getKey().getHashIndex();
|
| - SkASSERT(index == i);
|
| - index = fSorted.find(fHash[i]);
|
| - SkASSERT((size_t)index < count);
|
| - }
|
| - }
|
| -}
|
| -#endif
|
| -
|
| -
|
|
|