Better cache for layers, reduce memory usage and increase framerate.

Change-Id: I5ff864a361db4791bd5ff6be716f7ce692ef572d
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 2183718..31da924 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -30,9 +30,7 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-LayerCache::LayerCache():
-        mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity),
-        mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
+LayerCache::LayerCache(): mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
     char property[PROPERTY_VALUE_MAX];
     if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) {
         LOGD("  Setting layer cache size to %sMB", property);
@@ -42,11 +40,6 @@
     }
 }
 
-LayerCache::LayerCache(uint32_t maxByteSize):
-        mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity),
-        mSize(0), mMaxSize(maxByteSize) {
-}
-
 LayerCache::~LayerCache() {
     clear();
 }
@@ -64,19 +57,8 @@
 }
 
 void LayerCache::setMaxSize(uint32_t maxSize) {
+    clear();
     mMaxSize = maxSize;
-    while (mSize > mMaxSize) {
-        Layer* oldest = mCache.removeOldest();
-        deleteLayer(oldest);
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Callbacks
-///////////////////////////////////////////////////////////////////////////////
-
-void LayerCache::operator()(LayerSize& size, Layer*& layer) {
-    deleteLayer(layer);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -85,7 +67,7 @@
 
 void LayerCache::deleteLayer(Layer* layer) {
     if (layer) {
-        mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
+        mSize -= layer->width * layer->height * 4;
 
         glDeleteTextures(1, &layer->texture);
         delete layer;
@@ -93,21 +75,31 @@
 }
 
 void LayerCache::clear() {
-    mCache.setOnEntryRemovedListener(this);
+    size_t count = mCache.size();
+    for (size_t i = 0; i < count; i++) {
+        deleteLayer(mCache.itemAt(i).mLayer);
+    }
     mCache.clear();
-    mCache.setOnEntryRemovedListener(NULL);
 }
 
-Layer* LayerCache::get(LayerSize& size) {
-    Layer* layer = mCache.remove(size);
-    if (layer) {
-        LAYER_LOGD("Reusing layer");
+Layer* LayerCache::get(const uint32_t width, const uint32_t height) {
+    Layer* layer = NULL;
 
-        mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
+    LayerEntry entry(width, height);
+    ssize_t index = mCache.indexOf(entry);
+
+    if (index >= 0) {
+        entry = mCache.itemAt(index);
+        mCache.removeAt(index);
+
+        layer = entry.mLayer;
+        mSize -= layer->width * layer->height * 4;
+
+        LAYER_LOGD("Reusing layer %dx%d", layer->width, layer->height);
     } else {
-        LAYER_LOGD("Creating new layer");
+        LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
 
-        layer = new Layer;
+        layer = new Layer(entry.mWidth, entry.mHeight);
         layer->blend = true;
         layer->empty = true;
         layer->fbo = 0;
@@ -124,10 +116,10 @@
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
 #if DEBUG_LAYERS
-        uint32_t size = mCache.size();
-        for (uint32_t i = 0; i < size; i++) {
-            LayerSize ls = mCache.getKeyAt(i);
-            LAYER_LOGD("  Layer size %dx%d", ls.width, ls.height);
+        size_t size = mCache.size();
+        for (size_t i = 0; i < size; i++) {
+            const LayerEntry& entry = mCache.itemAt(i);
+            LAYER_LOGD("  Layer size %dx%d", entry.mWidth, entry.mHeight);
         }
 #endif
     }
@@ -135,18 +127,23 @@
     return layer;
 }
 
-bool LayerCache::put(LayerSize& layerSize, Layer* layer) {
-    const uint32_t size = layerSize.width * layerSize.height * 4;
+bool LayerCache::put(Layer* layer) {
+    const uint32_t size = layer->width * layer->height * 4;
     // Don't even try to cache a layer that's bigger than the cache
     if (size < mMaxSize) {
+        // TODO: Use an LRU
         while (mSize + size > mMaxSize) {
-            Layer* oldest = mCache.removeOldest();
-            deleteLayer(oldest);
-            LAYER_LOGD("  Deleting layer %.2fx%.2f", oldest->layer.getWidth(),
-                    oldest->layer.getHeight());
+            Layer* biggest = mCache.top().mLayer;
+            deleteLayer(biggest);
+            mCache.removeAt(mCache.size() - 1);
+
+            LAYER_LOGD("  Deleting layer %.2fx%.2f", biggest->layer.getWidth(),
+                    biggest->layer.getHeight());
         }
 
-        mCache.put(layerSize, layer);
+        LayerEntry entry(layer);
+
+        mCache.add(entry);
         mSize += size;
 
         return true;