diff options
author | 2011-02-22 20:50:57 +0000 | |
---|---|---|
committer | 2011-02-22 20:50:57 +0000 | |
commit | 5d32fc4c1cb2a5ee68cd5e195a5959f800cc3bc7 (patch) | |
tree | b57f70a53cf4f87f68bd833ebd8fae3e17f7f833 /obsolete/SkTextureCache.cpp | |
parent | ffca400ef6f96a280c3e2c09210f950af64a1f24 (diff) |
move old (unmaintained) gl backend out of src. src/gpu superceeds this now.
Will delete the files in obsolete/ at some point...
git-svn-id: http://skia.googlecode.com/svn/trunk@830 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'obsolete/SkTextureCache.cpp')
-rw-r--r-- | obsolete/SkTextureCache.cpp | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/obsolete/SkTextureCache.cpp b/obsolete/SkTextureCache.cpp new file mode 100644 index 0000000000..2eb5d84e36 --- /dev/null +++ b/obsolete/SkTextureCache.cpp @@ -0,0 +1,363 @@ +#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) { + + sk_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(); + sk_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 + + |