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/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 @@
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 @@
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 @@
}; // 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