aboutsummaryrefslogtreecommitdiffhomepage
path: root/obsolete/SkTextureCache.cpp
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-02-22 20:50:57 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-02-22 20:50:57 +0000
commit5d32fc4c1cb2a5ee68cd5e195a5959f800cc3bc7 (patch)
treeb57f70a53cf4f87f68bd833ebd8fae3e17f7f833 /obsolete/SkTextureCache.cpp
parentffca400ef6f96a280c3e2c09210f950af64a1f24 (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.cpp363
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
+
+