From a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Wed, 8 Sep 2010 18:04:33 -0700 Subject: [PATCH] Purge Skia objects from GL caches as needed. Change-Id: I754c671cf790ad5ae8bf047ad328034217da4ecc --- core/jni/android/graphics/Bitmap.cpp | 4 +++- core/jni/android/graphics/Path.cpp | 7 +++++++ core/jni/android/graphics/Shader.cpp | 6 ++++++ include/utils/Singleton.h | 5 +++++ libs/hwui/Caches.h | 4 +++- libs/hwui/GenerationCache.h | 6 ++++++ libs/hwui/GradientCache.cpp | 14 ++++++++++++++ libs/hwui/GradientCache.h | 6 ++++++ libs/hwui/PathCache.cpp | 27 +++++++++++++++++++++++++++ libs/hwui/PathCache.h | 10 ++++++++++ libs/hwui/TextureCache.cpp | 9 +++++++-- libs/hwui/TextureCache.h | 4 ++++ 12 files changed, 98 insertions(+), 4 deletions(-) diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 95bb24fb11832..880fb6eb823e8 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -254,7 +254,9 @@ static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src, static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) { #ifdef USE_OPENGL_RENDERER - android::uirenderer::Caches::getInstance().textureCache.remove(bitmap); + if (android::uirenderer::Caches::hasInstance()) { + android::uirenderer::Caches::getInstance().textureCache.remove(bitmap); + } #endif delete bitmap; } diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp index b8b2a10068f90..abe33f42a8cd2 100644 --- a/core/jni/android/graphics/Path.cpp +++ b/core/jni/android/graphics/Path.cpp @@ -26,12 +26,19 @@ #include "SkPath.h" +#include + namespace android { class SkPathGlue { public: static void finalizer(JNIEnv* env, jobject clazz, SkPath* obj) { +#ifdef USE_OPENGL_RENDERER + if (android::uirenderer::Caches::hasInstance()) { + android::uirenderer::Caches::getInstance().pathCache.remove(obj); + } +#endif delete obj; } diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index cb1c333762d9e..92024296eb312 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -9,6 +9,7 @@ #include "SkXfermode.h" #include +#include using namespace android::uirenderer; @@ -52,6 +53,11 @@ static int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArra static void Shader_destructor(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader) { +#ifdef USE_OPENGL_RENDERER + if (android::uirenderer::Caches::hasInstance()) { + android::uirenderer::Caches::getInstance().gradientCache.remove(shader); + } +#endif delete skiaShader; shader->safeUnref(); } diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h index 3b975b4c44483..e1ee8eb068fbc 100644 --- a/include/utils/Singleton.h +++ b/include/utils/Singleton.h @@ -37,6 +37,11 @@ public: } return *instance; } + + static bool hasInstance() { + Mutex::Autolock _l(sLock); + return sInstance != 0; + } protected: ~Singleton() { }; diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index fda57b8c862cc..9c67885f96014 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -17,7 +17,9 @@ #ifndef ANDROID_UI_CACHES_H #define ANDROID_UI_CACHES_H -#define LOG_TAG "OpenGLRenderer" +#ifndef LOG_TAG + #define LOG_TAG "OpenGLRenderer" +#endif #include diff --git a/libs/hwui/GenerationCache.h b/libs/hwui/GenerationCache.h index c42a5d8852c43..070e33fb46214 100644 --- a/libs/hwui/GenerationCache.h +++ b/libs/hwui/GenerationCache.h @@ -61,6 +61,7 @@ public: bool contains(K key) const; V get(K key); + K getKeyAt(uint32_t index) const; void put(K key, V value); V remove(K key); V removeOldest(); @@ -121,6 +122,11 @@ bool GenerationCache::contains(K key) const { return mCache.indexOfKey(key) >= 0; } +template +K GenerationCache::getKeyAt(uint32_t index) const { + return mCache.keyAt(index); +} + template V GenerationCache::get(K key) { ssize_t index = mCache.indexOfKey(key); diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 58920bd6f96d4..9957370a5ae64 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -21,6 +21,8 @@ #include #include +#include + #include "GradientCache.h" #include "Properties.h" @@ -52,6 +54,7 @@ GradientCache::GradientCache(uint32_t maxByteSize): } GradientCache::~GradientCache() { + Mutex::Autolock _l(mLock); mCache.clear(); } @@ -60,14 +63,17 @@ GradientCache::~GradientCache() { /////////////////////////////////////////////////////////////////////////////// uint32_t GradientCache::getSize() { + Mutex::Autolock _l(mLock); return mSize; } uint32_t GradientCache::getMaxSize() { + Mutex::Autolock _l(mLock); return mMaxSize; } void GradientCache::setMaxSize(uint32_t maxSize) { + Mutex::Autolock _l(mLock); mMaxSize = maxSize; while (mSize > mMaxSize) { mCache.removeOldest(); @@ -79,6 +85,7 @@ void GradientCache::setMaxSize(uint32_t maxSize) { /////////////////////////////////////////////////////////////////////////////// void GradientCache::operator()(SkShader*& shader, Texture*& texture) { + // Already locked here if (shader) { const uint32_t size = texture->width * texture->height * 4; mSize -= size; @@ -95,14 +102,17 @@ void GradientCache::operator()(SkShader*& shader, Texture*& texture) { /////////////////////////////////////////////////////////////////////////////// Texture* GradientCache::get(SkShader* shader) { + Mutex::Autolock _l(mLock); return mCache.get(shader); } void GradientCache::remove(SkShader* shader) { + Mutex::Autolock _l(mLock); mCache.remove(shader); } void GradientCache::clear() { + Mutex::Autolock _l(mLock); mCache.clear(); } @@ -128,17 +138,21 @@ Texture* GradientCache::addLinearGradient(SkShader* shader, float* bounds, uint3 canvas.drawRectCoords(0.0f, 0.0f, bitmap.width(), 1.0f, p); + mLock.lock(); // Asume the cache is always big enough const uint32_t size = bitmap.rowBytes() * bitmap.height(); while (mSize + size > mMaxSize) { mCache.removeOldest(); } + mLock.unlock(); Texture* texture = new Texture; generateTexture(&bitmap, texture); + mLock.lock(); mSize += size; mCache.put(shader, texture); + mLock.unlock(); return texture; } diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index 8795920e69443..51a8c0185adb9 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -82,6 +82,12 @@ private: uint32_t mSize; uint32_t mMaxSize; + + /** + * Used to access mCache and mSize. All methods are accessed from a single + * thread except for remove(). + */ + mutable Mutex mLock; }; // class GradientCache }; // namespace uirenderer diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 158c0cc70ff07..e8afe37d98cf1 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -21,6 +21,8 @@ #include #include +#include + #include "PathCache.h" #include "Properties.h" @@ -51,6 +53,7 @@ PathCache::PathCache(uint32_t maxByteSize): } PathCache::~PathCache() { + Mutex::Autolock _l(mLock); mCache.clear(); } @@ -67,14 +70,17 @@ void PathCache::init() { /////////////////////////////////////////////////////////////////////////////// uint32_t PathCache::getSize() { + Mutex::Autolock _l(mLock); return mSize; } uint32_t PathCache::getMaxSize() { + Mutex::Autolock _l(mLock); return mMaxSize; } void PathCache::setMaxSize(uint32_t maxSize) { + Mutex::Autolock _l(mLock); mMaxSize = maxSize; while (mSize > mMaxSize) { mCache.removeOldest(); @@ -99,14 +105,30 @@ void PathCache::operator()(PathCacheEntry& path, PathTexture*& texture) { // Caching /////////////////////////////////////////////////////////////////////////////// +void PathCache::remove(SkPath* path) { + Mutex::Autolock _l(mLock); + // TODO: Linear search... + for (uint32_t i = 0; i < mCache.size(); i++) { + if (mCache.getKeyAt(i).path == path) { + mCache.removeAt(i); + return; + } + } +} + PathTexture* PathCache::get(SkPath* path, SkPaint* paint) { PathCacheEntry entry(path, paint); + + mLock.lock(); PathTexture* texture = mCache.get(entry); + mLock.unlock(); if (!texture) { texture = addTexture(entry, path, paint); } else if (path->getGenerationID() != texture->generation) { + mLock.lock(); mCache.remove(entry); + mLock.unlock(); texture = addTexture(entry, path, paint); } @@ -132,9 +154,11 @@ PathTexture* PathCache::addTexture(const PathCacheEntry& entry, const uint32_t size = width * height; // Don't even try to cache a bitmap that's bigger than the cache if (size < mMaxSize) { + mLock.lock(); while (mSize + size > mMaxSize) { mCache.removeOldest(); } + mLock.unlock(); } PathTexture* texture = new PathTexture; @@ -157,8 +181,10 @@ PathTexture* PathCache::addTexture(const PathCacheEntry& entry, generateTexture(bitmap, texture); if (size < mMaxSize) { + mLock.lock(); mSize += size; mCache.put(entry, texture); + mLock.unlock(); } else { texture->cleanup = true; } @@ -167,6 +193,7 @@ PathTexture* PathCache::addTexture(const PathCacheEntry& entry, } void PathCache::clear() { + Mutex::Autolock _l(mLock); mCache.clear(); } diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index 522e5e0f65ad6..bde0e7d845e96 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -114,6 +114,10 @@ public: * Clears the cache. This causes all textures to be deleted. */ void clear(); + /** + * Removes an entry. + */ + void remove(SkPath* path); /** * Sets the maximum size of the cache in bytes. @@ -143,6 +147,12 @@ private: uint32_t mSize; uint32_t mMaxSize; GLuint mMaxTextureSize; + + /** + * Used to access mCache and mSize. All methods are accessed from a single + * thread except for remove(). + */ + mutable Mutex mLock; }; // class PathCache }; // namespace uirenderer diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index e5588708127a8..927070a54ec5a 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -102,9 +102,10 @@ void TextureCache::operator()(SkBitmap*& bitmap, Texture*& texture) { /////////////////////////////////////////////////////////////////////////////// Texture* TextureCache::get(SkBitmap* bitmap) { - Mutex::Autolock _l(mLock); - + mLock.lock(); Texture* texture = mCache.get(bitmap); + mLock.unlock(); + if (!texture) { if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) { LOGW("Bitmap too large to be uploaded into a texture"); @@ -114,9 +115,11 @@ Texture* TextureCache::get(SkBitmap* bitmap) { const uint32_t size = bitmap->rowBytes() * bitmap->height(); // Don't even try to cache a bitmap that's bigger than the cache if (size < mMaxSize) { + mLock.lock(); while (mSize + size > mMaxSize) { mCache.removeOldest(); } + mLock.unlock(); } texture = new Texture; @@ -124,8 +127,10 @@ Texture* TextureCache::get(SkBitmap* bitmap) { generateTexture(bitmap, texture, false); if (size < mMaxSize) { + mLock.lock(); mSize += size; mCache.put(bitmap, texture); + mLock.unlock(); } else { texture->cleanup = true; } diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index 847d69c93d11e..a63789a14eb06 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -87,6 +87,10 @@ private: uint32_t mMaxSize; GLint mMaxTextureSize; + /** + * Used to access mCache and mSize. All methods are accessed from a single + * thread except for remove(). + */ mutable Mutex mLock; }; // class TextureCache