Refcount 9-patches and properly handle GC events
This change adds refcounting of Res_png_9patch instances, the native
data structure used to represent 9-patches. The Dalvik NinePatch class
now holds a native pointer instead of a Dalvik byte[]. This pointer
is used whenever we need to draw the 9-patch (software or hardware.)
Since we are now tracking garbage collection of NinePatch objects
libhwui's PatchCache must keep a list of free blocks in the VBO
used to store the meshes.
This change also removes unnecessary instances tracking from
GLES20DisplayList. Bitmaps and 9-patches are refcounted at the
native level and do not need to be tracked by the Dalvik layer.
Change-Id: Ib8682d573a538aaf1945f8ec5a9bd5da5d16f74b
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 347bd78..58fa21c 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "OpenGLRenderer"
+
#include <SkPixelRef.h>
#include "ResourceCache.h"
#include "Caches.h"
@@ -79,6 +81,10 @@
incrementRefcount((void*) filterResource, kColorFilter);
}
+void ResourceCache::incrementRefcount(Res_png_9patch* patchResource) {
+ incrementRefcount((void*) patchResource, kNinePatch);
+}
+
void ResourceCache::incrementRefcount(Layer* layerResource) {
incrementRefcount((void*) layerResource, kLayer);
}
@@ -113,6 +119,10 @@
incrementRefcountLocked((void*) filterResource, kColorFilter);
}
+void ResourceCache::incrementRefcountLocked(Res_png_9patch* patchResource) {
+ incrementRefcountLocked((void*) patchResource, kNinePatch);
+}
+
void ResourceCache::incrementRefcountLocked(Layer* layerResource) {
incrementRefcountLocked((void*) layerResource, kLayer);
}
@@ -142,6 +152,10 @@
decrementRefcount((void*) filterResource);
}
+void ResourceCache::decrementRefcount(Res_png_9patch* patchResource) {
+ decrementRefcount((void*) patchResource);
+}
+
void ResourceCache::decrementRefcount(Layer* layerResource) {
decrementRefcount((void*) layerResource);
}
@@ -179,6 +193,10 @@
decrementRefcountLocked((void*) filterResource);
}
+void ResourceCache::decrementRefcountLocked(Res_png_9patch* patchResource) {
+ decrementRefcountLocked((void*) patchResource);
+}
+
void ResourceCache::decrementRefcountLocked(Layer* layerResource) {
decrementRefcountLocked((void*) layerResource);
}
@@ -265,6 +283,30 @@
}
}
+void ResourceCache::destructor(Res_png_9patch* resource) {
+ Mutex::Autolock _l(mLock);
+ destructorLocked(resource);
+}
+
+void ResourceCache::destructorLocked(Res_png_9patch* resource) {
+ ssize_t index = mCache->indexOfKey(resource);
+ ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
+ if (ref == NULL) {
+ if (Caches::hasInstance()) {
+ Caches::getInstance().patchCache.removeDeferred(resource);
+ }
+ // If we're not tracking this resource, just delete it
+ // A Res_png_9patch is actually an array of byte that's larger
+ // than sizeof(Res_png_9patch). It must be freed as an array.
+ delete[] (int8_t*) resource;
+ return;
+ }
+ ref->destroyed = true;
+ if (ref->refCount == 0) {
+ deleteResourceReferenceLocked(resource, ref);
+ }
+}
+
/**
* Return value indicates whether resource was actually recycled, which happens when RefCnt
* reaches 0.
@@ -335,6 +377,16 @@
delete filter;
}
break;
+ case kNinePatch: {
+ if (Caches::hasInstance()) {
+ Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
+ }
+ // A Res_png_9patch is actually an array of byte that's larger
+ // than sizeof(Res_png_9patch). It must be freed as an array.
+ int8_t* patch = (int8_t*) resource;
+ delete[] patch;
+ }
+ break;
case kLayer: {
Layer* layer = (Layer*) resource;
Caches::getInstance().deleteLayerDeferred(layer);