summaryrefslogtreecommitdiffstats
path: root/libs/hwui
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2013-06-26 15:45:41 -0700
committerRomain Guy <romainguy@google.com>2013-06-26 17:15:08 -0700
commite3b0a0117a2ab4118f868a731b238fe8f2430276 (patch)
treea4a6ac3783ace541cd35a0f9d3868af6d2bf97b7 /libs/hwui
parent89dc02a9bed818cc6f5296c97eb504ccb010db42 (diff)
downloadframeworks_base-e3b0a0117a2ab4118f868a731b238fe8f2430276.zip
frameworks_base-e3b0a0117a2ab4118f868a731b238fe8f2430276.tar.gz
frameworks_base-e3b0a0117a2ab4118f868a731b238fe8f2430276.tar.bz2
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
Diffstat (limited to 'libs/hwui')
-rw-r--r--libs/hwui/Caches.cpp1
-rw-r--r--libs/hwui/DisplayList.cpp12
-rw-r--r--libs/hwui/DisplayList.h4
-rw-r--r--libs/hwui/DisplayListRenderer.cpp6
-rw-r--r--libs/hwui/DisplayListRenderer.h11
-rw-r--r--libs/hwui/PatchCache.cpp152
-rw-r--r--libs/hwui/PatchCache.h55
-rw-r--r--libs/hwui/PathCache.cpp25
-rw-r--r--libs/hwui/PathCache.h2
-rw-r--r--libs/hwui/ResourceCache.cpp52
-rw-r--r--libs/hwui/ResourceCache.h11
11 files changed, 299 insertions, 32 deletions
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 1089b7c..6de8c8c 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -286,6 +286,7 @@ void Caches::dumpMemoryUsage(String8 &log) {
void Caches::clearGarbage() {
textureCache.clearGarbage();
pathCache.clearGarbage();
+ patchCache.clearGarbage();
Vector<DisplayList*> displayLists;
Vector<Layer*> layers;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 0d4dd1a..cebfd26 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -100,6 +100,10 @@ void DisplayList::clearResources() {
caches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
}
+ for (size_t i = 0; i < mPatchResources.size(); i++) {
+ caches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
+ }
+
for (size_t i = 0; i < mShaders.size(); i++) {
caches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
caches.resourceCache.destructorLocked(mShaders.itemAt(i));
@@ -134,6 +138,7 @@ void DisplayList::clearResources() {
mBitmapResources.clear();
mOwnedBitmapResources.clear();
mFilterResources.clear();
+ mPatchResources.clear();
mShaders.clear();
mSourcePaths.clear();
mPaints.clear();
@@ -201,6 +206,13 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
caches.resourceCache.incrementRefcountLocked(resource);
}
+ const Vector<Res_png_9patch*>& patchResources = recorder.getPatchResources();
+ for (size_t i = 0; i < patchResources.size(); i++) {
+ Res_png_9patch* resource = patchResources.itemAt(i);
+ mPatchResources.add(resource);
+ caches.resourceCache.incrementRefcountLocked(resource);
+ }
+
const Vector<SkiaShader*>& shaders = recorder.getShaders();
for (size_t i = 0; i < shaders.size(); i++) {
SkiaShader* resource = shaders.itemAt(i);
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 1417df7..194be9e 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -30,8 +30,11 @@
#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <utils/Vector.h>
+
#include <cutils/compiler.h>
+#include <androidfw/ResourceTypes.h>
+
#include "utils/LinearAllocator.h"
#include "Debug.h"
@@ -484,6 +487,7 @@ private:
Vector<SkBitmap*> mBitmapResources;
Vector<SkBitmap*> mOwnedBitmapResources;
Vector<SkiaColorFilter*> mFilterResources;
+ Vector<Res_png_9patch*> mPatchResources;
Vector<SkPaint*> mPaints;
Vector<SkPath*> mPaths;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 5d23e1d..9113092 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -57,6 +57,10 @@ void DisplayListRenderer::reset() {
mCaches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
}
+ for (size_t i = 0; i < mPatchResources.size(); i++) {
+ mCaches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
+ }
+
for (size_t i = 0; i < mShaders.size(); i++) {
mCaches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
}
@@ -74,6 +78,7 @@ void DisplayListRenderer::reset() {
mBitmapResources.clear();
mOwnedBitmapResources.clear();
mFilterResources.clear();
+ mPatchResources.clear();
mSourcePaths.clear();
mShaders.clear();
@@ -318,6 +323,7 @@ status_t DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, in
status_t DisplayListRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
float left, float top, float right, float bottom, SkPaint* paint) {
bitmap = refBitmap(bitmap);
+ patch = refPatch(patch);
paint = refPaint(paint);
addDrawOp(new (alloc()) DrawPatchOp(bitmap, patch, left, top, right, bottom, paint));
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 85d6107..03f50c8 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -156,6 +156,10 @@ public:
return mFilterResources;
}
+ const Vector<Res_png_9patch*>& getPatchResources() const {
+ return mPatchResources;
+ }
+
const Vector<SkiaShader*>& getShaders() const {
return mShaders;
}
@@ -315,9 +319,16 @@ private:
return colorFilter;
}
+ inline Res_png_9patch* refPatch(Res_png_9patch* patch) {
+ mPatchResources.add(patch);
+ mCaches.resourceCache.incrementRefcount(patch);
+ return patch;
+ }
+
Vector<SkBitmap*> mBitmapResources;
Vector<SkBitmap*> mOwnedBitmapResources;
Vector<SkiaColorFilter*> mFilterResources;
+ Vector<Res_png_9patch*> mPatchResources;
Vector<SkPaint*> mPaints;
DefaultKeyedVector<SkPaint*, SkPaint*> mPaintMap;
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index dc69d7f..dc0d98c 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -32,7 +32,7 @@ namespace uirenderer {
PatchCache::PatchCache():
mSize(0), mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity),
- mMeshBuffer(0), mGenerationId(0) {
+ mMeshBuffer(0), mFreeBlocks(NULL), mGenerationId(0) {
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, NULL) > 0) {
INIT_LOGD(" Setting patch cache size to %skB", property);
@@ -97,14 +97,130 @@ void PatchCache::clearCache() {
delete i.value();
}
mCache.clear();
+
+ BufferBlock* block = mFreeBlocks;
+ while (block) {
+ BufferBlock* next = block->next;
+ delete block;
+ block = next;
+ }
+ mFreeBlocks = NULL;
+}
+
+void PatchCache::remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* patch) {
+ LruCache<PatchDescription, Patch*>::Iterator i(mCache);
+ while (i.next()) {
+ const PatchDescription& key = i.key();
+ if (key.getPatch() == patch) {
+ patchesToRemove.push(patch_pair_t(&key, i.value()));
+ }
+ }
+}
+
+void PatchCache::removeDeferred(Res_png_9patch* patch) {
+ Mutex::Autolock _l(mLock);
+ mGarbage.push(patch);
+}
+
+void PatchCache::clearGarbage() {
+ Vector<patch_pair_t> patchesToRemove;
+
+ { // scope for the mutex
+ Mutex::Autolock _l(mLock);
+ size_t count = mGarbage.size();
+ for (size_t i = 0; i < count; i++) {
+ remove(patchesToRemove, mGarbage[i]);
+ }
+ mGarbage.clear();
+ }
+
+ // TODO: We could sort patchesToRemove by offset to merge
+ // adjacent free blocks
+ for (size_t i = 0; i < patchesToRemove.size(); i++) {
+ const patch_pair_t& pair = patchesToRemove[i];
+
+ // Add a new free block to the list
+ const Patch* patch = pair.getSecond();
+ BufferBlock* block = new BufferBlock(patch->offset, patch->getSize());
+ block->next = mFreeBlocks;
+ mFreeBlocks = block;
+
+ mSize -= patch->getSize();
+
+ mCache.remove(*pair.getFirst());
+ }
+
+#if DEBUG_PATCHES
+ if (patchesToRemove.size() > 0) {
+ dumpFreeBlocks("Removed garbage");
+ }
+#endif
}
void PatchCache::createVertexBuffer() {
glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW);
mSize = 0;
+ mFreeBlocks = new BufferBlock(0, mMaxSize);
mGenerationId++;
}
+/**
+ * Sets the mesh's offsets and copies its associated vertices into
+ * the mesh buffer (VBO).
+ */
+void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) {
+ // This call ensures the VBO exists and that it is bound
+ init(Caches::getInstance());
+
+ // If we're running out of space, let's clear the entire cache
+ uint32_t size = newMesh->getSize();
+ if (mSize + size > mMaxSize) {
+ clearCache();
+ createVertexBuffer();
+ }
+
+ // Find a block where we can fit the mesh
+ BufferBlock* previous = NULL;
+ BufferBlock* block = mFreeBlocks;
+ while (block) {
+ // The mesh fits
+ if (block->size >= size) {
+ break;
+ }
+ previous = block;
+ block = block->next;
+ }
+
+ // We have enough space left in the buffer, but it's
+ // too fragmented, let's clear the cache
+ if (!block) {
+ clearCache();
+ createVertexBuffer();
+ previous = NULL;
+ block = mFreeBlocks;
+ }
+
+ // Copy the 9patch mesh in the VBO
+ newMesh->offset = (GLintptr) (block->offset);
+ newMesh->textureOffset = newMesh->offset + gMeshTextureOffset;
+ glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices);
+
+ // Remove the block since we've used it entirely
+ if (block->size == size) {
+ if (previous) {
+ previous->next = block->next;
+ } else {
+ mFreeBlocks = block->next;
+ }
+ } else {
+ // Resize the block now that it's occupied
+ block->offset += size;
+ block->size -= size;
+ }
+
+ mSize += size;
+}
+
const Patch* PatchCache::get(const AssetAtlas::Entry* entry,
const uint32_t bitmapWidth, const uint32_t bitmapHeight,
const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
@@ -117,6 +233,7 @@ const Patch* PatchCache::get(const AssetAtlas::Entry* entry,
TextureVertex* vertices;
if (entry) {
+ // An atlas entry has a UV mapper
vertices = newMesh->createMesh(bitmapWidth, bitmapHeight,
pixelWidth, pixelHeight, entry->uvMapper, patch);
} else {
@@ -125,24 +242,13 @@ const Patch* PatchCache::get(const AssetAtlas::Entry* entry,
}
if (vertices) {
- // This call ensures the VBO exists and that it is bound
- init(Caches::getInstance());
-
- // TODO: Simply remove the oldest items until we have enough room
- // This will require to keep a list of free blocks in the VBO
- uint32_t size = newMesh->getSize();
- if (mSize + size > mMaxSize) {
- clearCache();
- createVertexBuffer();
- }
-
- newMesh->offset = (GLintptr) mSize;
- newMesh->textureOffset = newMesh->offset + gMeshTextureOffset;
- mSize += size;
-
- glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices);
+ setupMesh(newMesh, vertices);
}
+#if DEBUG_PATCHES
+ dumpFreeBlocks("Adding patch");
+#endif
+
mCache.put(description, newMesh);
return newMesh;
}
@@ -150,5 +256,17 @@ const Patch* PatchCache::get(const AssetAtlas::Entry* entry,
return mesh;
}
+#if DEBUG_PATCHES
+void PatchCache::dumpFreeBlocks(const char* prefix) {
+ String8 dump;
+ BufferBlock* block = mFreeBlocks;
+ while (block) {
+ dump.appendFormat("->(%d, %d)", block->offset, block->size);
+ block = block->next;
+ }
+ ALOGD("%s: Free blocks%s", prefix, dump.string());
+}
+#endif
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 1829b89..9f2c9a5 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -26,6 +26,7 @@
#include "AssetAtlas.h"
#include "Debug.h"
#include "Patch.h"
+#include "utils/Pair.h"
namespace android {
namespace uirenderer {
@@ -74,10 +75,20 @@ public:
return mGenerationId;
}
-private:
- void clearCache();
- void createVertexBuffer();
+ /**
+ * Removes the entries associated with the specified 9-patch. This is meant
+ * to be called from threads that are not the EGL context thread (GC thread
+ * on the VM side for instance.)
+ */
+ void removeDeferred(Res_png_9patch* patch);
+ /**
+ * Process deferred removals.
+ */
+ void clearGarbage();
+
+
+private:
struct PatchDescription {
PatchDescription(): mPatch(NULL), mBitmapWidth(0), mBitmapHeight(0),
mPixelWidth(0), mPixelHeight(0) {
@@ -91,6 +102,8 @@ private:
hash_t hash() const;
+ const Res_png_9patch* getPatch() const { return mPatch; }
+
static int compare(const PatchDescription& lhs, const PatchDescription& rhs);
bool operator==(const PatchDescription& other) const {
@@ -124,14 +137,50 @@ private:
}; // struct PatchDescription
+ /**
+ * A buffer block represents an empty range in the mesh buffer
+ * that can be used to store vertices.
+ *
+ * The patch cache maintains a linked-list of buffer blocks
+ * to track available regions of memory in the VBO.
+ */
+ struct BufferBlock {
+ BufferBlock(uint32_t offset, uint32_t size): offset(offset), size(size), next(NULL) {
+ }
+
+ uint32_t offset;
+ uint32_t size;
+
+ BufferBlock* next;
+ }; // struct BufferBlock
+
+ typedef Pair<const PatchDescription*, Patch*> patch_pair_t;
+
+ void clearCache();
+ void createVertexBuffer();
+
+ void setupMesh(Patch* newMesh, TextureVertex* vertices);
+
+ void remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* patch);
+
+#if DEBUG_PATCHES
+ void dumpFreeBlocks(const char* prefix);
+#endif
+
uint32_t mMaxSize;
uint32_t mSize;
LruCache<PatchDescription, Patch*> mCache;
GLuint mMeshBuffer;
+ // First available free block inside the mesh buffer
+ BufferBlock* mFreeBlocks;
uint32_t mGenerationId;
+
+ // Garbage tracking, required to handle GC events on the VM side
+ Vector<Res_png_9patch*> mGarbage;
+ mutable Mutex mLock;
}; // class PatchCache
}; // namespace uirenderer
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 3ab40da..70ab6e7 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -350,8 +350,7 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
// Paths
///////////////////////////////////////////////////////////////////////////////
-void PathCache::remove(const path_pair_t& pair) {
- Vector<PathDescription> pathsToRemove;
+void PathCache::remove(Vector<PathDescription>& pathsToRemove, const path_pair_t& pair) {
LruCache<PathDescription, PathTexture*>::Iterator i(mCache);
while (i.next()) {
@@ -362,10 +361,6 @@ void PathCache::remove(const path_pair_t& pair) {
pathsToRemove.push(key);
}
}
-
- for (size_t i = 0; i < pathsToRemove.size(); i++) {
- mCache.remove(pathsToRemove.itemAt(i));
- }
}
void PathCache::removeDeferred(SkPath* path) {
@@ -374,12 +369,20 @@ void PathCache::removeDeferred(SkPath* path) {
}
void PathCache::clearGarbage() {
- Mutex::Autolock l(mLock);
- size_t count = mGarbage.size();
- for (size_t i = 0; i < count; i++) {
- remove(mGarbage.itemAt(i));
+ Vector<PathDescription> pathsToRemove;
+
+ { // scope for the mutex
+ Mutex::Autolock l(mLock);
+ size_t count = mGarbage.size();
+ for (size_t i = 0; i < count; i++) {
+ remove(pathsToRemove, mGarbage.itemAt(i));
+ }
+ mGarbage.clear();
+ }
+
+ for (size_t i = 0; i < pathsToRemove.size(); i++) {
+ mCache.remove(pathsToRemove.itemAt(i));
}
- mGarbage.clear();
}
/**
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index a191f0e..16d20a8 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -269,7 +269,7 @@ private:
* Removes an entry.
* The pair must define first=path, second=sourcePath
*/
- void remove(const path_pair_t& pair);
+ void remove(Vector<PathDescription>& pathsToRemove, const path_pair_t& pair);
/**
* Ensures there is enough space in the cache for a texture of the specified
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 @@ void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) {
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 @@ void ResourceCache::incrementRefcountLocked(SkiaColorFilter* filterResource) {
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 @@ void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) {
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 @@ void ResourceCache::decrementRefcountLocked(SkiaColorFilter* filterResource) {
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::destructorLocked(SkiaColorFilter* resource) {
}
}
+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 @@ void ResourceCache::deleteResourceReferenceLocked(void* resource, ResourceRefere
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);
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index ab493e5..ea0c1b5 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -22,7 +22,11 @@
#include <SkBitmap.h>
#include <SkiaColorFilter.h>
#include <SkiaShader.h>
+
#include <utils/KeyedVector.h>
+
+#include <androidfw/ResourceTypes.h>
+
#include "Layer.h"
namespace android {
@@ -35,6 +39,7 @@ enum ResourceType {
kBitmap,
kShader,
kColorFilter,
+ kNinePatch,
kPath,
kLayer
};
@@ -69,35 +74,41 @@ public:
void incrementRefcount(SkBitmap* resource);
void incrementRefcount(SkiaShader* resource);
void incrementRefcount(SkiaColorFilter* resource);
+ void incrementRefcount(Res_png_9patch* resource);
void incrementRefcount(Layer* resource);
void incrementRefcountLocked(SkPath* resource);
void incrementRefcountLocked(SkBitmap* resource);
void incrementRefcountLocked(SkiaShader* resource);
void incrementRefcountLocked(SkiaColorFilter* resource);
+ void incrementRefcountLocked(Res_png_9patch* resource);
void incrementRefcountLocked(Layer* resource);
void decrementRefcount(SkBitmap* resource);
void decrementRefcount(SkPath* resource);
void decrementRefcount(SkiaShader* resource);
void decrementRefcount(SkiaColorFilter* resource);
+ void decrementRefcount(Res_png_9patch* resource);
void decrementRefcount(Layer* resource);
void decrementRefcountLocked(SkBitmap* resource);
void decrementRefcountLocked(SkPath* resource);
void decrementRefcountLocked(SkiaShader* resource);
void decrementRefcountLocked(SkiaColorFilter* resource);
+ void decrementRefcountLocked(Res_png_9patch* resource);
void decrementRefcountLocked(Layer* resource);
void destructor(SkPath* resource);
void destructor(SkBitmap* resource);
void destructor(SkiaShader* resource);
void destructor(SkiaColorFilter* resource);
+ void destructor(Res_png_9patch* resource);
void destructorLocked(SkPath* resource);
void destructorLocked(SkBitmap* resource);
void destructorLocked(SkiaShader* resource);
void destructorLocked(SkiaColorFilter* resource);
+ void destructorLocked(Res_png_9patch* resource);
bool recycle(SkBitmap* resource);
bool recycleLocked(SkBitmap* resource);