Merge "Fix possible infinite loop when purging textures."
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index b062264..95bb24f 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -12,6 +12,8 @@
 

 #include <jni.h>

 

+#include <Caches.h>

+

 #if 0

     #define TRACE_BITMAP(code)  code

 #else

@@ -251,6 +253,9 @@
 }

 

 static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {

+#ifdef USE_OPENGL_RENDERER

+    android::uirenderer::Caches::getInstance().textureCache.remove(bitmap);

+#endif

     delete bitmap;

 }

 

diff --git a/libs/hwui/GenerationCache.h b/libs/hwui/GenerationCache.h
index c358c80..c42a5d8 100644
--- a/libs/hwui/GenerationCache.h
+++ b/libs/hwui/GenerationCache.h
@@ -143,11 +143,7 @@
     }
 
     ssize_t index = mCache.indexOfKey(key);
-    if (index >= 0) {
-        sp<Entry<K, V> > entry = mCache.valueAt(index);
-        detachFromCache(entry);
-        addToCache(entry, key, value);
-    } else {
+    if (index < 0) {
         sp<Entry<K, V> > entry = new Entry<K, V>;
         addToCache(entry, key, value);
     }
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index e874a16..6dad831 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_UI_PATCH_CACHE_H
 #define ANDROID_UI_PATCH_CACHE_H
 
+#include <utils/ResourceTypes.h>
+
 #include "Patch.h"
 #include "GenerationCache.h"
 
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 90f548b..817f143 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -28,6 +28,7 @@
 struct Texture {
     Texture() {
         cleanup = false;
+        bitmapSize = 0;
     }
 
     /**
@@ -54,6 +55,10 @@
      * Indicates whether this texture should be cleaned up after use.
      */
     bool cleanup;
+    /**
+     * Optional, size of the original bitmap.
+     */
+    uint32_t bitmapSize;
 }; // struct Texture
 
 class AutoTexture {
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 753c544..e558870 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -18,6 +18,8 @@
 
 #include <GLES2/gl2.h>
 
+#include <utils/threads.h>
+
 #include "TextureCache.h"
 #include "Properties.h"
 
@@ -49,6 +51,7 @@
 }
 
 TextureCache::~TextureCache() {
+    Mutex::Autolock _l(mLock);
     mCache.clear();
 }
 
@@ -64,14 +67,17 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 uint32_t TextureCache::getSize() {
+    Mutex::Autolock _l(mLock);
     return mSize;
 }
 
 uint32_t TextureCache::getMaxSize() {
+    Mutex::Autolock _l(mLock);
     return mMaxSize;
 }
 
 void TextureCache::setMaxSize(uint32_t maxSize) {
+    Mutex::Autolock _l(mLock);
     mMaxSize = maxSize;
     while (mSize > mMaxSize) {
         mCache.removeOldest();
@@ -83,12 +89,9 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void TextureCache::operator()(SkBitmap*& bitmap, Texture*& texture) {
-    if (bitmap) {
-        const uint32_t size = bitmap->rowBytes() * bitmap->height();
-        mSize -= size;
-    }
-
+    // This will be called already locked
     if (texture) {
+        mSize -= texture->bitmapSize;
         glDeleteTextures(1, &texture->id);
         delete texture;
     }
@@ -99,6 +102,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 Texture* TextureCache::get(SkBitmap* bitmap) {
+    Mutex::Autolock _l(mLock);
+
     Texture* texture = mCache.get(bitmap);
     if (!texture) {
         if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
@@ -115,6 +120,7 @@
         }
 
         texture = new Texture;
+        texture->bitmapSize = size;
         generateTexture(bitmap, texture, false);
 
         if (size < mMaxSize) {
@@ -131,15 +137,18 @@
 }
 
 void TextureCache::remove(SkBitmap* bitmap) {
+    Mutex::Autolock _l(mLock);
     mCache.remove(bitmap);
 }
 
 void TextureCache::clear() {
+    Mutex::Autolock _l(mLock);
     mCache.clear();
 }
 
 void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate) {
     SkAutoLockPixels alp(*bitmap);
+
     if (!bitmap->readyToDraw()) {
         LOGE("Cannot generate texture from bitmap");
         return;
@@ -159,6 +168,7 @@
     switch (bitmap->getConfig()) {
     case SkBitmap::kA8_Config:
         texture->blend = true;
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
         glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, bitmap->rowBytesAsPixels(), texture->height, 0,
                 GL_ALPHA, GL_UNSIGNED_BYTE, bitmap->getPixels());
         break;
@@ -175,6 +185,7 @@
         texture->blend = !bitmap->isOpaque();
         break;
     default:
+        LOGW("Unsupported bitmap config");
         break;
     }
 
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index b5e4c7c..847d69c 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -86,6 +86,8 @@
     uint32_t mSize;
     uint32_t mMaxSize;
     GLint mMaxTextureSize;
+
+    mutable Mutex mLock;
 }; // class TextureCache
 
 }; // namespace uirenderer