Update HWUI to store its own SkBitmap objects

This enables us to...

1) simplify the lifecycle/ownership between Java and HWUI
2) remove DisplayListRenderer::drawBitmapData and associated logic
3) track pixel lifecycle using standard SkPixelRef refcounting
4) Remove uncessary calls to ref/unref the bitmap's pixels and colorTable

Change-Id: I3c95078da20995444f6388a029414280fd654318
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 45c27c2..2d1adc5 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -16,7 +16,6 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include <SkPixelRef.h>
 #include "ResourceCache.h"
 #include "Caches.h"
 
@@ -37,8 +36,8 @@
         ResourceReference* ref = mCache->valueAt(i);
         ALOGD("  ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p",
                 i, mCache->keyAt(i), mCache->valueAt(i));
-        ALOGD("  ResourceCache: mCache(%zu): refCount, recycled, destroyed, type = %d, %d, %d, %d",
-                i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType);
+        ALOGD("  ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d",
+                i, ref->refCount, ref->destroyed, ref->resourceType);
     }
 }
 
@@ -60,15 +59,26 @@
     mLock.unlock();
 }
 
+const SkBitmap* ResourceCache::insert(const SkBitmap* bitmapResource) {
+    Mutex::Autolock _l(mLock);
+
+    BitmapKey bitmapKey(bitmapResource);
+    ssize_t index = mBitmapCache.indexOfKey(bitmapKey);
+    if (index == NAME_NOT_FOUND) {
+        SkBitmap* cachedBitmap = new SkBitmap(*bitmapResource);
+        index = mBitmapCache.add(bitmapKey, cachedBitmap);
+        return cachedBitmap;
+    }
+
+    mBitmapCache.keyAt(index).mRefCount++;
+    return mBitmapCache.valueAt(index);
+}
+
 void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
     Mutex::Autolock _l(mLock);
     incrementRefcountLocked(resource, resourceType);
 }
 
-void ResourceCache::incrementRefcount(const SkBitmap* bitmapResource) {
-    incrementRefcount((void*) bitmapResource, kBitmap);
-}
-
 void ResourceCache::incrementRefcount(const SkPath* pathResource) {
     incrementRefcount((void*) pathResource, kPath);
 }
@@ -87,25 +97,14 @@
     ref->refCount++;
 }
 
-void ResourceCache::incrementRefcountLocked(const SkBitmap* bitmapResource) {
-    incrementRefcountLocked((void*) bitmapResource, kBitmap);
-}
-
-void ResourceCache::incrementRefcountLocked(const SkPath* pathResource) {
-    incrementRefcountLocked((void*) pathResource, kPath);
-}
-
-void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) {
-    incrementRefcountLocked((void*) patchResource, kNinePatch);
-}
-
 void ResourceCache::decrementRefcount(void* resource) {
     Mutex::Autolock _l(mLock);
     decrementRefcountLocked(resource);
 }
 
 void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) {
-    decrementRefcount((void*) bitmapResource);
+    Mutex::Autolock _l(mLock);
+    decrementRefcountLocked(bitmapResource);
 }
 
 void ResourceCache::decrementRefcount(const SkPath* pathResource) {
@@ -130,7 +129,20 @@
 }
 
 void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) {
-    decrementRefcountLocked((void*) bitmapResource);
+    BitmapKey bitmapKey(bitmapResource);
+    ssize_t index = mBitmapCache.indexOfKey(bitmapKey);
+
+    LOG_ALWAYS_FATAL_IF(index == NAME_NOT_FOUND,
+                    "Decrementing the reference of an untracked Bitmap");
+
+    const BitmapKey& cacheEntry = mBitmapCache.keyAt(index);
+    if (cacheEntry.mRefCount == 1) {
+        // delete the bitmap and remove it from the cache
+        delete mBitmapCache.valueAt(index);
+        mBitmapCache.removeItemsAt(index);
+    } else {
+        cacheEntry.mRefCount--;
+    }
 }
 
 void ResourceCache::decrementRefcountLocked(const SkPath* pathResource) {
@@ -164,28 +176,6 @@
     }
 }
 
-void ResourceCache::destructor(const SkBitmap* resource) {
-    Mutex::Autolock _l(mLock);
-    destructorLocked(resource);
-}
-
-void ResourceCache::destructorLocked(const SkBitmap* resource) {
-    ssize_t index = mCache->indexOfKey(resource);
-    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
-    if (ref == nullptr) {
-        // If we're not tracking this resource, just delete it
-        if (Caches::hasInstance()) {
-            Caches::getInstance().textureCache.releaseTexture(resource);
-        }
-        delete resource;
-        return;
-    }
-    ref->destroyed = true;
-    if (ref->refCount == 0) {
-        deleteResourceReferenceLocked(resource, ref);
-    }
-}
-
 void ResourceCache::destructor(Res_png_9patch* resource) {
     Mutex::Autolock _l(mLock);
     destructorLocked(resource);
@@ -212,64 +202,12 @@
 }
 
 /**
- * Return value indicates whether resource was actually recycled, which happens when RefCnt
- * reaches 0.
- */
-bool ResourceCache::recycle(SkBitmap* resource) {
-    Mutex::Autolock _l(mLock);
-    return recycleLocked(resource);
-}
-
-/**
- * Return value indicates whether resource was actually recycled, which happens when RefCnt
- * reaches 0.
- */
-bool ResourceCache::recycleLocked(SkBitmap* resource) {
-    ssize_t index = mCache->indexOfKey(resource);
-    if (index < 0) {
-        if (Caches::hasInstance()) {
-            Caches::getInstance().textureCache.releaseTexture(resource);
-        }
-        // not tracking this resource; just recycle the pixel data
-        resource->setPixels(nullptr, nullptr);
-        return true;
-    }
-    ResourceReference* ref = mCache->valueAt(index);
-    if (ref == nullptr) {
-        // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
-        return true;
-    }
-    ref->recycled = true;
-    if (ref->refCount == 0) {
-        deleteResourceReferenceLocked(resource, ref);
-        return true;
-    }
-    // Still referring to resource, don't recycle yet
-    return false;
-}
-
-/**
  * This method should only be called while the mLock mutex is held (that mutex is grabbed
  * by the various destructor() and recycle() methods which call this method).
  */
 void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) {
-    if (ref->recycled && ref->resourceType == kBitmap) {
-        SkBitmap* bitmap = (SkBitmap*) resource;
-        if (Caches::hasInstance()) {
-            Caches::getInstance().textureCache.releaseTexture(bitmap);
-        }
-        bitmap->setPixels(nullptr, nullptr);
-    }
     if (ref->destroyed) {
         switch (ref->resourceType) {
-            case kBitmap: {
-                SkBitmap* bitmap = (SkBitmap*) resource;
-                if (Caches::hasInstance()) {
-                    Caches::getInstance().textureCache.releaseTexture(bitmap);
-                }
-                delete bitmap;
-            }
-            break;
             case kPath: {
                 SkPath* path = (SkPath*) resource;
                 if (Caches::hasInstance()) {
@@ -296,5 +234,38 @@
     delete ref;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// Bitmap Key
+///////////////////////////////////////////////////////////////////////////////
+
+void BitmapKey::operator=(const BitmapKey& other) {
+    this->mRefCount = other.mRefCount;
+    this->mBitmapDimensions = other.mBitmapDimensions;
+    this->mPixelRefOrigin = other.mPixelRefOrigin;
+    this->mPixelRefStableID = other.mPixelRefStableID;
+}
+
+bool BitmapKey::operator==(const BitmapKey& other) const {
+    return mPixelRefStableID == other.mPixelRefStableID &&
+           mPixelRefOrigin == other.mPixelRefOrigin &&
+           mBitmapDimensions == other.mBitmapDimensions;
+}
+
+bool BitmapKey::operator<(const BitmapKey& other) const {
+    if (mPixelRefStableID != other.mPixelRefStableID) {
+        return mPixelRefStableID < other.mPixelRefStableID;
+    }
+    if (mPixelRefOrigin.x() != other.mPixelRefOrigin.x()) {
+        return mPixelRefOrigin.x() < other.mPixelRefOrigin.x();
+    }
+    if (mPixelRefOrigin.y() != other.mPixelRefOrigin.y()) {
+        return mPixelRefOrigin.y() < other.mPixelRefOrigin.y();
+    }
+    if (mBitmapDimensions.width() != other.mBitmapDimensions.width()) {
+        return mBitmapDimensions.width() < other.mBitmapDimensions.width();
+    }
+    return mBitmapDimensions.height() < other.mBitmapDimensions.height();
+}
+
 }; // namespace uirenderer
 }; // namespace android