Optimize FBO cache.

This change introduces a new generational cache called GenerationMultiCache
that can store several values with the same key. This can be used to use
multiple layers of the same size at the same time, without recreating them
over and over again.

Change-Id: I425466a20908b862c5f464a0f9e582ec18cbd7ac
diff --git a/libs/hwui/GenerationCache.h b/libs/hwui/GenerationCache.h
index d92a0bb..5f64a35 100644
--- a/libs/hwui/GenerationCache.h
+++ b/libs/hwui/GenerationCache.h
@@ -20,9 +20,68 @@
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
 
+#include "SortedList.h"
+
 namespace android {
 namespace uirenderer {
 
+template<typename K, typename V>
+class GenerationCacheStorage {
+public:
+    virtual ~GenerationCacheStorage();
+
+    virtual size_t size() const = 0;
+    virtual void clear() = 0;
+    virtual ssize_t add(const K& key, const V& item) = 0;
+    virtual ssize_t indexOfKey(const K& key) const = 0;
+    virtual const V& valueAt(size_t index) const = 0;
+    virtual ssize_t removeItemsAt(size_t index, size_t count) = 0;
+}; // GenerationCacheStorage
+
+template<typename K, typename V>
+GenerationCacheStorage<K, V>::~GenerationCacheStorage() {
+}
+
+template<typename K, typename V>
+class KeyedVectorStorage: public GenerationCacheStorage<K, V> {
+public:
+    KeyedVectorStorage() { }
+    ~KeyedVectorStorage() { }
+
+    inline size_t size() const { return mStorage.size(); }
+    inline void clear() { mStorage.clear(); }
+    inline ssize_t add(const K& key, const V& value) { return mStorage.add(key, value); }
+    inline ssize_t indexOfKey(const K& key) const { return mStorage.indexOfKey(key); }
+    inline const V& valueAt(size_t index) const { return mStorage.valueAt(index); }
+    inline ssize_t removeItemsAt(size_t index, size_t count) {
+        return mStorage.removeItemsAt(index, count);
+    }
+private:
+    KeyedVector<K, V> mStorage;
+}; // class KeyedVectorStorage
+
+template<typename K, typename V>
+class SortedListStorage: public GenerationCacheStorage<K, V> {
+public:
+    SortedListStorage() { }
+    ~SortedListStorage() { }
+
+    inline size_t size() const { return mStorage.size(); }
+    inline void clear() { mStorage.clear(); }
+    inline ssize_t add(const K& key, const V& value) {
+        return mStorage.add(key_value_pair_t<K, V>(key, value));
+    }
+    inline ssize_t indexOfKey(const K& key) const {
+        return mStorage.indexOf(key_value_pair_t<K, V>(key));
+    }
+    inline const V& valueAt(size_t index) const { return mStorage.itemAt(index).value; }
+    inline ssize_t removeItemsAt(size_t index, size_t count) {
+        return mStorage.removeItemsAt(index, count);
+    }
+private:
+    SortedList<key_value_pair_t<K, V> > mStorage;
+}; // class SortedListStorage
+
 template<typename EntryKey, typename EntryValue>
 class OnEntryRemoved {
 public:
@@ -30,11 +89,27 @@
     virtual void operator()(EntryKey& key, EntryValue& value) = 0;
 }; // class OnEntryRemoved
 
+template<typename EntryKey, typename EntryValue>
+struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > {
+    Entry() { }
+    Entry(const Entry<EntryKey, EntryValue>& e):
+            key(e.key), value(e.value), index(e.index), parent(e.parent), child(e.child) { }
+    Entry(sp<Entry<EntryKey, EntryValue> > e):
+            key(e->key), value(e->value), index(e->index), parent(e->parent), child(e->child) { }
+
+    EntryKey key;
+    EntryValue value;
+    ssize_t index;
+
+    sp<Entry<EntryKey, EntryValue> > parent;
+    sp<Entry<EntryKey, EntryValue> > child;
+}; // struct Entry
+
 template<typename K, typename V>
 class GenerationCache {
 public:
-    GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) { };
-    ~GenerationCache() { clear(); };
+    GenerationCache(uint32_t maxCapacity);
+    virtual ~GenerationCache();
 
     enum Capacity {
         kUnlimitedCapacity,
@@ -52,39 +127,64 @@
 
     uint32_t size() const;
 
+protected:
+    virtual GenerationCacheStorage<K, sp<Entry<K, V> > >* createStorage() = 0;
+    GenerationCacheStorage<K, sp<Entry<K, V> > >* mCache;
+
 private:
-    template<typename EntryKey, typename EntryValue>
-    struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > {
-        Entry() { }
-        Entry(const Entry<EntryKey, EntryValue>& e):
-                key(e.key), value(e.value), parent(e.parent), child(e.child) { }
-        Entry(sp<Entry<EntryKey, EntryValue> > e):
-                key(e->key), value(e->value), parent(e->parent), child(e->child) { }
-
-        EntryKey key;
-        EntryValue value;
-
-        sp<Entry<EntryKey, EntryValue> > parent;
-        sp<Entry<EntryKey, EntryValue> > child;
-    }; // struct Entry
-
     void addToCache(sp<Entry<K, V> > entry, K key, V value);
     void attachToCache(sp<Entry<K, V> > entry);
     void detachFromCache(sp<Entry<K, V> > entry);
 
+    V removeAt(ssize_t index);
+
     uint32_t mMaxCapacity;
 
     OnEntryRemoved<K, V>* mListener;
 
-    KeyedVector<K, sp<Entry<K, V> > > mCache;
-
     sp<Entry<K, V> > mOldest;
-    sp<Entry<K, V> > mYougest;
+    sp<Entry<K, V> > mYoungest;
 }; // class GenerationCache
 
 template<typename K, typename V>
+class GenerationSingleCache: public GenerationCache<K, V> {
+public:
+    GenerationSingleCache(uint32_t maxCapacity): GenerationCache<K, V>(maxCapacity) {
+        GenerationCache<K, V>::mCache = createStorage();
+    };
+    ~GenerationSingleCache() { }
+protected:
+    GenerationCacheStorage<K, sp<Entry<K, V> > >* createStorage() {
+        return new KeyedVectorStorage<K, sp<Entry<K, V> > >;
+    }
+}; // GenerationSingleCache
+
+template<typename K, typename V>
+class GenerationMultiCache: public GenerationCache<K, V> {
+public:
+    GenerationMultiCache(uint32_t maxCapacity): GenerationCache<K, V>(maxCapacity) {
+        GenerationCache<K, V>::mCache = createStorage();
+    };
+    ~GenerationMultiCache() { }
+protected:
+    GenerationCacheStorage<K, sp<Entry<K, V> > >* createStorage() {
+        return new SortedListStorage<K, sp<Entry<K, V> > >;
+    }
+}; // GenerationMultiCache
+
+template<typename K, typename V>
+GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) {
+};
+
+template<typename K, typename V>
+GenerationCache<K, V>::~GenerationCache() {
+    clear();
+    delete mCache;
+};
+
+template<typename K, typename V>
 uint32_t GenerationCache<K, V>::size() const {
-    return mCache.size();
+    return mCache->size();
 }
 
 template<typename K, typename V>
@@ -95,26 +195,26 @@
 template<typename K, typename V>
 void GenerationCache<K, V>::clear() {
     if (mListener) {
-        while (mCache.size() > 0) {
+        while (mCache->size() > 0) {
             removeOldest();
         }
     } else {
-        mCache.clear();
+        mCache->clear();
     }
-    mYougest.clear();
+    mYoungest.clear();
     mOldest.clear();
 }
 
 template<typename K, typename V>
 bool GenerationCache<K, V>::contains(K key) const {
-    return mCache.indexOfKey(key) >= 0;
+    return mCache->indexOfKey(key) >= 0;
 }
 
 template<typename K, typename V>
 V GenerationCache<K, V>::get(K key) {
-    ssize_t index = mCache.indexOfKey(key);
+    ssize_t index = mCache->indexOfKey(key);
     if (index >= 0) {
-        sp<Entry<K, V> > entry = mCache.valueAt(index);
+        sp<Entry<K, V> > entry = mCache->valueAt(index);
         if (entry.get()) {
             detachFromCache(entry);
             attachToCache(entry);
@@ -127,13 +227,13 @@
 
 template<typename K, typename V>
 void GenerationCache<K, V>::put(K key, V value) {
-    if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) {
+    if (mMaxCapacity != kUnlimitedCapacity && mCache->size() >= mMaxCapacity) {
         removeOldest();
     }
 
-    ssize_t index = mCache.indexOfKey(key);
+    ssize_t index = mCache->indexOfKey(key);
     if (index >= 0) {
-        sp<Entry<K, V> > entry = mCache.valueAt(index);
+        sp<Entry<K, V> > entry = mCache->valueAt(index);
         detachFromCache(entry);
         addToCache(entry, key, value);
     } else {
@@ -146,31 +246,36 @@
 void GenerationCache<K, V>::addToCache(sp<Entry<K, V> > entry, K key, V value) {
     entry->key = key;
     entry->value = value;
-    mCache.add(key, entry);
+    entry->index = mCache->add(key, entry);
     attachToCache(entry);
 }
 
 template<typename K, typename V>
 V GenerationCache<K, V>::remove(K key) {
-    ssize_t index = mCache.indexOfKey(key);
+    ssize_t index = mCache->indexOfKey(key);
     if (index >= 0) {
-        sp<Entry<K, V> > entry = mCache.valueAt(index);
-        if (mListener) {
-            (*mListener)(entry->key, entry->value);
-        }
-        mCache.removeItemsAt(index, 1);
-        detachFromCache(entry);
-
-        return entry->value;
+        return removeAt(index);
     }
 
     return NULL;
 }
 
 template<typename K, typename V>
+V GenerationCache<K, V>::removeAt(ssize_t index) {
+    sp<Entry<K, V> > entry = mCache->valueAt(index);
+    if (mListener) {
+        (*mListener)(entry->key, entry->value);
+    }
+    mCache->removeItemsAt(index, 1);
+    detachFromCache(entry);
+
+    return entry->value;
+}
+
+template<typename K, typename V>
 V GenerationCache<K, V>::removeOldest() {
     if (mOldest.get()) {
-        return remove(mOldest->key);
+        return removeAt(mOldest->index);
     }
 
     return NULL;
@@ -178,12 +283,12 @@
 
 template<typename K, typename V>
 void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) {
-    if (!mYougest.get()) {
-        mYougest = mOldest = entry;
+    if (!mYoungest.get()) {
+        mYoungest = mOldest = entry;
     } else {
-        entry->parent = mYougest;
-        mYougest->child = entry;
-        mYougest = entry;
+        entry->parent = mYoungest;
+        mYoungest->child = entry;
+        mYoungest = entry;
     }
 }
 
@@ -201,8 +306,8 @@
         mOldest = entry->child;
     }
 
-    if (mYougest == entry) {
-        mYougest = entry->parent;
+    if (mYoungest == entry) {
+        mYoungest = entry->parent;
     }
 
     entry->parent.clear();